Halcon測量圓直徑(半徑)的方法之暴力擬合法 vs 測量工具法

原文鏈接:https://blog.csdn.net/horsee/article/details/82794569

今天要給大家分享一點關於Halcon測量圓直徑(半徑)的方法。
首先容我囉嗦兩句:之所以要對這個看似很基礎的問題進行探討,主要原因有二,其一是這個問題確實困擾了我一段時間,當然這主要是由於我自己經驗不足所致;其二是爲了解決這個問題,我在網上查閱了很多博客資料,突然發現一件比較有趣的事情——網上多數能搜索到的關於這個問題的博客居然都主動避開了Halcon設計者的初衷,即最簡單實現它的方式,反而和我這個經驗不足的傢伙一樣,採用了自以爲合理的解決方案——而且居然還是相近甚至相同的思路。針對這個現象,我後來也發現了一些原因,留待本篇的末段解釋,此處賣一個關子,暫且不表。

暴力擬合法


上來先給大家講一下在多數博客裏採用的方法——思路其實簡單又暴力,而且確實是有效的,我將其稱爲暴力擬合法。
算法如下:

  • Step1: 如下圖給出一個帶有圓形區域的圖形,首先我們調用一個畫圓的工具,來逼近它的邊緣區域。
  • Step2: 然後繪製這個圓的兩個同心圓作爲邊界,即直徑略大於和略小於它的兩個同心圓;
  • Step3: 這樣做的目的,是爲了把包含待測量圓邊界的環狀區域分割出來;
  • Step4: 對分割出的局部環形區域作邊緣提取,得到一系列邊界輪廓;
  • Step5: 採用Halcon的輪廓擬合算子完成圓的擬合。

短短五步,成功獲得了當前圓的擬合參數。
參考代碼如下所示:

dev_close_window()
dev_update_off ()
dev_open_file_dialog ('read_image', 'default', 'default', Selection)
read_image (Image, Selection)
get_image_size (Image, Width, Height)
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_display (Image)
draw_circle_mod (WindowHandle, Height/2, Width/2, Width/20, Row, Column, Radius)
gen_circle_contour_xld (ContCircle, Row, Column, Radius, 0, 6.28318, 'positive', 1)
dev_display (ContCircle)
dev_set_color ('green')
gen_circle (Circle1, Row, Column, Radius*13.0/10)
gen_circle (Circle2, Row, Column, Radius*7.0/10)
dev_set_draw ('margin')
dev_display (Circle1)
dev_display (Circle2)
stop()
difference (Circle1, Circle2, RegionDifference)
reduce_domain (Image, RegionDifference, ImageReduced)
edges_sub_pix (ImageReduced, Edges, 'canny', 1, 20, 40)
fit_circle_contour_xld (Edges, 'algebraic', -1, 0, 0, 3, 2, Row1, Column1, Radius1, StartPhi, EndPhi, PointOrder)
gen_circle_contour_xld (ContCircle1, Row1, Column1, Radius1, 0, 6.28318, 'positive', 1)
dev_clear_window ()
dev_display (Image)
dev_display (ContCircle1)
message1 := 'CenterRow: ' + Row1
message2 := 'CenterCol: ' + Column1
message3 := 'Radius: ' + Radius1
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
disp_message (WindowHandle, message1, 'window', 0, -1, 'forest green', 'false')
disp_message (WindowHandle, message2, 'window', 20, -1, 'forest green', 'false')
disp_message (WindowHandle, message3, 'window', 40, -1, 'forest green', 'false')



真的成功了嗎?
但是,完美?No!

