【HALCON】【樣例解析】3d_coordinates.hdev


# 1 簡介 計算傾斜與旋轉對象在世界座標系下的尺寸。該樣例主要計算HALCON標定板的邊距與標誌點的直徑。

2 測量流程

2.1 相機標定

  1. 創建相機標定模型
  2. 設置標定模型的參數
  3. 提取每一張圖像的標誌點與外輪廓
  4. 執行相機標定,獲取標定誤差

2.2 邊距

  1. 獲取標定板的黑色外框
  2. 通過輪廓選擇平行的輪廓線
  3. 獲取過中心且垂直於輪廓線的標誌點座標
  4. 計算交點
  5. 構建二維測量模型
  6. 通過測量模型計算邊緣點座標
  7. 映射到世界座標系
  8. 在世界座標系中計算邊距

2.3 標誌點半徑

  1. 提取標誌點外輪廓
  2. 橢圓擬合
  3. 映射到世界座標系
  4. 世界座標系下的橢圓擬合
  5. 計算半徑的平均值於方差

3 代碼解析

3.1 程序初始化

// 關閉當前的圖像窗口
dev_close_window ()

// 以指定的位置、尺寸、背景顏色打開一個新的窗口
dev_open_window (0, 0, 768, 576, 'black', WindowHandle)

// 取消所有自動更新
dev_update_off ()

// 設置繪製模式
dev_set_draw ('margin')

// 設置顯示線寬
dev_set_line_width (3)

// 設置顯示字體
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')

3.2 相機標定

// 指定標定板描述文件
CalTabDescrFile := 'caltab_big.descr'

/* 設置初始相機內參
 * 參數按位置順序依次爲:
 * 		鏡頭焦距
 * 		徑向扭曲係數
 * 		像元水平尺寸(單位:米)
 * 		像元垂直尺寸(單位:米)
 * 		圖像座標系下的主點列座標(單位:像素)
 * 		圖像座標系下的主點行座標(單位:像素)
 * 		圖像寬度(單位:像素)
 * 		圖像高度(單位:像素)
 */
gen_cam_par_area_scan_division (0.008, 0, 0.0000086, 0.0000086, 384, 288, 768, 576, StartCamPar)

/* 創建相機標定模型
 * 參數按位置順序依次爲:
 * 		標定的類型
 * 		同時標定的相機數量
 * 		標定板對象的數量
 * 		輸出的標定模型句柄
 */
create_calib_data ('calibration_object', 1, 1, CalibDataID)

/* 設置標定模型的初始相機內參
 * 參數按位置順序依次爲:
 * 		標定模型句柄
 * 		相機索引
 * 		相機類型
 * 		相機內參
 */
set_calib_data_cam_param (CalibDataID, 0, [], StartCamPar)

/* 通過標定板描述文件確定標定板對象
 * 參數按位置順序依次爲:
 * 		標定句柄
 * 		標定對象索引
 * 		標定對象描述文件
 */
set_calib_data_calib_object (CalibDataID, 0, CalTabDescrFile)

// 指定用於標定的標定板圖像的數量
NumImages := 10

