在自動計算影象中有幾枚硬幣的任務中,分離出前景和背景後是否就可以馬上實現自動計件,如果可以,如何實現?如果不可以,為什麼?
答案是否定的。二值化之後我們的得到的只是前景總畫素的多少,並不知道哪些畫素屬於同一枚硬幣。想要實現自動計件功能還需要用到連通域標記的知識。
連通域標記的方法這裡我們使用種子填充法:
1、遍歷一幅影象。
2、如果遇到前景且該點未被標記,說明在該點附近可能存在與該點相連通的畫素點,即可能存在連通域,停止遍歷。否則繼續遍歷。
3、以該點為seed點,遍歷seed點4鄰域或者8鄰域。如果同為前景,將座標存到乙個棧中,並將這點貼上label,表示已經訪問過該畫素,避免重複訪問。
4、將棧中的座標取出,以該點為seed點,重複2操作。
5、直到棧中的所有元素都取出,說明已經遍歷完了該label的所有元素。
6、label++;從一開始停止遍歷的點繼續遍歷。
7、重複2-6直到遍歷到最後乙個畫素
*--------------------------【練習】連通域標記-------------------------------------*/
/*引數說明:
src_img:輸入影象
flag_img:作為標記的空間(在函式內部設定為單通道)
draw_img:作為輸出的影象,不同的連通域的顏色不同
iflag:作為判斷屬於連通域的畫素目標值,一般來說我們是對二值圖進行連通域分析,所以這個值為0或者255,物體是0/1,則iflag是0/1
type: type==4 :用4鄰域 type==8 :用8鄰域
nums: 設定的label畫素個數截斷值,被標記的連通域畫素個數必須大於nums才算是正確的連通域。用來防止二值化後的效果並不好的情況。
*/void
seed_connected_component_labeling
(mat& src_img,mat& flag_img,mat& draw_img,
int iflag,
int type,
int nums)
;//存放每個區域的畫素個數
//mat(縱座標,橫座標)
//point(橫座標,縱座標)
for(
int j =
0; j < img_row; j++
)//height}}
//對8鄰域進行標記
else
if(type ==8)
}}} next_label++;}
}}next_label = next_label -1;
int all_labels = next_label;
std::cout <<
"labels : "
<< next_label <<:endl>
//給不同連通域的塗色並且記錄下每個連通域的畫素個數
for(
int j =
0;j < img_row;j++
)//行迴圈
} std::cout <<
"初步結論 : "
<< std::endl;
for(
int i =
1;i <= next_label;i++
) std::cout <<
"最後結論 : "
<< std::endl;
std::cout <<
"截斷畫素數目 : "
<< nums << std::endl;
for(
int i =
1;i <= next_label;i++)}
std::cout <<
"labels : "
<< all_labels << std::endl;
}int
main()
原圖:
二值圖(可以看到有幾個噪點,而且影象的右邊和上邊是白色的,這是因為原圖我是截圖的,邊界並沒有剪裁好,這點在下面的連通域標記會有影響)
我給屬於不同連通域的物體塗上不同的顏色。
下面是列印出來的資訊:初步得到的label是19個,其中label1就是我所說的截圖邊界問題。其他的幾個畫素個數小的就是噪點。
通過設定門限,畫素個數小於500的標籤物體我們將它視為雜訊。最後得到的label數目正好是10,也就是硬幣的數目。
連通域標記函式**部分,可以看到我還嘗試了其他兩種遍歷seed周圍元素的方式,分別是順時針和逆時針。但是運算速度沒有第一種快,至於原因我沒有深究。希望有心人能給我講解一波。此外,試了一下8鄰域,運算速度也得到了下降。
這就是我說的剪裁錯誤,嘿嘿。
此外,二值化的方法我是用的人工調整,原圖受到非均勻光線的照射,全域性大津閾值得到的效果並不是很好,反而由於直方圖雙峰性比較明顯,迭代法看起來還不錯。不過為了連通域標記的時候能夠準確一點,我就用滑條調整閾值了。
滑動條調整閾值的**在這兒:
迭代法、大津的**在這兒:
首先回顧之前遇到的問題:受到雜訊影響,十個硬幣竟然貼了19個labels,儘管利用限制畫素個數的方法來限制,但這種方法有許多弊端。
這幾天學習了一些簡單的形態學操作,其中腐蝕操作有個作用:去除黏連畫素以及雜訊。
這不就正好能解決之前遇到的問題嘛!
操作也很簡單,加上兩行**就行。
結果執行如下(把自己簡陋的限制畫素函式去掉了)
效果很好啊!
關於腐蝕的詳細講解請看這邊:
連通域標記
二值影象,顧名思義就是影象的亮度值只有兩個狀態 黑 0 和白 255 二值影象在影象分析與識別中有著舉足輕重的地位,因為其模式簡單,對畫素在空間上的關係有著極強的表現力。在實際應用中,很多影象的分析最終都轉換為二值影象的分析,比如 醫學影象分析 前景檢測 字元識別,形狀識別。二值化 數學形態學能解決...
連通域標記方法
這裡列舉二值影象連通域標記演算法包括直接掃瞄標記演算法和二值影象連通域標記快速演算法 一 直接掃瞄標記演算法把連續區域作同乙個標記,常見的四鄰域標記演算法和八鄰域標記演算法。1 四鄰域標記演算法 1 判斷此點四鄰域中的最左,最上有沒有點,如果都沒有點,則表示乙個新的區域的開始。2 如果此點四鄰域中的...
opencv實現連通域
文章 在本文中使用影象連通域統計使用opencv中的cvfloodfill方法,但是在cvfloodfill方法中cvconnectedcomp引數無法返回具體點座標位置資訊,找了些資料 給cvseq分配空間但是還是contour內容沒有值,估計是opencv2.00版本不支援。如果想獲取點座標資訊...