matlab圖像處理基礎及入門

引言:
作爲一個大一狗,剛剛接觸計算機編程,居然老師不教我們C語言,教matlab,我也是蠻震驚的。不過了,matlab確實比C語言好玩又好學多了,進階的也快一點,畢竟全是庫函數與工具箱嘛,語法也是很人性化的。
纔剛剛大一就得到了一些大神學長的指導,爲我們班無償輔導數據擬合與數組圖像處理基礎,在這裏特別要感謝學長,所以我在的第一篇CSDN博客就奉獻給這個了,數據擬合與數組圖像處理基礎的綜合應用。


下面步入正題:

先給出我要處理的原圖:

這裏寫圖片描述


我想做的或者說學長要我做的就是要銳化這些個棋子.對於銳化整個圖中較爲突出的一個物體(即其邊界處與背景有較大變化),我們可以先對其進行邊緣提取,其方法有多種,就我目前膚淺所知,大致有兩種方法:
1:用拉普拉斯算子(例如[-1 -1 -1;-1 8 -1;-1 -1 -1]),調用imfilter函數對圖像進行卷積濾波(具體什麼原理並不是很清楚,好像是用導數?)可以提取出其邊界。
2先用rgb2gray函數把RGB真彩色圖轉爲灰度圖,再調用邊界提取函數edge,該函數大概有五種邊界提取方式,分別是Sober,Prewitt,Roberts,LOG,Canny.各有優缺點吧(具體也不知道),生成二值圖。
接着我們將所提取的邊界圖乘以某個係數(這個係數是依實際效果而定的,反覆嘗試找一個較合適的),再與原圖像相加,就可以得到物體被銳化的圖.
兩種方法代碼如下:

a=imread('E:/圖片存放室/1.JPG');
h=[-1 -1 -1;-1 8 -1;-1 -1 -1];%拉普拉斯算子,對圖像進行求導,突出其邊緣
a1=imfilter(a,h);
a2=a1/2+a;%係數自行設定
a22=rgb2gray(a);
a3=edge(a22,'Canny');
a3(:,:,2)=a3;%將其轉爲三維數組
a3(:,:,3)=a3(:,:,2);
a3=uint8(a3);%數字類型轉換(logic變爲uint8型)
a4=a3*60+a;%係數依效果自行設定
figure(1);
subplot(1,3,1);
imshow(a);
title('原圖');
subplot(1,3,2);
imshow(a2);
title('imfilter函數拉普拉斯算子濾波處理圖');
subplot(1,3,3);
imshow(a4);
title('edge函數Canny提取');

處理後的圖像與原圖像的對比如圖:

這裏寫圖片描述
可以看到,邊界變化較大的物體被突出,但是我們無法選擇特定的物體,所以我就依學長的思路想了一下方法,結合數據擬合與圖像處理兩方面知識,思路如下:
分爲以下幾個模塊:


模塊一:
提取出原圖像中含有棋子的矩形區域,用imtool函數確定其位置;再用拉普拉斯算子卷積濾波(imfilter),對圖像進行求導,確定邊界;設定閾值(可以多次嘗試設定適合的閾值(應該有相應自動確定閾值的算法)),並將處理的圖變爲二值圖(用im2bw函數)。
處理後的二值圖如下:
這裏寫圖片描述
可以看到,二值圖的效果並不好,棋子內部也有白點(棋子反光),矩形區域邊界處也有白點,所以我們還要把其他爲一的點去除,使之爲零。
模塊一代碼如下:

clc;
clear;
close all;%全是套路
i=imread('E:/圖片存放室/1.JPG');
h=[-1 -1 -1;-1 8 -1;-1 -1 -1];%拉普拉斯算子,對圖像進行求導,突出其邊緣
a=i(54:90,135:180,1:3);%提取出原圖像的含有棋子的矩形區域,用imtool函數確定其位置
a1=imfilter(a,h);%用卷積和h進行濾波
b=100/255;
a2=im2bw(a1,b);%設定閾值(可以多次嘗試設定適合的閾值),並將處理的圖變爲二值圖
a3=a1/2+a;%鑑於邊緣求導與原本圖像相加過亮,故依效果將邊緣求導後的圖像除二
figure,imshow(a2);
a2(15:27,13:40)=0;%去除不在棋子邊緣上的爲1的點,減少以後擬合曲線的誤差
a2(35:36,17:30)=0;%去除不在棋子邊緣上的爲1的點,減少以後擬合曲線的誤差
a2(8,16)=0;%去除不在棋子邊緣上的爲1的點,減少以後擬合曲線的誤差
a2(20,2)=0;%去除不在棋子邊緣上的爲1的點,減少以後擬合曲線的誤差
a2(4,4)=0;%去除不在棋子邊緣上的爲1的點,減少以後擬合曲線的誤差
a2(4,38)=0;%去除不在棋子邊緣上的爲1的點,減少以後擬合曲線的誤差
a2(9,6)=0;%去除不在棋子邊緣上的爲1的點,減少以後擬合曲線的誤差
a2(1,1:46)=0;%將a2邊界的爲1的點變爲0
a2(37,1:46)=0;%將a2邊界的爲1的點變爲0
a2(1:37,1)=0;%將a2邊界的爲1的點變爲0
a2(1:37,46)=0;%將a2邊界的爲1的點變爲0
a2(37,1:46)=0;%將a2邊界的爲1的點變爲0