// 循環讀取圖像,並提取標誌點
for I := 1 to NumImages by 1
	// 讀取圖像
    read_image (Image, 'calib/calib-3d-coord-' + I$'02d')
    // 顯示圖像
    dev_display (Image)
    // 顯示提示信息
    Message := 'Find calibration plate in\nall calibration images (' + I + '/' + NumImages + ')'
    disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
    
    /* 在圖像中查找標定對象
     * 參數按位置順序依次爲:
     * 		標定對象圖像
     * 		標定句柄
     * 		相機索引
     * 		標定對象索引
     * 		額外參數名稱集合
     * 		額外參數值集合
     */
    find_calib_object (Image, CalibDataID, 0, 0, I - 1, [], [])
    /* 獲取初始標定參數
     * 參數按位置順序依次爲:
     * 		標定句柄
     * 		標定數據類型,'calib_obj', 'calib_obj_pose', 'camera', 'model', 'tool'
     * 		索引
     * 		數據名
     * 		返回數據值
     */
    get_calib_data (CalibDataID, 'camera', 0, 'init_params', StartCamPar)
    /* 獲取標誌點的圖像座標與姿態
     * 參數按位置順序依次爲:
     * 		標定句柄
     * 		相機索引
     * 		標定對象索引
     * 		標定對象姿態索引
     * 		標誌點行座標
     * 		標誌點列座標
     * 		標誌點索引號
     * 		標定對象相對於相機座標系的姿態
     */
    get_calib_data_observ_points (CalibDataID, 0, 0, I - 1, Row, Column, Index, Pose)
    /* 獲取標定對象邊界輪廓
     * 參數按位置順序依次爲:
     * 		輸出輪廓
     * 		標定句柄
     *      輪廓名,'caltab', 'last_caltab', 'marks'
     * 		相機索引
     * 		標定對象索引
     * 		標定對象姿態索引
     */
    get_calib_data_observ_contours (Contours, CalibDataID, 'caltab', 0, 0, I - 1)
    // 創建十字標識
    gen_cross_contour_xld (Cross, Row, Column, 6, 0.785398)
    // 設置顏色
    dev_set_color ('green')
    // 顯示輪廓
    dev_display (Contours)
    // 設置顏色
    dev_set_color ('yellow')
    // 顯示十字標識
    dev_display (Cross)
endfor
// 顯示提示信息
disp_continue_message (WindowHandle, 'black', 'true')
stop ()

// 執行標定
calibrate_cameras (CalibDataID, Error)
// 獲取標定後的相機參
get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam)

在這裏插入圖片描述

3.3 標定對象中心點提取

爲了計算邊距或標誌點的半徑,都需要對圖像進行預處理。因此,先介紹預處理函數。

/* 函數的參數依次爲:
 * 		Image       : (IN) 標定對象圖像
 * 		PlateRegion : (OUT) 標定對象區域
 * 		CalibDataID : (IN)  標定句柄
 * 	    PoseIndex   : (IN)  標定姿態索引
 * 		Distance    : (OUT) 邊距的粗略距離
 *      Phi         : (OUT) 標定對象的旋轉角度
 * 		RowCenter   : (OUT) 標定板中心行座標
 * 		ColumnCenter: (OUT) 標定板中心列座標
 */
// 固定閾值二值化
threshold (Image, Region, 0, 120)
// 連通域提取
connection (Region, ConnectedRegions)
// 根據條件選擇區域
select_shape (ConnectedRegions, SelectedRegions, ['holes_num','rect2_len1','rect2_len2'], 'and', [1,120,120], [1,200,200])
// 填充區域
fill_up (SelectedRegions, PlateRegion)

二值化

二值化

在這裏插入圖片描述

連通域

在這裏插入圖片描述

根據形狀選擇後的區域

在這裏插入圖片描述

填充後的區域
/* 根據區域的邊界生成輪廓
 *	第三個參數爲提取邊界的模式,有以下值:
 *		center       : 邊界像素的中心點連接成的輪廓
 *		border       : 邊界像素的外輪廓
 *		border_holes : 除了邊界像素的被提取,孔邊界也被提取
 */
gen_contour_region_xld (PlateRegion, Contours, 'center')
/* 將輪廓分割成直線段和圓弧段或橢圓弧段
 * 參數按位置順序依次爲:
 * 		輸入輪廓
 * 		分割後輪廓
 * 		分割模式,'lines', 'lines_circles', 'lines_ellipses'
 * 		平滑輪廓使用的點數
 * 		第一次迭代使用弧替代直線段的最大距離
 * 		第二次迭代使用弧替代直線段的最大距離
 */
