如需轉載請先聯(lián)系我
寫在前面:
全部程序代碼基于Matlab 2015b 不保證版本過低的Matlab能正常使用
如果matlab版本太低沒有內置以下函數(shù)請下載以下文件放到工作目錄
已知問題:
matlab 7.0以下的版本不支持“~”這個符號以用于代替無關參數(shù),所以在7.0版本以下的版本中無法實現(xiàn)本文用到的函數(shù)功能,請至少使用7.0以上的版本
"identifier" expected, "~" found. Error in
https://cn.mathworks.com/matlabcentral/newsreader/view_thread/324057
hough.m
https://drop.me/MYwpjo
houghpeaks.m
https://drop.me/BZwbWo
houghlines.m
https://drop.me/aGwy3a
題目預覽
如果已知函數(shù)表達式,就可以利用計算機輕易地畫出函數(shù)圖形。相反,如果給你一張圖片,里面有函數(shù)的圖形,能不能獲取其中的數(shù)據(jù),從而進一步構建出函數(shù)的表達式呢?請以附件中的圖片為例,解決以下幾個問題:
- 問題1:如何獲取圖片中曲線的坐標數(shù)據(jù)?請以01.jpg為例,運用你的方法獲取數(shù)據(jù),并重新繪制圖形。
- 問題2:如果圖片中包含有坐標系,如何去除?請針對02.jpg、03.jpg應用你的方法進行處理,并運用1)的方法獲取坐標數(shù)據(jù)。
- 問題3:當圖片中有多條曲線時,如何獲取每條曲線的坐標數(shù)據(jù)?請針對04.jpg、05.jpg應用你的方法,給出處理的結果。對05.jpg中獲得的數(shù)據(jù)進行重新標定,使得標定后的數(shù)據(jù)的大小與原圖中顯示的結果盡可能的相符。
- 問題4:如何利用獲得的坐標數(shù)據(jù),重建函數(shù)表達式?請給出06.jpg、07.jpg中各曲線的函數(shù)表達式。
(注:在應用您的方法之前,可以適當?shù)貙D片做預處理,包括手工的處理,但應該進行說明,并遵循盡量減少手工處理的原則)
圖片附件

01.jpg

02.jpg

03.jpg

04.jpg

05.jpg

06.jpg

