Halcon例程分析10:仿射變換物體的測量

打開halcon,按下ctrl+e打開halcon自帶例程。方法->模板匹配(基於形狀)->pm_measure_board.hdev

*********************************************************************************
* This example program shows the use of pattern matching with shape models
* to locate an object.  Furthermore, it shows how to use the detected position
* and rotation of the object to construct search spaces for inspection tasks.
* In this particular example, the print on an IC is used to find the IC.  From the
* found position and rotation, two measurement rectangles are constructed to
* measure the spacing between the leads of the IC.  Because of the lighting
* used in this example, the leads have the saturated gray value of 255 at several
* positions and rotations, which enlarges the apparent width of the leads, and
* hence seems to reduce the spacing between the leads, although the same
* board is used in all images.
*********************************************************************************
dev_update_pc ('off')
dev_update_window ('off')
dev_update_var ('off')
*虛擬圖像採集,seq文件是一個文本序列,對其中的文字逐行讀取,打開對應文本路徑的圖像,模擬一個相機採集圖像
open_framegrabber ('File', 1, 1, 0, 0, 0, 0, 'default', -1, 'default', -1, 'default', 'board/board.seq', 'default', -1, 1, FGHandle)
*採集單幀圖像,獲得圖像寬高
grab_image (Image, FGHandle)
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
dev_open_window (Height + 70, 0, Width, 120, 'black', WindowHandleText)
*激活圖像窗口,設置顯示字符樣式
dev_set_window (WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
set_display_font (WindowHandleText, 16, 'mono', 'true', 'false')
dev_set_color ('red')
dev_display (Image)
*定義生成矩形的變量,左上角與右下角座標
Row1 := 188
Column1 := 182
Row2 := 298
Column2 := 412
*生成矩形ROI區域
gen_rectangle1 (Rectangle, Row1, Column1, Row2, Column2)
*獲得ROI區域中心座標
area_center (Rectangle, Area, Row, Column)
*定義變量用於生成上下兩個測量矩形
Rect1Row := -102
Rect1Col := 5
Rect2Row := 107
Rect2Col := 5
RectPhi := 0
*測量芯片引腳矩形長170,寬5
RectLength1 := 170
RectLength2 := 5
*生成兩個測量矩形,以矩形ROI區域爲基準,第一個上移102,第二個下移107,水平方向
gen_rectangle2 (Rectangle1, Row + Rect1Row, Column + Rect1Col, RectPhi, RectLength1, RectLength2)
gen_rectangle2 (Rectangle2, Row + Rect2Row, Column + Rect2Col, RectPhi, RectLength1, RectLength2)

*處理矩形ROI區域,在原圖上截取ROI區域做處理
reduce_domain (Image, Rectangle, ImageReduced)
*創建模板
*第一個參數創建模板的ROI區域圖像
*第二個參數金子塔層數
*第三個參數模板的起始角度
*第四個參數模板的總角度
*第五個參數是模板的角度步長,這裏設置爲1°,也就是說這裏總共會創建出360個模板用於尋找圖像
*第六個參數是否優化模板點,這裏選擇不優化
*第七個參數極性選擇,選擇使用極性則必須是在與模板相同的背景下選擇物體,例如模板中是在白色背景下選擇黑色的目標物,則查找的時候也是在白色背景下找黑色目標物
*第八個參數是模板灰度閾值,即灰度差值超過這個數值的點纔會選擇爲模板點,
*第九個參數是最小灰度值,用於去除噪聲影響的
*最後一個參數模板ID,後面需要用到模板就通過這個ID查找
create_shape_model (ImageReduced, 4, 0, rad(360), rad(1), 'none', 'use_polarity', 30, 10, ModelID)
*獲取模板的亞像素輪廓
get_shape_model_contours (ShapeModel, ModelID, 1)
*生成單位矩陣,用於平移變換,不生成單位矩陣直接使用下面的vector_angle_to_rigid也是一樣的
hom_mat2d_identity (HomMat2DIdentity)
hom_mat2d_translate (HomMat2DIdentity, Row, Column, HomMat2DTranslate)
*vector_angle_to_rigid (0, 0, 0, Row, Column, 0, HomMat2DTranslate)
*把查找到的輪廓平移到圖像中的相應位置上。從ROI區域上找到的模板輪廓實際上默認位置是中心與原圖像原點重合的,
*所以要顯示在圖像相應位置上需要經過一定的旋轉平移變換
affine_trans_contour_xld (ShapeModel, ShapeModelTrans, HomMat2DTranslate)
*把模板輪廓顯示到原圖像上
dev_display (Image)
dev_set_color ('green')
dev_display (ShapeModelTrans)
dev_set_color ('blue')
dev_set_draw ('margin')
dev_set_line_width (3)
dev_display (Rectangle1)
dev_display (Rectangle2)
dev_set_draw ('fill')
dev_set_line_width (1)
dev_set_color ('yellow')
disp_message (WindowHandle, ['Press left button to start','and stop the demo'], 'window', 12, 12, 'black', 'true')
*阻塞程序,等待鼠標左鍵按下才往下執行
get_mbutton (WindowHandle, Row3, Column3, Button1)
wait_seconds (0.5)
Button := 0
*一直執行,當鼠標左鍵按下Button=1時程序退出循環
while (Button != 1)
    dev_set_window (WindowHandle)
    dev_set_part (0, 0, Height - 1, Width - 1)
    *從虛擬相機裏獲取一幀圖像
    grab_image (ImageCheck, FGHandle)
    dev_display (ImageCheck)
    count_seconds (S1)
    *查找模板
    *第一個參數用於查找的圖像
    *第二個參數模板ID
    *第三個參數起始角度
    *第四個參數查找的總角度值,這裏是360度全方位查找
    *第五個參數最小分數,查找到的圖像與原模板會有一個相似度比較,越接近1圖像越相似
    *第六個參數查找的個數,爲0時是把所有目標查找出來
    *第七個參數是最大重疊度,表示找到的兩個目標間可以有多大比例重疊
    *第八個參數亞像素精度選擇
    *第九個參數金字塔層數
    *第十個參數搜索貪婪度,越大搜索得越快,表示搜索得越不仔細
    *第十一個參數搜索到的目標物的行座標,搜到多個目標時這個參數是一個數組
    *第十二個參數搜索到的目標物的列座標,搜到多個目標時這個參數是一個數組
    *第十三個參數搜索到的目標物的角度值,搜到多個目標時這個參數是一個數組
    *第十四個參數搜索到的目標物的分數值,越接近1與模板越相似,搜到多個目標時這個參數是一個數組
    find_shape_model (ImageCheck, ModelID, 0, rad(360), 0.7, 1, 0.5, 'least_squares', 4, 0.7, RowCheck, ColumnCheck, AngleCheck, Score)
    count_seconds (S2)
    dev_display (ImageCheck)
    *判斷是否搜到目標
    if (|Score| > 0)
        dev_set_color ('green')
        *對模板進行旋轉平移變換,變換到搜索到的區域位置,方便在原圖上直觀顯示
        *hom_mat2d_identity (HomMat2DIdentity)
        *hom_mat2d_translate (HomMat2DIdentity, RowCheck, ColumnCheck, HomMat2DTranslate)
        *hom_mat2d_rotate (HomMat2DTranslate, AngleCheck, RowCheck, ColumnCheck, HomMat2DRotate)
        *vector_angle_to_rigid是以上兩個函數的綜合,既有平移,也有旋轉
        vector_angle_to_rigid (0, 0, 0, RowCheck, ColumnCheck, AngleCheck, HomMat2DRotate)
        *HomMat2DRotate是從圖像原點旋轉平移到查找到的目標中心點的旋轉平移矩陣
        affine_trans_contour_xld (ShapeModel, ShapeModelTrans, HomMat2DRotate)
        *顯示平移旋轉後的模板輪廓
        dev_display (ShapeModelTrans)
        *例程中把矩形中心位置平移回原點對應的位置上,再對這個點通過HomMat2DRotate旋轉平移矩陣旋轉到新圖像上對應的位置處
        *即第二個參數Rect1Row=Row+Rect1Row-Row,第三個參數Rect1Col=Column+Rect1Col-Column
        *affine_trans_pixel (HomMat2DRotate, Rect1Row, Rect1Col, Rect1RowCheck, Rect1ColCheck)
        *affine_trans_pixel (HomMat2DRotate, Rect2Row, Rect2Col, Rect2RowCheck, Rect2ColCheck)
        
         *下面我自己寫的方法:求出原圖上模板中心點與檢測出來的目標點中心位置對應的旋轉平移矩陣,
         *那麼就可以用這個矩陣求出原模板上任意點在新圖像上的座標了,再在這個座標上畫出測量矩形
         *HomMat2D是原圖像上模板中心點座標到檢測圖像上檢測出的模板的中心座標的平移變換矩陣
        vector_angle_to_rigid (Row, Column, 0, RowCheck, ColumnCheck, AngleCheck, HomMat2D)
        affine_trans_pixel (HomMat2D, Rect1Row+Row, Rect1Col+Column, Rect11RowCheck, Rect11ColCheck)
        affine_trans_pixel (HomMat2D, Rect2Row+Row, Rect2Col+Column, Rect22RowCheck, Rect22ColCheck)
        *在相應位置上生成測量矩形
        gen_rectangle2 (Rectangle1Check, Rect11RowCheck, Rect11ColCheck, AngleCheck, RectLength1, RectLength2)
        gen_rectangle2 (Rectangle2Check, Rect22RowCheck, Rect22ColCheck, AngleCheck, RectLength1, RectLength2)
        *顯示測量矩形
        dev_set_color ('blue')
        dev_set_draw ('margin')
        dev_set_line_width (3)
        dev_display (Rectangle1Check)
        dev_display (Rectangle2Check)
        dev_set_draw ('fill')
        count_seconds (S3)
        *生成測量矩形
        gen_measure_rectangle2 (Rect11RowCheck, Rect11ColCheck, AngleCheck, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle1)
        gen_measure_rectangle2 (Rect22RowCheck, Rect22ColCheck, AngleCheck, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle2)
        *下面這個函數是提取與測試矩形垂直方向上的的邊緣對,想象一下在矩形長軸方向上做灰度差分,得到的曲線應該是每個一段距離出現一個上尖角與一個下尖角
        *第一個上尖角的X座標RowEdgeFirst,第一個上尖角的Y座標ColumnEdgeFirst
        *第一個下尖角的X座標RowEdgeSecond,第一個下尖角的Y座標ColumnEdgeSecond
        
        *第一個參數輸入圖像
        *第二個參數測量矩形的句柄
        *第三個參數(1.5)是高斯平滑sigma值
        *第四個參數(30)是最低閾值,對應上述尖角的高度值
        *第五個參數('negative')是上述差分值的黑白方向,爲negative時是白到黑爲第一點,如果是爲positive時爲黑到白爲第一點
        *第六個參數是('all')是返回所有的測量到的值,即返回所有的尖角位置
        *第九個參數(AmplitudeFirst)是上尖角最大幅值的大小
        *(PinwWidth)是上尖角與下尖角之間的距離
        *(PinDistance)是下尖角與上尖角之間的距離
        measure_pairs (ImageCheck, MeasureHandle1, 2, 90, 'positive', 'all', RowEdgeFirst1, ColumnEdgeFirst1, AmplitudeFirst1, RowEdgeSecond1, ColumnEdgeSecond1, AmplitudeSecond1, IntraDistance1, InterDistance1)
        measure_pairs (ImageCheck, MeasureHandle2, 2, 90, 'positive', 'all', RowEdgeFirst2, ColumnEdgeFirst2, AmplitudeFirst2, RowEdgeSecond2, ColumnEdgeSecond2, AmplitudeSecond2, IntraDistance2, InterDistance2)
        count_seconds (S4)
        *顯示檢測出來的小直線
        dev_set_color ('red')
        disp_line (WindowHandle, RowEdgeFirst1 - RectLength2 * cos(AngleCheck), ColumnEdgeFirst1 - RectLength2 * sin(AngleCheck), RowEdgeFirst1 + RectLength2 * cos(AngleCheck), ColumnEdgeFirst1 + RectLength2 * sin(AngleCheck))
        disp_line (WindowHandle, RowEdgeSecond1 - RectLength2 * cos(AngleCheck), ColumnEdgeSecond1 - RectLength2 * sin(AngleCheck), RowEdgeSecond1 + RectLength2 * cos(AngleCheck), ColumnEdgeSecond1 + RectLength2 * sin(AngleCheck))
        disp_line (WindowHandle, RowEdgeFirst2 - RectLength2 * cos(AngleCheck), ColumnEdgeFirst2 - RectLength2 * sin(AngleCheck), RowEdgeFirst2 + RectLength2 * cos(AngleCheck), ColumnEdgeFirst2 + RectLength2 * sin(AngleCheck))
        disp_line (WindowHandle, RowEdgeSecond2 - RectLength2 * cos(AngleCheck), ColumnEdgeSecond2 - RectLength2 * sin(AngleCheck), RowEdgeSecond2 + RectLength2 * cos(AngleCheck), ColumnEdgeSecond2 + RectLength2 * sin(AngleCheck))
        dev_set_line_width (1)
        *引腳總數目是兩邊引腳數之和
        NumLeads := |IntraDistance1| + |IntraDistance2|
        MinDistance := min([InterDistance1,InterDistance2])
        *打開個小窗口顯示文字信息
        dev_set_window (WindowHandleText)
        dev_set_part (0, 0, 119, Width - 1)
        dev_clear_window ()
        disp_message (WindowHandleText, 'Matching: Time: ' + ((S2 - S1) * 1000)$'5.2f' + 'ms , Score: ' + Score$'7.5f', 'image', 20, 20, 'green', 'false')
        disp_message (WindowHandleText, 'Measure:  Time: ' + ((S4 - S3) * 1000)$'5.2f' + ' ms, Num. leads: ' + NumLeads$'2d', 'image', 50, 20, 'red', 'false')
        disp_message (WindowHandleText, '          Min. lead dist: ' + MinDistance$'6.3f', 'image', 80, 20, 'red', 'false')
    endif
    dev_error_var (Error, 1)
    dev_set_check ('~give_error')
    *獲取鼠標點狀態信息,也可以響應鍵盤的事件,程序不阻塞
    *R是鼠標行座標,C是鼠標點擊處的列座標,Button指示是那個按鍵被按下
    *0:No button,1:Left button,2:Middle button,4:Right button,8:Shift key,16:Ctrl key,32:Alt key.
    get_mposition (WindowHandle, R, C, Button)
    dev_error_var (Error, 0)
    dev_set_check ('give_error')
    if (Error != H_MSG_TRUE)
        Button := 0
    endif
endwhile
dev_set_window (WindowHandleText)
dev_close_window ()
*關閉虛擬相機
close_framegrabber (FGHandle)

模板圖像

查找測試圖像

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