segment_contours_xld (Contours, ContoursSplit, 'lines', 7, 4, 2)
// 計算迴歸線
regress_contours_xld (ContoursSplit, RegressContours, 'no', 1)
// 輪廓選擇
select_contours_xld (RegressContours, VerticalContours, 'direction', rad(45), rad(135), -0.5, 0.5)
// 輪廓選擇
select_contours_xld (VerticalContours, LongContours, 'length', 150, 500, -0.5, 0.5)

// 選擇第一個垂直邊緣
select_obj (LongContours, Contour, 1)
// 獲取輪廓點
get_contour_xld (Contour, Rows, Columns)

// 獲取起始點
RowBegin1 := Rows[0]
ColBegin1 := Columns[0]
// 獲取終止點
RowEnd1 := Rows[|Rows| - 1]
ColEnd1 := Columns[|Columns| - 1]

// 選擇第二個垂直邊緣
select_obj (LongContours, Contour, 2)
// 獲取輪廓點
get_contour_xld (Contour, Rows, Columns)

// 獲取起始點
RowBegin2 := Rows[0]
ColBegin2 := Columns[0]
// 獲取終止點
RowEnd2 := Rows[|Rows| - 1]
ColEnd2 := Columns[|Columns| - 1]

// 獲取標誌點的中心座標
get_calib_data_observ_points (CalibDataID, 0, 0, PoseIndex - 1, Row, Column, PoseIndex, _Pose)

// 選取過中心且垂直於提取垂直邊緣的標誌點中心
Row1 := Row[find(PoseIndex,21)]
Row2 := Row[find(PoseIndex,27)]
Column1 := Column[find(PoseIndex,21)]
Column2 := Column[find(PoseIndex,27)]

// 顯示直線段,並計算焦點
dev_get_window (WindowHandle)
disp_line (WindowHandle, Row1, Column1, Row2, Column2)
disp_line (WindowHandle, RowBegin1, ColBegin1, RowEnd1, ColEnd1)
intersection_lines (Row1, Column1, Row2, Column2, RowBegin1, ColBegin1, RowEnd1, ColEnd1, RowA, ColA, IsOverlapping)

// 顯示直線段,並計算焦點
dev_get_window (WindowHandle)
disp_line (WindowHandle, Row1, Column1, Row2, Column2)
disp_line (WindowHandle, RowBegin2, ColBegin2, RowEnd2, ColEnd2)
intersection_lines (Row1, Column1, Row2, Column2, RowBegin2, ColBegin2, RowEnd2, ColEnd2, RowB, ColB, IsOverlapping)

// 計算距離
distance_pp (RowA, ColA, RowB, ColB, Distance)
// 計算角度
line_orientation (RowA, ColA, RowB, ColB, Phi)

// 計算中心座標
RowCenter := (RowA + RowB) / 2
ColumnCenter := (ColA + ColB) / 2

在這裏插入圖片描述

邊緣輪廓

在這裏插入圖片描述

輪廓分段

在這裏插入圖片描述

輪廓提取

在這裏插入圖片描述
在這裏插入圖片描述

交點直線段

3.4 邊距測量

// 讀取圖像
read_image (Image, 'calib/calib-3d-coord-01')

// 獲取測量參數
get_measure_positions (Image, PlateRegion, CalibDataID, 0, Distance, Phi, RowCenter, ColumnCenter)
// 生成測量矩形,用於顯示
gen_rectangle2_contour_xld (Rectangle, RowCenter, ColumnCenter, Phi, Distance * 0.52, 8)
// 矩形區域測量
gen_measure_rectangle2 (RowCenter, ColumnCenter, Phi, Distance * 0.52, 8, 768, 576, 'nearest_neighbor', MeasureHandle)
// 執行測量
measure_pos (Image, MeasureHandle, 1, 40, 'all', 'all', RowEdge, ColumnEdge, Amplitude, Distance1)