07.jpg
解題思路
- 總體思想是去掉曲線以外的部分,對曲線重構,并進行坐標變換以盡可能接近原圖中的函數(shù)
- 就本題而言,曲線以外的部分包括字母、數(shù)字、箭頭,坐標軸(直線)
- 曲線重構通過二值化取點做
- 坐標變換通過屏幕坐標與笛卡爾坐標關系進行
- 獲取函數(shù)表達式通過多項式擬合進行,考慮到簡便性就不做冪函數(shù)、指數(shù)函數(shù)、對數(shù)函數(shù)的擬合,方法都是類似的
- 針對每幅圖都有單獨的m文件解題,但主要通過調用寫好的函數(shù)。
程序源代碼
模塊函數(shù)(供調用)
findandpoly.m
%--------------------------------------------------------
%本程序用于對二值化后(黑曲線白背景)的圖像進行曲線提取并擬合
%參數(shù)2個,BW(圖像二值化后的矩陣),輔助參數(shù)他,分3種選擇:0、普通、-1
%1是對曲線進行多項式擬合(3、5、7次)并和原提取到的曲線相對比(即畫在同一張圖里)
%2是進行指定n次多項式擬合,并與原曲線對比,同時在圖中標注擬合曲線的表達式
%3是只進行坐標變換
%其他:無論被處理圖像有沒有坐標軸,執(zhí)行此程序時都需要手動依次選擇兩個點,
%第一個是(0,0),第二個是(0,1),以用于重建坐標系并便于求曲線表達式
%如果需要其他特殊參數(shù),請自行更改相關部分
%--------------------------------------------------------
function [p1,x,y]=findandpoly(BW,pic,t)
p1=[];
a=imread(pic);
%xx=size(a,1);%x1為圖像橫向長度,實際上這里用不上
yy=size(a,2);%y1為縱向長度
imshow(a);
[x,y] = ginput(1);%選(0,0)
x1=x;y1=yy-y;
[x,y] = ginput(1);%選(0,1)(對06.jpg是(2*pi,0))
x2=x;y2=yy-y;
%現(xiàn)在(x1,y1),(x2,y2)即為提取的點的笛卡爾坐標系的坐標
k=(y2-y1);%k是屏幕坐標系與圖像坐標系的倍數(shù)
%k=(x2-x1)./(2.*pi);%針對06.jpg的處理改進
clear x;clear y;
[x,y]=find(BW==0);%找到黑色的點,并生成坐標(矩陣)
temp=x;%這里是進行圖像坐標與屏幕坐標之間的變換
x=y;x=(x-x1)./k;%切換到和圖片相符的坐標系,后續(xù)求出的擬合即是圖片中的表達式了
y=(yy-temp);y=(y-y1)./k;
if (t~=-1)
clear x1;clear x2;clear y1;clear y2;
% mu = [mean(x); std(x)];%手動實現(xiàn) centering and scaling:
%x1 = (x - mu(1))/mu(2);%即以橫坐標的均值為中心、以橫坐標的標準差來做歸一化因子,將數(shù)據(jù)變得相對集中。
if (t~=0)
p1 = polyfit(x,y,t);%其中, x, y為已知數(shù)據(jù)點向量, 分別表示橫,縱坐標, t為擬合多項式的次數(shù)
figure
plot(x,y,'k.',x,polyval(p1,x),'r')
legend('原始數(shù)據(jù)',[num2str(t) '次擬合數(shù)據(jù)'],2)%2表示圖例在右上角
ftext=num2str(p1(t+1));
for i=1:t
ftext=[ftext '+' '(' num2str(p1(t-i+1)) '*x.^' num2str(i) ')'];
end
%ftext(end)=[];
ftext=strcat('y=',ftext)
p1=ftext;
title(ftext);
else
p1 = polyfit(x,y,3);%其中, x, y為已知數(shù)據(jù)點向量, 分別表示橫,縱坐標, 3為擬合多項式的次數(shù)
p2 = polyfit(x,y,5);
p3 = polyfit(x,y,7);
figure
plot(x,y,'k.',x,polyval(p1,x),'r',x,polyval(p2,x),'g',x,polyval(p3,x),'b')
legend('原始數(shù)據(jù)','3次擬合數(shù)據(jù)','5次擬合數(shù)據(jù)','7次擬合數(shù)據(jù)',2)
end
axis equal%使坐標軸單位長度一直,否則圖像會看起來扭曲
end
ginputpro.m
function [ii]=ginputpro(I)
figure
imshow(I);
%end
p=size(I,3);
if p==3
r=I(:,:,1);
g=I(:,:,2);
b=I(:,:,3);
I1=rgb2gray(I);
else
I1=I;
end
hold on
[x,y,c]=ginput(1);
m(1)=x;
n(1)=y;
plot(x,y,'r');
k=2;
while(c==1)
[x1,y1,c1]=ginput(1);
if c1==1
m(k)=x1;
n(k)=y1;
plot(x,y,'r');
line([m(k-1) m(k)],[n(k-1) n(k)]);
k=k+1;
c=c1;
else
break
end
end
line([m(k-1) m(1)],[n(k-1) n(1)]);
BW = roipoly(I1,m,n);
if p==3
r1=double(r).*double(BW);
g1=double(g).*double(BW);
b1=double(b).*double(BW);
i1=cat(3,r1,g1,b1);
figure
imshow(mat2gray(i1));
ii=i1;
else
i2=double(I1).*double(BW);
figure
imshow(mat2gray(i2));ii=i2;
end
ii=im2uint8(mat2gray(ii));
houghdiy.m
%-------------------------------------------------------------
%通過霍夫變換尋找直線,并將直線部分去掉(即將像素點RGB值賦為255成為白色)
%本函數(shù)輸入?yún)?shù)兩個,一個BW(圖像二值化后的矩陣)、一個輔助參數(shù)t(用于確定是否對被檢查到的直線范圍進行擴大處理)
%-------------------------------------------------------------
function [BW]=houghdiy(BW,t)
I=~BW;
[H,theta,rho] = hough(BW);
P = houghpeaks(H,2,'threshold',ceil(0.5*max(H(:))));
lines = houghlines(BW,theta,rho,P,'FillGap',10,'MinLength',80);
for k = 1: length(lines)
xy = [lines(k).point1; lines(k).point2];
if xy(1,1)==xy(2,1)
I(xy(1,2):xy(2,2),(xy(1,1)-2):(xy(1,1)+2))=255;
else
syms kk bb x1 y1 x2 y2
[kk,bb]=solve('kk*x1+bb=y1','kk*x2+bb=y2','kk','bb');
kk=subs(kk,{x1,x2,y1,y2},{xy(1,1),xy(2,1),xy(1,2),xy(2,2)});
bb=subs(bb,{x1,x2,y1,y2},{xy(1,1),xy(2,1),xy(1,2),xy(2,2)});
kk=double(kk);
bb=double(bb);
if kk<=1 && kk>=-1
xx=linspace(xy(1,1),xy(2,1),abs(xy(1,1)-xy(2,1))+1);
yy=floor(kk*xx+bb);
else
yy=linspace(xy(1,2),xy(2,2),abs(xy(1,2)-xy(2,2))+1);
xx=floor((yy-bb)/kk);
end
for i=1:size(xx,2)
I((yy(i)-2):(yy(i)+2),xx(i))=255;
if (t==1)%有的時候檢測到的直線部分不均勻,需要擴大處理范圍
I((yy(i)-1):(yy(i)+2),xx(i))=255;
I((yy(i)-2):(yy(i)+3),xx(i))=255;
I((yy(i)-1):(yy(i)+3),xx(i))=255;
I((yy(i)-3):(yy(i)+2),xx(i))=255;
I((yy(i)-2):(yy(i)+1),xx(i))=255;
I((yy(i)-3):(yy(i)+1),xx(i))=255;
end
end
end
end
figure,imshow(I);%顯示函數(shù)圖像
BW=I;
quse.m
%-----------------------------------------------------
%im為輸入的圖像RGB數(shù)據(jù),后面的三個數(shù)為要去除的顏色的RGB值
%-----------------------------------------------------
function im=quse(im,a,b,c)
jd = [a b c]; % 藍色
njd = [1 1 1]*255; % 白色
tol = 1; % 閾值
for i = 1 : size(im, 1)
for j = 1 : size(im, 2);
temp = double(im(i, j, :)/255);
temp = temp(:).';
if norm(temp-jd) < tol
im(i, j, :) = njd;
im(i+1, j, :) = njd;
im(i, j+1, :) = njd;
im(i+1, j+1, :) = njd;
im(i-1, j, :) = njd;
im(i, j-1, :) = njd;
im(i-1, j-1, :) = njd;
end
end
end
imshow(im, []);
每幅圖的主函數(shù)
Q01.m
%-------------------------------------------
%對于01:二值化->平滑處理->重繪圖形->平滑處理結果與原圖對比
%-------------------------------------------
close all
clear
pic='01.jpg';
a=imread(pic);
BW=im2bw(a,0.4);%二值化
[nop,x,y]=findandpoly(BW,pic,-1);
figure;plot(x,y);%默認打開句柄1,畫出圖像
print(2,'-djpeg','01_01.jpg');
title('圖形重繪')
y(ceil(length(x)*rand(2,1))) = 3;%兩種平滑處理,并畫圖對比
yy1 = smooth(x,y,0.1,'loess');
%yy2 = smooth(x,y,0.1,'rloess');第二種這個效果不好,舍去
[xx,ind] = sort(x);
figure;plot(xx,yy1(ind),'r-')%只重繪圖形
title('圖形平滑處理')
print(3,'-djpeg','01_02.jpg');
figure;plot(xx,y(ind),'b.',xx,yy1(ind),'y-')%包括與原二值圖對比
title('圖形對比')
print(4,'-djpeg','01_03.jpg');
Q02.m
%--------------------------------
%對于02:二值化->擬合對比->選取最優(yōu)擬合并輸出表達式
%--------------------------------
close all
clear
pic='02.jpg';
p=imread(pic);%讀取圖像
%I=im2bw(p,0.8);%直接二值化
BW=~im2bw(p,0.8);%后續(xù)處理圖像(去掉直線)時是對I操作,即對原圖二值化的圖去直線
figure, imshow(BW);%顯示二值化處理結果
title('二值化');
print(1,'-djpeg','02_01.jpg');
BW=houghdiy(BW,0);%霍夫變換,去直線
title('去直線')
print(2,'-djpeg','02_02.jpg');
findandpoly(BW,pic,0);%擬合并對比
title('多項式擬合對比');
print(3,'-djpeg','02_03.jpg');
[p1,~,~]=findandpoly(BW,pic,5);%擬合
title({p1 '最優(yōu)擬合'});
print(4,'-djpeg','02_04.jpg');
%輸出最后最優(yōu)擬合系數(shù)p1
Q03.m
%-----------------------------------------
%對于03:預處理不需要的部分->去除指定顏色紅色->去直線->二值化->擬合對比
%-----------------------------------------
close all
clear
pic='03.jpg';
im=imread(pic);
figure,imshow(im);
for t=1:3%選三次,依次是Y和旁邊箭頭;原點0;X和旁邊箭頭;當然也可以增加次數(shù)手動去除A、B
[x,y] = ginput(2); %在圖像上手動選取兩個頂點,從左上往右下選,矩形
for i = y(1):y(2)
for j = x(1):x(2)
im(i,j,1)=255;
im(i,j,2)=255;
im(i,j,3)=255;
end
end
end
%---------------------------------
%以上為選區(qū)域,做成白色(等同于去掉顏色)
%----------------------------------------
%第一步將手動選擇區(qū)域處理為白色后,下面進行去除指定色彩(紅色)
im=quse(im,1,0,0); % 紅色
title('圖像預處理');
print('-djpeg','03_01.jpg');
I=im2bw(im,0.8);
BW=~im2bw(im,0.8);
figure, imshow(BW);
title('二值化');
print('-djpeg','03_02.jpg');
BW=houghdiy(BW,0);%霍夫變換,去直線
title('去直線')
print('-djpeg','03_03.jpg');
findandpoly(BW,pic,0);%再次選點(0,0)(0,1);擬合并對比
title('多項式擬合對比');
print('-djpeg','03_04.jpg');
Q04.m
%————————————————————————————————————————
%對于04:預處理不需要的部分->去除藍色->腐蝕圖像(盡量減少直線部分)
%->去直線->再去除少數(shù)殘留部分->擬合對比->選取最優(yōu)擬合并輸出表達式
%對于黑線步驟一致,只需改變需要去除的RGB值
%————————————————————————————————————————
close all
clear
pic='04.jpg';
im=imread(pic);
figure,imshow(im);
for t=1:4%選三次,依次是Y和旁邊箭頭;原點0;X和旁邊箭頭;當然也可以增加次數(shù)手動去除A、B
[x,y] = ginput(2); %在圖像上手動選取兩個頂點,從左上往右下選,矩形
for i = round(y(1)):round(y(2))
for j = round(x(1)):round(x(2))
im(i,j,1)=255;
im(i,j,2)=255;
im(i,j,3)=255;
end
end
end
im=quse(im,0,0,1);%去藍色
title('圖像預處理');
I=~im2bw(im,0.8);
se = strel('disk',1);%腐蝕圖像
I2 = imerode(I,se);
figure,imshow(I2)
title('二值化');
print('-djpeg','04_01.jpg');
BW=houghdiy(I2,0);%霍夫變換,去直線
title('去直線')
print('-djpeg','04_02.jpg');
figure,imshow(BW);%顯示處理后的圖像
[x,y] = ginput(2); %需要手動再去除一點東西
for i = round(y(1)):round(y(2))
for j = round(x(1)):round(x(2))
BW(i,j)=255;
end
end
figure,imshow(BW);
title('進一步去直線')
print('-djpeg','04_03.jpg');
findandpoly(BW,pic,0);%選點(0,0)(0,1);擬合并對比
title('多項式擬合對比');
print('-djpeg','04_04.jpg');
[p1,~,~]=findandpoly(BW,pic,5);%指定擬合
title({p1 '黑線最優(yōu)擬合'});
print('-djpeg','04_05.jpg');
%---------------以下為針對藍線處理-----------------
im=imread(pic);
im=quse(im,0,0,0);%去黑色
title('圖像預處理');
I=~im2bw(im,0.8);
se = strel('disk',1);%腐蝕圖像
I2 = imerode(I,se);
figure,imshow(I2)
title('二值化');
print('-djpeg','04_06.jpg');
findandpoly(~I2,pic,0);%選點(0,0)(0,1);擬合并對比
title('多項式擬合對比');
print('-djpeg','04_07.jpg');
[p1,~,~]=findandpoly(~I2,pic,5);%指定擬合
title({p1 '藍線最優(yōu)擬合'});
print('-djpeg','04_08.jpg');
Q05.m
%-------------------------------------------------
%對于05:提取指定顏色+坐標變換,然后擬合即可
%這里以紅線為例,提取紅線更改輸入的RGB值組合即可
%提取指定顏色->膨脹處理->二值化->擬合對比->選取最優(yōu)擬合并輸出表達式
%----------------------------------------------
close all
clear
pic='05.jpg';
a=imread(pic);
xx=size(a,1);%x1為圖像橫向長度
yy=size(a,2);%y1為縱向長度
imshow(a);
[x,y] = ginput(1);%選兩個點即可,用于坐標變換
x1=x;y1=yy-y;
[x,y] = ginput(1);
x2=x;y2=yy-y;
k=(y2-y1);
a=double(a);
modeblue=zeros(size(a(:,:,1)));
modeblue=(a(:,:,1)>125).*(a(:,:,2)<125).*(a(:,:,3)<125);%<<>藍色 ><<紅色 <><黃色
I=~modeblue;
figure,imshow(I)
title('紅線提取');
print('-djpeg','05_04.jpg');
se = strel('disk',1);%膨脹圖像
I2 = imdilate(~I,se);
figure,imshow(I2);
title('二值化');
print('-djpeg','05_05.jpg');
[p1,~,~]=findandpoly(~I2,pic,9);%指定擬合
title({p1 '紅線最優(yōu)擬合'});
print('-djpeg','05_06.jpg');
Q06.m
%--------------------------------------
%對于06:
%預處理不需要的部分->去直線->擬合對比->選取最優(yōu)擬合并輸出表達式
%--------------------------------------
close all
clear
pic='06.jpg';
im=imread(pic);
figure,imshow(im);
for t=1:4%選四次,依次是Y和箭頭;原點0;2pi;
[x,y] = ginput(2); %在圖像上手動選取兩個頂點,從左上往右下選,矩形
for i = round(y(1)):round(y(2))
for j = round(x(1)):round(x(2))
im(i,j,1)=255;
im(i,j,2)=255;
im(i,j,3)=255;
end
end
end
BW=~im2bw(im,0.8);
title('二值化');
print('-djpeg','06_01.jpg');
BW=houghdiy(BW,0);%霍夫變換,去直線
title('去直線')
print('-djpeg','06_02.jpg');
findandpoly(BW,pic,0);%選點(0,0)(2*pi,0);擬合并對比
title('多項式擬合對比');
print('-djpeg','06_03.jpg');
[p1,~,~]=findandpoly(BW,pic,9);%指定擬合
title({p1 '最優(yōu)擬合'});
print('-djpeg','06_04.jpg');
Q07.m
%--------------------------------
%對于07:提取目標曲線->二值化->指定次數(shù)擬合
%--------------------------------
close all
clear
pic='07.jpg';
for kkk=1:7
kk=num2str(kkk);
im=imread(pic);
im=ginputpro(im);%多邊形選取范圍,并返回被選取的圖像
title('選擇要提取的目標曲線區(qū)域');
print('-djpeg',['07_' kk '_01.jpg']);
for i = 1 : size(im, 1)%把黑色部分填白,便于后續(xù)二值化及擬合
for j = 1 : size(im, 2);
if(im(i, j)==0)
im(i, j, :) = im(i, j, :)+255;
end
end
end
figure;imshow(im);
title('提取的曲線');
print('-djpeg',['07_' kk '_02.jpg']);
im=im2bw(im,0.8);%二值化
figure;imshow(im);
title('二值化并準備擬合');
print('-djpeg',['07_' kk '_03.jpg']);
[p1,~,~]=findandpoly(im,pic,3);%每一次都要重新選點,并指定擬合
title({p1 '指定為3次擬合'});
print('-djpeg',['07_' kk '_04.jpg']);
end
處理得到的圖片
01

