文章目錄
說明
資料來自《詳解MATLAB圖像函數及其應用》
作者:張倩,佔君,陳珊
出版社:電子工業出版社
出版時間:2011-04
這是我對MTALAB圖像處理整理出來的學習筆記,望與君共勉
採用部分只有代碼,其他的我自己收集來的資料,萌新一枚,侵權即刪
內容來自書的第十九章1457頁的圖像特徵提取實戰2
——————————————————————
本次會出現5個圖像窗口,所以我會根據每一次出現的圖像窗口來進行分段解釋
Figure 1
首先讀取圖像
RGB=imread('1234.png');
imshow(RGB);
imread函數
- A=imread(filename)
從指定的圖像中讀取灰度圖像或真彩色圖像
filename是表示文件名全名的字符串(包括擴展名)
也就是***.jpg啊,***.png啊這些圖像文件名字
imshow函數
- imshow(I)
顯示真彩色圖像RGB,
RGB爲三維數組,第三維的維數爲3
其他用語說明
- 三維數組
這一個三維數組在本次案例中是指imread函數操作來的三維數組,如RGB,顯示如下
再打開
這個圖是
Figure 2
然後對圖像進行閾值分割
將圖像轉換爲灰度圖像,設置閾值,對圖像進行閾值分割,生成二值圖像
I=rgb2gray(RGB);
threshold=graythresh(I);
bw=im2bw(I,threshold);
figure;
imshow(bw);
rgb2gray函數
- I=rgb2gray(RGB)
將真彩色RGB圖像或索引圖像轉換爲灰度圖像
參量RGB是一個維數爲MxNx3的數組,表示RGB圖像,上方已經展示出來
graythresh函數
- level=graythresh(I)
計算全局圖像閾值
level爲標準化灰度值,範圍是[0 1]
其他用語解釋
- 閾值
即臨界值,是爲轉化二值圖像做準備來的
而這一次把上圖進行計算全局閾值後得到的level值爲
而這個計算全局圖像閾值的方式是大津法——Otsu方法,又稱最大類間方差法
Otsu算法
- 對於圖像I(x,y)
前景(即目標)和背景的分割閾值記作T
前景像素點數佔整幅圖像的比例記爲ω0,其平均灰度μ0;
背景像素點數佔整幅圖像的比例記爲ω1,其平均灰度爲μ1。
圖像的總平均灰度記爲μ,類間方差記爲g。- 假設圖像的背景較暗,並且圖像的大小爲M×N
圖像中像素的灰度值小於閾值T的像素個數記作N0
像素灰度大於閾值T的像素個數記作N1
則有:
ω0=N0/ M×N (1)
ω1=N1/ M×N (2)
N0+N1=M×N (3)
ω0+ω1=1 (4)
μ=ω0μ0+ω1μ1 (5)
g=ω0(μ0-μ)2+ω1(μ1-μ)2 (6)
將式(5)代入式(6),得到等價公式:
g=ω0ω1(μ0-μ1)^2 (7)
這就是類間方差
採用遍歷的方法得到使類間方差g最大的閾值T,即爲所求。
內容學習來源
作爲一個熱愛學習的人,我當然得去看看這個函數在幹些啥
於是我去畫了個圖
於是
那如果我用三色呢
於是
我們再次引用這裏的的概念來解釋平均灰度
- 平均灰度,反映整體的亮、暗,越高越亮
- 平均對比度,一幅圖亮暗的差異
- 平滑度,一幅圖灰度的均勻性,0-1:平滑-不平滑
- 三階矩,直方圖偏斜度的度量。對稱爲0,右偏斜爲正,左偏斜爲負
- 一致性,度量一致性
- 熵,反映像素的隨機性,越大越粗糙
im2bw函數
- BW=im2bw(I,level)
閾值法轉換圖像爲二值圖像
將灰度圖像I轉換成二值圖像BW
level爲閾值,即標準化灰度值,範圍爲[0 1]
I中大於level的像素設爲1(白色),小於的像素爲0(黑色)
結果當然會得到二值圖像
繼續打開
figure函數
- figure
創建新的圖形對象,在屏幕上單獨顯示的窗口,且窗口中可以輸出圖形
可以看到想要提高效率(偷懶),可以只打一個figure代碼,就可以按順序新建一個圖像窗口,如下圖(本次代碼產生的)
本次產生的圖是
Figure 3
然後去除圖像中的噪聲,開運算去除小於30個像素的目標
bw=bwareaopen(bw,30);
figure;
imshow(bw);
bwareaopen函數
- BW2=bwareaopen(BW,P)
- 移除二值圖像BW中所有少於P個像素的連通元素,生成另一個二值圖像BW2
- 對二值圖像進行形態學開運算,用於移除小目標
- 對於二維圖像默認採用8連通鄰域
三維採用26連通鄰域
本次bwareaopen會對bw進行操作,故之前我展示出來的bw的邏輯矩陣已經是經過變化了的矩陣,有一些地方的1可能變成了0,但是我們只是爲了看看這個圖片在電腦裏是怎麼解釋的(我就是沒看過,我就是想看)
第一次的實戰案例裏我們瞭解到,開運算就是可以去除孤立的小點、毛刺這些東西,P就是結構元素,用於作爲濾波的標準,BW就是濾波對象,接下來我們看看濾波的結果如何
然後我們再來看看兩副圖像的區別
開運算後的圖片:
之前的圖片:
很明顯,一些很小的點被填補上了,這裏被移除的是白點,故可以說是去掉了黑點周圍的毛刺,使邏輯矩陣裏的1(白)變成了0(黑),在圖片的其他地方也是有變化的,我們就說一處
Figure 4
填充圖像縫隙(洞孔)
se=strel('disk',2);
bw=imclose(bw,se);
bw=imfill(bw,'holes');
figure;
imshow(bw);
strel函數
- SE=strel(shape,parameters)
創建形態學結構元素對象
shape可是square方形,line線形,disk圓盤形,ball球形和rectangle長方形等
parameters是對shape的大小描述
結果得到的se是什麼呢,我們來看看
我們繼續打開
可以看到還有兩個按鈕可以繼續點開
再開!
另外一個也不會放過的
查閱資料知道,se爲strel函數創造的形態學結構元素對象——strel對象,代表一個扁平的形態結構元素,那麼這個strel函數就牽涉到strel的對象功能,如下表
函數 | 作用 |
---|---|
imdilate | 膨脹圖像 |
imerode | 腐蝕圖像 |
imclose | 形態接近圖像 |
imopen | 形態上開放的圖像 |
imbothat | 底帽過濾 |
imtophat | 高帽過濾 |
bwhitmiss | 二進制未命中操作 |
decompose | 分解後的結構元素的返回順序 |
reflrct | 反映結構元素 |
translate | 翻譯結構元素 |
imfill(BW,‘holes’) | 空洞填充 |
另外我們還看到,繼續打開的兩個圖中,一個是0,1矩陣,1組合起來的形狀我們就當做圓盤狀吧,然後另一個圖裏只有一個數字2,這個2就來自代碼中後邊我們輸入的2。實際上如果把disk變成square,就會使整個矩陣變成1,變成line,就還需要一個角度,若角度設定爲45度,則會讓1從左下角連續到右上角去,也就是一條線的形狀(矩陣畫圖太難了)
接下來我們看本次用到的strel的對象
imclose函數
- IM2=imclose(IM,SE)
對圖像進行形態學閉運算
對灰度圖像或二值圖像IM進行形態學閉運算,返回閉運算結果圖像IM2
SE爲由strel函數生成的結構元素對象
imfill函數
- BW2=imfill(BW,‘holes’)
顯示二值圖像BW,對二值圖像BW中的目標點孔進行填充點
來看看這一次的圖像的變化
我們可以看到一些很明顯的變化,人物耳朵的輪廓沒了,用這幅圖感覺看不出是怎麼填的洞
那我們把imfiil函數劃掉看看
可以看到耳朵的輪廓還在
那我們來看看那個imclose閉運算的結果
閉運算之後:
閉運算之前:
可以看到經過閉運算,黑色(0)的線條作爲白色(1)的裂縫,被彌補了,也就是補1了
所以我們可以知道,這個過程中,開運算使1變0,閉運算使0變1,正好是兩個基本算子,多少理解了一點吧
Figure 5
接下來提取圖像中的各種目標的幾何特徵,利用幾何特徵及圓形檢測算法判斷每個目標是否是圓形目標。當目標的面積和周長滿足公式ε=4piS/L^2,ε接近於1時,則認爲該目標爲圓形目標
[B,L]=bwboundaries(bw,'noholes');
figure;
imshow(label2rgb(L,@jet,[.5 .5 .5]));%5
bwboundaries函數
- B=bwboundaries(BW)
搜索二值圖像BW的外邊界和內邊界
BW爲矩陣,其元素爲0或1(即二值圖像)
該函數將0視爲背景像素點,1視爲待提取邊界的目標
B爲Px1細胞矩陣,P爲目標和洞的個數
B中的每個細胞元素均爲Qx2矩陣,Q爲邊界所含像素點的個數
故該矩陣中每一行包含邊界像素點的行座標和列座標
我們來看看B裏有什麼
一個元胞數組,然後打開
套娃遊戲,然後我們繼續打開可以看到的是,這就是邊界像素點的座標
- 而本次代碼中使用的方式是
[B,L]=bwboundaries(BW,conn,options)
返回標識矩陣L,用於標識二值圖像中被邊界所劃分的區域,包括目標和洞
conn指定搜索算法中所使用的連通方法,可選4連通和8連通,其中8爲默認值
字符串參量options指定算法的搜索方式,可選holes和noholes
默認使用holes,算法搜索目標的內邊界和外邊界,noholes只搜索目標的外邊界
那麼我們打開L
我好氣啊全是0,純屬來佔內存的?
然後我發現它列有點多…
這就是標識矩陣,用於下邊循環繪製每個邊界
label2rgb函數
- RGB=label2rgb(L,map,zerocolor)
定義輸入標註矩陣L中標註爲0的元素的RGB顏色
zerocolor爲字符串或三元向量
本題內爲三元向量,分表代表R、G、B的顏色,默認爲[1 1 1],即白色 - 聯合imshow函數使用
即imshow(RGB),顯示真彩色圖像RGB,RGB爲三維數組,第三維的維數爲3
這裏的@jet是colormap,解釋是說默認大值爲紅,小爲藍,還可以用colormap(flipud(jet))進行顛倒,但是…
那問題出在哪呢,我認爲是後邊的zerocolor的問題,於是我去修改參數
改成.1 .5 .9之後的樣子,其他顏色有待挖掘呀,然後接下來是圖中耳朵位置的metric值,本圖只有一個地方可以計算,我們待會換個圖
檢測算法
hold on;
for k=1:length(B)
boundary=B{k};
plot(boundary(:,2),boundary(:,1),'w','LineWidth',2);
end
stats=regionprops(L,'Area','Centroid');
threshold=0.94;
for k=1:length(B)
boundary=B{k};
delta_sq=diff(boundary).^2;
perimeter=sum(sqrt(sum(delta_sq,2)));
area=stats(k).Area;
metric=4*pi*area/perimeter^2;
metric_string=sprintf('%2.2f',metric);
if metric>threshold
centroid=stats(k).Centroid;
plot(centroid(1),centroid(2),'ko');
end
text(boundary(1,2)-35,boundary(1,1)+13,metric_string,'Color','y','FontSize',14,'FontWeight','bold');
end
title(['Metrics closer to 1 indicate that','the object is approximately round']);
先給出流程圖
具體的區別我用第三幅圖來觀察了,有需要可以從目錄跳到最後的那個第三幅圖去觀察
regionprops函數
- STATS=regionprops(L,properties)
測量每個標籤區域L的屬性
L爲標識矩陣,L中的正整數元素對應不同的區域
properties可以是逗號分隔的字符串、包含字符串的細胞矩陣、字符串all或字符串basic
此處計算測量值Area(區域像素點個數)、Centroid(區域的質心)
代碼說明:
獲取標識區域的面積和質心屬性
我們打開stats來看
再打開
area即面積,centroid即質心
threshold=0.94是在手動設置圓的閾值,可以觀察下方對比metric和threshold
然後是用循環檢測每一個標識目標
利用邊界座標計算目標周長
area=states(k).Area即獲取目標面積屬性
打開area
然後計算metric值,保存計算結果,將檢測出的圓形目標用黑圈標識出其質心,判斷其是否爲圓
diff函數
- Y=diff(X)
計算沿大小不等於1的第一個數組維度的X相鄰元素之間的差分
這個函數在這次算法裏比較玄學吧,算着算着周長就出來了,我也是看了半天,我們先來看看diff函數是在幹些啥
它的用途有這些
那結果呢
我們可以看到,
-
對於一維向量,diff函數會用右減左,即相鄰數的增量
-
對於二維的矩陣
- 對於diff(A,1,1),就相當於diff(A),並且是用矩陣的下行作被減數,上行作減數
- 對於diff(A,2,1),就相當於diff(diff(A)),並且是用矩陣的下行作被減數,上行作減數
- 對於diff(A,1,2),就相當於diff(A),並且是用矩陣的右列-左列
- 對於diff(A,2,2),就相當於diff(diff(A),並且是用矩陣的右列-左列
所以本次算法中就是把boundary作爲邊緣座標,然後下減上,得到的幾乎都是(0,1)(1,0)(-1,0)和(0,-1),因爲是連續的離散點,然後平方變爲正,再求和,第一個sum計算得到數行一列的1,sqrt之後還是1,行數甚至不變,然後最後一個sum得到周長
sprintf函數
- str=sprintf(formatSpec,A1,…,An)
使用formatSpec指定的格式化操作符格式化數組A1,…,An中的數據,並在str中返回結果文本
text函數
- text(___,Name,Value)
最後我們來換個圖試試
第一幅圖
我去用ps畫了圖,如下
於是我們開始吧
按順序來
第二幅圖
被暗算了一波,我們換個顏色再來
第三幅圖
只到最後一個imshow操作,連邊都沒有描
描完邊之後就沒了,明明figure裏是有描邊的,我也不知道爲什麼保存後就沒了白邊
分別把threshold修改爲0.5和0.1
可以看到計算metric大於threshold的就會在質心出現黑圓圈
那我們再繼續,這次把string_metric去掉
可以看到每個標記都相同了
我們來看最終結果