// 顯示測量點的位置
Rows := [RowEdge[0],RowEdge[|RowEdge| - 1]]
Columns := [ColumnEdge[0],ColumnEdge[|RowEdge| - 1]]
gen_cross_contour_xld (Cross, Rows, Columns, 16, Phi)

// 獲取標定板的姿態
get_calib_data (CalibDataID, 'calib_obj_pose', [0,0], 'pose', Pose)
// 圖像座標系到世界座標系的映射
image_points_to_world_plane (CamParam, Pose, Rows, Columns, 'm', SX, SY)
// 世界座標系的距離季孫
distance_pp (SY[0], SX[0], SY[1], SX[1], Width)


// 顯示測量結果
dev_display (Image)
dev_set_color ('white')
dev_set_line_width (3)
dev_display (Rectangle)
dev_set_color ('green')
dev_set_draw ('fill')
dev_set_line_width (2)
dev_display (Cross)
dev_set_draw ('margin')
disp_message (WindowHandle, 'Width = ' + (Width * 100)$'8.3f' + 'cm', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')

在這裏插入圖片描述

測量區域

在這裏插入圖片描述

測量結果

3.5 半徑測量

// 腐蝕區域
erosion_circle (PlateRegion, ROI, 17.5)
// 摳圖
reduce_domain (Image, ROI, ImageReduced)
// 亞像素邊緣提取
edges_sub_pix (ImageReduced, Edges, 'canny', 1, 20, 60)
// 輪廓選擇
select_contours_xld (Edges, SelectedEdges, 'contour_length', 20, 99999999, -0.5, 0.5)
// 橢圓擬合
fit_ellipse_contour_xld (SelectedEdges, 'fitzgibbon', -1, 2, 0, 200, 3, 2, Row, Column, Phi, Radius1, Radius2, StartPhi, EndPhi, PointOrder)

MeanRadius1 := mean(Radius1)
MeanRadius2 := mean(Radius2)
DevRadius1 := deviation(Radius1)
DevRadius2 := deviation(Radius2)

// 映射到世界座標
contour_to_world_plane_xld (SelectedEdges, WorldCircles, CamParam, Pose, 'mm')

// 世界座標系下的邊緣擬合
fit_ellipse_contour_xld (WorldCircles, 'fitzgibbon', -1, 2, 0, 200, 3, 2, Row, Column, Phi, RadiusW1, RadiusW2, StartPhi, EndPhi, PointOrder)
MeanRadiusW1 := mean(RadiusW1)
MeanRadiusW2 := mean(RadiusW2)
DevRadiusW1 := deviation(RadiusW1)
DevRadiusW2 := deviation(RadiusW2)

// 顯示結果
dev_display (Image)
dev_set_color ('yellow')
dev_set_line_width (3)
dev_display (SelectedEdges)
Message := 'Measured dimensions of the ellipses'
Message[0] := '                    Mean Radius1; Mean Radius2; (Standard deviations [%])'
Message[1] := 'Image coordinates:       ' + MeanRadius1$'5.2f' + 'px; ' + MeanRadius2$'5.2f' + 'px            (' + (DevRadius1 / MeanRadius1 * 100)$'4.2f' + ', ' + (DevRadius2 / MeanRadius2 * 100)$'4.2f' + ')'
Message[2] := 'World coordinates:       ' + (MeanRadiusW1 / 10)$'5.2f' + 'cm; ' + (MeanRadiusW2 / 10)$'5.2f' + 'cm            (' + (DevRadiusW1 / MeanRadiusW1 * 100)$'4.2f' + ', ' + (DevRadiusW2 / MeanRadiusW2 * 100)$'4.2f' + ')'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')

在這裏插入圖片描述

區域腐蝕

在這裏插入圖片描述

摳圖

在這裏插入圖片描述

亞像素邊緣提取

在這裏插入圖片描述

輪廓篩選

在這裏插入圖片描述

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