01_01.jpg

01_02.jpg

01_03.jpg
02

02_01.jpg

02_02.jpg

02_03.jpg

02_04.jpg
03

03_01.jpg

03_02.jpg

03_03.jpg

03_04.jpg

03_05.jpg
04

04_01.jpg

04_02.jpg

04_03.jpg

04_04.jpg

04_05.jpg

04_06.jpg

04_07.jpg

04_08.jpg
05

05_01.jpg

05_02.jpg

05_03.jpg

05_04.jpg

05_05.jpg

05_06.jpg
06

06_01.jpg

06_02.jpg

06_03.jpg

06_04.jpg
07

07_1_01.jpg

07_1_02.jpg

07_1_03.jpg

07_1_04.jpg

07_2_01.jpg

07_2_02.jpg

07_2_03.jpg

07_2_04.jpg

07_3_01.jpg

07_3_02.jpg

07_3_03.jpg

07_3_04.jpg

07_4_01.jpg

07_4_02.jpg

07_4_03.jpg

07_4_04.jpg

07_5_01.jpg

07_5_02.jpg

07_5_03.jpg

07_5_04.jpg

07_6_01.jpg

07_6_02.jpg

07_6_03.jpg

07_6_04.jpg

07_7_01.jpg

07_7_02.jpg

07_7_03.jpg

07_7_04.jpg