模塊二:
按學長的思路,接下來使找到該二值圖像的質心,用質心公式進行計算(後期擬合時確定初值時用)
公式如下:
這裏寫圖片描述

其中xi,yi爲點的橫縱座標,p(xi,yi)爲改點的數值。
我們對於一般情況求其質點座標,用兩個兩層循環結構計算其結果:
模塊二代碼如下:

%用質心公式確定棋子的圓心
s2=0;%賦初值
[d,e]=size(a2);
for n=1:d%分子mi*ni的和
    for m=1:e       
            c1=n*a2(n,m);
            s1=s1+c1;
            c2=m*a2(n,m);
            s2=s2+c2;
    end
end
s3=0;
for n=1:d%分母mi的和
    for m=1:e  
        s3=s3+a2(n,m);
    end
end
w1=s1/s3;%確定圓心座標
w2=s2/s3;
figure,imsho,w1,'*');%畫圓心

其圖像如下:
這裏寫圖片描述


模塊三:
對二值圖像中爲一的點進行數據擬合,對其進行橢圓擬合,我用自己的方法進行擬合(雖說應該有庫函數可以完美擬合橢圓),即將橢圓分爲上下兩部分進行擬合(用非線性擬合的lsqcurvefit函數(知道函數形式,未知參數))(這裏初值很重要,我們要事先大致估算出初值(橢圓圓心由模塊二確定)),再對上下擬合的結果取均值作爲最終參數。接着利用參數確定出橢圓的焦點。
模塊三代碼如下:

iiii=1;%初值化 
for ii=1:105%一共有105個邊界點 
if o(ii)>17.3%把縱座標大於某值小於某值的點分別賦給兩個新數組,即將橢圓上下兩部分 
qy(iii)=o(ii); 
qx(iii)=p(ii); 
iii=iii+1; 
else 
py(iiii)=o(ii); 
px(iiii)=p(ii); 
iiii=iiii+1; 
end 
end%分別對上下的橢圓曲線進行擬合, 
k=[w2 225 225/400 w1];%對橢圓上部擬合,對橢圓上部賦初值(起初的橢圓參數)(選好初值很重要,否則擬合的不好) 
we=@(k,p)(k(1)+sqrt(k(2)-k(3).*(p-k(4)).^2));%y=f(x)橢圓上部含參表達式 
k1=lsqcurvefit(we,k,qx,qy);%確定擬合的參數值 
hold on; 
we=@(k,p)(k(1)-sqrt(k(2)-k(3).*(p-k(4)).^2));%對橢圓上部擬合,同上 
k2=lsqcurvefit(we,k,px,py); 
k3(1)=(k1(1)+k2(1))/2;%對上下擬合後的橢圓參數取平均值,圓心縱座標 
k3(2)=(k1(2)+k2(2))/2;%對上下擬合後的橢圓參數取平均值,短半軸平方 
k3(3)=(k1(3)+k2(3))/2; 
k3(4)=(k1(4)+k2(4))/2;%對上下擬合後的橢圓參數取平均值,圓心橫座標 
k3(3)=k3(2)/k3(3);%對上下擬合後的橢圓參數取平均值,長半軸平方 
ezplot(‘(x-24)^2/317.772+(y-18.5)^2/245-1’,[0,50,0,50]);%符號畫圖用ezplot函數(表達式用單引號引),查看擬合效果如何 
hold on; 
cc=sqrt(k3(3)-k3(2));%求擬合橢圓的半焦距c 
cclx=kt(ccrx,k3(1),’‘,cclx,k3(1),’‘);%畫出兩個焦點 

其圖像如下:
這裏寫圖片描述