這個方法有一個致命缺陷,因爲它是我們強行通過Contour輪廓算子的一些特性來完成的擬合,所以它是一個一次性的產物,並不符合Halcon設計者的初衷。
爲什麼這樣說呢?我舉下一個例子來說明這樣做的侷限性:
還是剛纔這個工件的圖像,但是現在不是一張,而是一組,這個工件在圖像中的位置角度等均發生了變化,現在要求我們1)定位工件2)在定位工件的基礎上找到圓孔並計算它的直徑。
我們知道,Halcon完成“定位”-“測量”分別是通過*.shm和*.mtr文件這樣的形式來構成通用方案的。那麼通過暴力擬合法,如何才能跟*.shm文件進行綁定,從而減低我們在定位完成的基礎上,二次定位圓ROI的工作量呢?
(當然這也是有方法的,並且我也嘗試並實現過,需要通過記錄圓和定位模板間的相對位置關係,通過仿射變換來得到每次定位後的圓ROI,但這樣增加了很多參數的傳遞,使定位過程和測量過程更加孤立,顯然也不會是Halcon設計者的設計思路)
別急,相信和我水平相當的Halcon小白使用者都會想到Halcon的測量助手工具。假如問題不是要測量一個圓的直徑,而是要測量某個工件的寬度,那麼我們可以通過Halcon的Measure工具生成一個測量卡尺。點一下生成代碼,略微添加幾個變量,輕鬆加愉快。可是問題來了,Halcon的測量助手居然沒有提供測量圓直徑的工具!

測量工具法


但是事實上Halcon提供了一個圓的測量卡尺,只是它的名稱被藏在了另一個算子裏。下面隆重推出這個算子:

add_metrology_object_generic( : : MetrologyHandle, Shape, ShapeParam, MeasureLength1, MeasureLength2, MeasureSigma, MeasureThreshold, GenParamName, GenParamValue: Index)

你也許和我一樣,在對這個算子還不瞭解的時候完全忽視它。從名稱上看,這個算子和圓卡尺工具有半毛錢關係?(相信這也是博客裏都是暴力擬合法而鮮有提及這個方法的主要原因。)
然而當看到Shape這個參數的列表時,我就知道Halcon的設計者絕對還是聰明人,這個參數有一個選項是’Circle’.
當Shape參數設置爲’Circle’時, ShapeParam的格式要寫成[Row, Column, Radius].
這樣就清楚了,問題也解決了,和其他測量工具一樣,只要調用這個算子生成一個圓測量卡尺,通過apply_metrology_model,再通過get_metrology_object_result取出測量結果就大功告成了。

這個方法和任何其他測量工具一樣,都可以與前置的定位工具進行align,省下了好多事情,而且也維持了Halcon在定位-測量環節上工具邏輯的一致性。
參考代碼如下:

dev_close_window()
dev_update_off ()
dev_open_file_dialog ('read_image', 'default', 'default', Selection)
read_image (Image, Selection)
get_image_size (Image, Width, Height)
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_display (Image)
draw_circle_mod (WindowHandle, Height/2, Width/2, Width/20, Row, Column, Radius)
gen_circle_contour_xld (ContCircle, Row, Column, Radius, 0, 6.28318, 'positive', 1)
dev_display (ContCircle)
dev_set_color ('green')
create_metrology_model (MetrologyHandle)
add_metrology_object_generic (MetrologyHandle, 'circle', [Row, Column, Radius], 20, 5, 1, 30, [], [], Index)

apply_metrology_model (Image, MetrologyHandle)
get_metrology_object_result (MetrologyHandle, 'all', 'all', 'result_type', 'all_param', Parameter)
get_metrology_object_result_contour (Contour, MetrologyHandle, 'all', 'all', 1.5)
get_metrology_object_measures (Contours, MetrologyHandle, 'all', 'all', Row1, Column1)
dev_display (Contours)

clear_metrology_model (MetrologyHandle)

dev_clear_window ()
dev_display (Image)
dev_display (Contour)
message1 := 'CenterRow: ' + Parameter[0]
message2 := 'CenterCol: ' + Parameter[1]
message3 := 'Radius: ' + Parameter[2]
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
disp_message (WindowHandle, message1, 'window', 0, -1, 'forest green', 'false')
disp_message (WindowHandle, message2, 'window', 20, -1, 'forest green', 'false')
disp_message (WindowHandle, message3, 'window', 40, -1, 'forest green', 'false')

 

發佈了20 篇原創文章 · 獲贊 3 · 訪問量 5331
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章