matlab——識別圖像中的圓形目標

說明

資料來自《詳解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

其他用語說明

  1. 三維數組
    這一個三維數組在本次案例中是指imread函數操作來的三維數組,如RGB,顯示如下

在matlab中的讀取樣式

再打開

再打開這個圖是

動漫圖

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]

其他用語解釋

  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,即爲所求。
    內容學習來源
    作爲一個熱愛學習的人,我當然得去看看這個函數在幹些啥
    於是我去畫了個圖
    黑白五五卡一號
    於是
    沒想到
    那如果我用三色呢
    三色
    於是
    三色
    我們再次引用這裏的的概念來解釋平均灰度
  1. 平均灰度,反映整體的亮、暗,越高越亮
  2. 平均對比度,一幅圖亮暗的差異
  3. 平滑度,一幅圖灰度的均勻性,0-1:平滑-不平滑
  4. 三階矩,直方圖偏斜度的度量。對稱爲0,右偏斜爲正,左偏斜爲負
  5. 一致性,度量一致性
  6. 熵,反映像素的隨機性,越大越粗糙

im2bw函數

  • BW=im2bw(I,level)
    閾值法轉換圖像爲二值圖像
    將灰度圖像I轉換成二值圖像BW
    level爲閾值,即標準化灰度值,範圍爲[0 1]
    I中大於level的像素設爲1(白色),小於的像素爲0(黑色)

結果當然會得到二值圖像
邏輯矩陣
繼續打開

好不容易找到的有1的地方

figure函數

  • figure
    創建新的圖形對象,在屏幕上單獨顯示的窗口,且窗口中可以輸出圖形

可以看到想要提高效率(偷懶),可以只打一個figure代碼,就可以按順序新建一個圖像窗口,如下圖(本次代碼產生的)

無描述
本次產生的圖是
第二張圖

Figure 3

然後去除圖像中的噪聲,開運算去除小於30個像素的目標

bw=bwareaopen(bw,30);
figure;
imshow(bw);

bwareaopen函數

  • BW2=bwareaopen(BW,P)
    1. 移除二值圖像BW中所有少於P個像素的連通元素,生成另一個二值圖像BW2
    2. 對二值圖像進行形態學開運算,用於移除小目標
  • 對於二維圖像默認採用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
我們繼續打開

打開se
可以看到還有兩個按鈕可以繼續點開
再開!

Neighborhood
另外一個也不會放過的

Dimensionality
查閱資料知道,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
一個元胞數組,然後打開

套娃
套娃遊戲,然後我們繼續打開可以看到的是,這就是邊界像素點的座標

繼續打開

  • 而本次代碼中使用的方式是
    [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函數是在幹些啥
它的用途有這些
在這裏插入圖片描述那結果呢
在這裏插入圖片描述我們可以看到,

  1. 對於一維向量,diff函數會用右減左,即相鄰數的增量

  2. 對於二維的矩陣

    • 對於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去掉
在這裏插入圖片描述可以看到每個標記都相同了
我們來看最終結果
在這裏插入圖片描述

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