模塊四:
依據橢圓的第一定義:橢圓上的點到兩橢圓焦點的距離和爲定值,將在橢圓外的點賦爲原圖像中的值,橢圓內與橢圓上的點不變(銳化),因此只有棋子內部與邊界上的點被銳化處理了,棋盤與棋線都未做銳化處理,這樣就可以銳化特定物體了。
模塊四代碼如下:

a4=a3;%將a2賦給新數組a4 
for mm=1:d 
for nn=1:e 
if sqrt((mm-cclx)^2+(nn-k3(4))^2)+sqrt((mm-ccrx)^2+(nn-k3(4))^2)>sqrt(4*k3(3))%判斷a4圖像上的點哪些在橢圓外(即點到兩焦點的距離大於2c)。 
a4(mm,nn,1:3)=a(mm,nn,1:3);%將這些點不做銳化處理,將原圖a的值賦回給他們 
end 
end 
end 
figure,imshow(a4); 
i(54:90,135:180,1:3)=a4;%將處理過的棋子返還給原圖 
figure,imshow(i);%展示棋子被處理後的圖的效果

圖像如下:
這裏寫圖片描述


總結:
這是matlab圖像處理與數據擬合的綜合應用,算是我大一上學期matlab學習的總結與應用吧,毫無疑問,這個寫煩了(主要是要兼顧數據擬合),第一次嘗試吧,總要走不少坑。如果知道相應的算法,應該是比較簡單的(可惜數學太差,不大看懂算法後面的數學原理,深表遺憾)。


P.S:

另一種方法:閉運算
我可以用圖像的腐蝕與膨脹,使用閉運算,先腐蝕後膨脹,可以去掉一些細小的黑色突出部分,將那些棋盤線去除掉,使之並不那麼顯眼。(具體原理也不懂)。

index:
閉運算的物理結果也是會平滑對象的輪廓,但是與開運算不同的是,閉運算一般會將狹窄的缺口連接起來形成細長的彎口,並填充比結構元素小的洞。底帽變換是原始圖像減去其閉運算後的圖像。閉運算可以除去比結構元素更小的暗色細節。

代碼如下:

clc;
clear;
a=imread('E:/圖片存放室/1.JPG');
 s=strel('disk',2);
 a1=imclose(a,s);
 h=[-1 -1 -1;-1 8 -1;-1 -1 -1];
 a3=imfilter(a1,h);
 a5=a3/3+a;
 a4=imsubtract(a1,a);
  a2=a1+a3/3-a4/3;
subplot(1,3,2),imshow(a2);
title('腐蝕閉運算後圖像');
subplot(1,3,1),imshow(a);
title('原圖像');
subplot(1,3,3),imshow(a5);
title('底帽變化後圖像');

圖像如下:
這裏寫圖片描述
可以看到,棋子被銳化突出了,但棋盤線卻變得不那麼顯眼了,效果無疑比上面方法要好。


另一種未完成的方法:霍夫變換
可以用來分離出具有相同幾何特徵的幾何形狀(如直線與圓等)。
所以我們可以先將該圖中的直線棋盤線提取出來,然後對棋子進行銳化,或直接對橢圓棋子提取並進行銳化。對於霍夫直線提取,matlab中提供了三個互爲關聯的函數:hough,houghpeaks,houghlines,其原理目前我尚不清楚,用法也不清楚(比較複雜),我嘗試了一下,感覺效果非常不好,幾乎與原來的邊界提取二值圖沒啥區別。
其失敗的代碼如下:

clc;
clear;
a=imread('E:/圖片存放室/1.JPG');
a1=rgb2gray(a);
a1= edge(a1,'Prewitt');
[H,theta,rho]=hough(a1);
peaks=houghpeaks(H,20);
lines = houghlines(a1,theta,rho,peaks);
for n=1:2
    for i=lines(n).point1(2):lines(n).point2(2)
        for ii=lines(n).point1(1):lines(n).point2(1)
            a1(i,ii)=0;
        end
    end
end
figure(1),imshow(a1);

這個等我以後再去慢慢理解吧,超出了我的理解範圍,實際上開始學圖像處理就是個坑,對於原理一竅不通,可謂只知其然,不知其所以難啊。不行得去補理論知識了。


有個疑問:既然matlab可以將其語言轉成C/C++語言,爲什麼還是絕大部分人去學OpenCV啊?是OpenCV裏有matlab沒有的庫嗎?還是可開源交流?好像OpenCV能更好的應用,而matlab更多做仿真研究。。。話說如果學圖像處理(就是學光電專業的)方面是不是matlab與OpenCV都要學啊?關鍵是自己C語言水平太渣了,C++又根本不會,所以OpenCV只能暫時放一放了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章