廉江網(wǎng)站建設(shè)公眾號推廣合作平臺
文章目錄
- 一、引言
- 二、檢測圓形
- 三、總結(jié)
一、引言
前面的文(用戶指南/快速向?qū)?#xff09;差不多已經(jīng)把HALCON的基本內(nèi)容講完了,并且在學(xué)習(xí)過程中還跑過一個簡單示例——在單一背景下定位回形針。示例跑過,頓時覺得自己行了,但如果此時(假設(shè)你和我一樣沒有其他圖像處理經(jīng)驗)你想上手解決一個實際問題,很可能寸步難行。
就拿我來說,隨手找了張圖片,想定位圖片中的目標(biāo)圖形——硬幣。
于是,按照回形針示例中的步驟,借用灰度圖像來閾值化,得到的圖片是這樣的,
先不談背景中的大紅塊,連顏色相近的文字也被保留了下來,這不是我希望保留的。不過也很正常,因為用到的圖像處理是基于形態(tài)學(xué)的,簡單講就是顏色、形狀、面積的匹配,是比較傻瓜式的,實際上計算機并不認(rèn)識硬幣。
那如何去掉這些背景中不希望保留的元素呢,經(jīng)過我一番查閱,知道了兩種常用操作——腐蝕(erosion)和膨脹(dilation)。因為本文不是主要介紹它們的實現(xiàn),所以只簡單談一下經(jīng)過它們處理的效果。
- 腐蝕(erosion)
- 自然界中的腐蝕,假設(shè)你有一塊鐵板,經(jīng)過腐蝕后,可能會變得像下圖一樣銹跡斑斑且有許多破洞,這些破洞大的區(qū)域,可能原本就有損壞、比較脆弱;而一些保留相對完好的區(qū)域,原本可能是成塊的、比較結(jié)實的部分(假設(shè)腐蝕對每塊區(qū)域作用都一樣)。
而圖像處理中的腐蝕,作用于引言中的示例圖后,就得到了下圖。可以看到,其實效果類似鐵板腐蝕,大塊圖形保留較好,而一些細(xì)小圖形直接消失了(被腐蝕掉了);大圖形上的一些小孔,經(jīng)過腐蝕也變大了。
膨脹(dilation) - 說到膨脹,自然就想到吹氣球,氣球充氣后變大了(當(dāng)然也可能爆掉)。圖像處理中的膨脹也類似(但不會爆),它是與腐蝕相反的操作。把圖像中的像素/區(qū)域想成一個氣球,經(jīng)過膨脹后,它就變大了。下面對示例圖做膨脹,原來那些密密麻麻的字體明顯變粗壯了,就像墨水在紙上洇開來一樣。
Ok,關(guān)于腐蝕和膨脹到這里就差不多了(應(yīng)用章節(jié)能理解其效果即可)?,F(xiàn)在開始跑一個官方示例 Inspection of Ball Bonding ,在HDevelop示例程序中搜索 ball 關(guān)鍵字,可以找到該示例工程,選中 ball.hdev 打開。
二、檢測圓形
這是示例原圖,現(xiàn)在要找到并標(biāo)注黑色圓形粘接口,接下來一行行學(xué)習(xí)它的程序(共五十多行)。
HALCON程序的頭幾行,
* ball.hdev: Inspection of Ball Bonding
*
dev_update_window ('off')
dev_close_window ()
dev_open_window (0, 0, 728, 512, 'black', WindowID)
*(星號)開頭的是注釋,剩下三行以 dev_ 前綴的與圖形處理無直接關(guān)系,它們的作用分別是:
- 會關(guān)閉圖像變量向圖形窗口的自動輸出(設(shè)置為’off’,還有一點好處是當(dāng)你選中圖像變量,圖形窗口中只會顯示選中的圖像變量,方便觀察,不然需要手動再選一次 顯示/清除)
- 關(guān)閉活動的圖形窗口
- 并打開一個728×512的黑色背景窗口。
接著,讀取原圖,
read_image (Bond, 'die/die_03')
雖然上面代碼中關(guān)閉了圖像變量自動顯示在活動窗口,但在你單步調(diào)試程序時,這點會被無視掉。下面用 dev_display 顯式輸出讀取的圖像到圖形窗口。
dev_display (Bond)
set_display_font (WindowID, 14, 'mono', 'true', 'false')
disp_continue_message (WindowID, 'black', 'true')
stop ()
剩下兩句看似是系統(tǒng)算子,但實際上是預(yù)定義好的外部函數(shù)。效果就是在圖像下方顯示文字,接著 stop() 暫停程序執(zhí)行。
接下來是老朋友了,閾值化。
threshold (Bond, Bright, 100, 255)
閾值化后是一個新的算子 shape_trans ,它可以變換區(qū)域的形狀。這邊填的參數(shù)為 ‘rectangle2’ ,在輸入?yún)^(qū)域中外接最小矩形。上面閾值化后的圖像,頂部明顯有一片區(qū)域是黑的,也就是沒有像素的,這部分區(qū)域在后續(xù)處理過程中是不需要的,我們?nèi)绾稳サ羲?#xff0c;就需要外接矩形了。
shape_trans (Bright, Die, 'rectangle2')
接下來幾步是在外接矩形外圍畫一個框,并顯示預(yù)定義好的文字提示信息,然后暫停一下。
dev_set_color ('green')
dev_set_line_width (3)
dev_set_draw ('margin')
dev_display (Die)
disp_continue_message (WindowID, 'black', 'true')
stop ()
你可能會問,有這么一個矩形有啥用呢?
別急,接下來的算子 reduce_domain 中會用到它,
reduce_domain (Bond, Die, DieGrey)
它會從原圖中裁剪出矩形區(qū)域的圖像,
這里的裁剪出圖像,其實圖像的尺寸未發(fā)生變化,你可以看到黑色背景還是在的,這相當(dāng)于把矩形以外的區(qū)域去掉了,但保留背景/畫布(HALCON中還有一個算子)。
上面這幾步操作(獲取目標(biāo)矩形,用矩形裁剪圖像)很常用,通常獲取ROI區(qū)域就是這么做的。
接下來對裁剪得到區(qū)域再次進行閾值化,這次保留了灰度值低的區(qū)域(靠近0接近黑色,靠近255接近白色),另外圖像頂部的黑色區(qū)域其實是沒有像素的,所以并未選中
threshold (DieGrey, Wires, 0, 50)
下一步又是一個新的算子 fill_up_shape ,它的作用是填充區(qū)域中具有某些特征的空洞,下面參數(shù)表示的特征是面積,范圍是1-100。也就是將該范圍面積的空洞填滿,
fill_up_shape (Wires, WiresFilled, 'area', 1, 100)
來看下放大后的效果吧,處理前,
處理后,
還是很明顯的,區(qū)域內(nèi)的小圓孔被填充滿了。你可能會問,不是填充滿嗎,為什么消失了?因為圖案是接近黑色的,填充后看起來就是消失了。
接下來又是一些額外操作,顯示原圖底片,用紅色填充滿處理后區(qū)域,
dev_display (Bond)
dev_set_draw ('fill')
dev_set_color ('red')
dev_display (WiresFilled)
disp_continue_message (WindowID, 'black', 'true')
stop ()
下一步是一個很有用的操作——開操作(halcon中名稱為opening的都是開操作相關(guān)的),它的原理其實是腐蝕和膨脹的結(jié)合,即先腐蝕后膨脹,
opening_circle (WiresFilled, Balls, 15.5)
處理后的效果,是不是非常離譜,但理解了文章開頭說的效果后,其實不難想象。
接下來,切換了輸出顏色,重新輸出處理后的區(qū)域,
dev_set_color ('green')
dev_display (Balls)
disp_continue_message (WindowID, 'black', 'true')
stop ()
接下來三個算子, 先是connection 尋找區(qū)域內(nèi)的連通部分;
第二個是新算子 select_shape ,找到具有目標(biāo)特征的形狀,這邊填寫的參數(shù)是 ‘circularity’ ,就是類圓的圖形;
第三個算子就是字面意思,對圖形按位置排序(這邊參數(shù)表示按列值升序排)。
connection (Balls, SingleBalls)
select_shape (SingleBalls, IntermediateBalls, 'circularity', 'and', 0.85, 1.0)
sort_region (IntermediateBalls, FinalBalls, 'first_point', 'true', 'column')
然后,又是換色顯示原圖對比,并輸入提示文本,
dev_display (Bond)
dev_set_colored (12)
dev_display (FinalBalls)
disp_continue_message (WindowID, 'black', 'true')
stop ()
最后,
smallest_circle 確定這些圓形區(qū)域的最小外接圓,并將輸出的坐標(biāo)和半徑做處理后輸出到圖形窗口。
smallest_circle (FinalBalls, Row, Column, Radius)
NumBalls := |Radius|
Diameter := 2 * Radius
meanDiameter := mean(Diameter)
minDiameter := min(Diameter)
dev_display (Bond)
disp_circle (WindowID, Row, Column, Radius)
dev_set_color ('white')
disp_message (WindowID, 'D: ' + Diameter$'.4', 'image', Row - 2 * Radius, Column, 'white', 'false')
dev_update_window ('on')
至此,示例程序處理完畢。
之后,我用了示例方法處理文章開頭的示例圖,得到如下效果
三、總結(jié)
整個過程其實并不復(fù)雜,畢竟我們只是調(diào)用算子,不需要關(guān)注算法細(xì)節(jié)。
但這里還是得稍微總結(jié)一下所涉及的常用操作,
- 閾值化,拿到圖之后通常會先閾值化一下,方便后續(xù)處理。
- 選取ROI,通常獲取一個形狀,然后用該形狀去裁剪原圖,可以減少后續(xù)圖像處理量,并減少干擾區(qū)域。
- 腐蝕和膨脹,上面示例中的開操作(opening)就包含了腐蝕和膨脹,你也可以分開來使用,常見的還有閉操作(closing)。這些操作通常用來去掉圖像背景中的干擾區(qū)域,填充空缺。
- 基于的特征的圖形選擇,這步是在尋找連通區(qū)域(connection)之后的。
上面提到的閾值化、選取ROI等操作都可以UI交互實現(xiàn),比直接調(diào)參更方便。