Halcon Camera Calibration Procedure Notes

Halcon program notes:

* 
* Initialize the program
dev_close_window ()               //关闭图像窗口
dev_open_window (0, 0, 768, 576, 'black', WindowHandle)  //打开一个窗口,背景为黑色
dev_update_pc ('off') //更新窗口为关闭
dev_update_window ('off')  //更新窗口为off状态
dev_update_var ('off')   //在程序执行期间关闭变量窗口的更新。
dev_update_time ('off')  //关闭算子的开关时间测量。
dev_set_draw ('margin') //定义区域填充模式
dev_set_line_width (3)  //定义绘制时的线宽为3
set_display_font (WindowHandle, 14, 'mono', 'false', 'false')  //设置字体,不用粗体和斜体
* 
* Calibrate the camera.
* 
CaltabName := 'caltab_big.descr'
StartCamPar := [0.008,0,0.0000086,0.0000086,384,288,768,576]  //定义数组并且赋值
NStartPose := []
NRow := []
NCol := []
caltab_points (CaltabName, X, Y, Z)    
NumImages := 10
for I := 1 to NumImages by 1
    read_image (Image, 'calib/calib-3d-coord-' + I$'02d')
    dev_display (Image)
    find_caltab (Image, Caltab, CaltabName, 3, 112, 5)  //分割图像中的标准校准板区域。
    dev_set_color ('green')
    dev_display (Caltab)
    find_marks_and_pose (Image, Caltab, CaltabName, StartCamPar, 128, 10, 18, 0.9, 15, 100, RCoord, CCoord, StartPose) //从图像中提取二维校准标记并计算外部摄像机参数的初始值。
    //提取并排序输入图像Image区域CalTabRegion内的校准标记的2D中心点[RCoord,CCoord]
    //计算外部相机参数(StartPose)的粗略估计,即校准板相对于相机坐标系统的3D姿态(=位置和方向)
    dev_set_color ('red')
    disp_circle (WindowHandle, RCoord, CCoord, gen_tuple_const(|RCoord|,1.5))
    NStartPose := [NStartPose,StartPose]
    NRow := [NRow,RCoord]
    NCol := [NCol,CCoord]
endfor
camera_calibration (X, Y, Z, NRow, NCol, StartCamPar, NStartPose, 'all', CamParam, NFinalPose, Errors)
//X 有校准标记的所有x坐标的有序元组(以米为单位)。
//Y 具有校准标记的所有y坐标的有序元组(以米为单位)。
//Z 带有校准标记的所有z坐标的有序元组(以米为单位)。
//NRow 对提取的校准标记的所有行坐标进行排序(以像素为单位)。
//NCol 同时最小化过程确定所有相机参数。
//StartCamPar 内部摄像机参数的初始值。
//NStartPose 用外部摄像机参数的所有初始值排序的元组。
//
//CamParam 内部摄像机参数。
//NFinalPose 与所有外部摄像机参数排序的元组。
//Errors 以像素为单位的平均误差距
//
//  /      \     / x \     /        \   /      \
//  | p(c) |  =  | y |  =  |  R   t | * | p(w) |
//  |      |     | z |     |        |   |      |
//  \  1   /     \ 1 /     \ 0 0  1 /   \  1   /
// 
// 现在,测量表格黑色边框的大小。
// 
// 通过设置NumImage来浏览全部10张图像是有益的。
NumImage := 9
// 获取校准表的姿势
Pose := NFinalPose[(NumImage - 1) * 7:(NumImage - 1) * 7 + 6]
read_image (Image, 'calib/calib-3d-coord-' + NumImage$'02d')
dev_display (Image)
dev_set_color ('green')
// 提取校准表。
threshold (Image, Region, 0, 140)   //使用全局阈值分割图像。
connection (Region, ConnectedRegions)  //计算区域的连接组件。
select_shape (ConnectedRegions, SelectedRegions, ['holes_num','rect2_len1','rect2_len2'], 'and', [1,150,150], [1,200,200])//借助形状特征选择区域。
fill_up (SelectedRegions, RegionFillUp)  //Fill up holes in regions.
// 从表格边框构建测量矩形。
gen_contour_region_xld (RegionFillUp, Contours, 'center')  //从地区生成XLD轮廓。
segment_contours_xld (Contours, ContoursSplit, 'lines', 7, 4, 2)  //分段XLD轮廓分为线段和圆弧或椭圆弧。
regress_contours_xld (ContoursSplit, RegressContours, 'no', 1)  //计算回归线的参数到XLD轮廓。
select_contours_xld (RegressContours, VerticalContours, 'direction', rad(45), rad(135), -0.5, 0.5)  //返回XLD轮廓的坐标。
select_contours_xld (VerticalContours, LongContours, 'length', 150, 500, -0.5, 0.5)
// 测量线由表格的两条垂直边界线的中心点构成。
select_obj (LongContours, Contour, 1)  
get_contour_xld (Contour, Row, Col)
RowBegin1 := Row[0]
ColBegin1 := Col[0]
RowEnd1 := Row[|Row| - 1]
ColEnd1 := Col[|Col| - 1]
select_obj (LongContours, Contour, 2)
get_contour_xld (Contour, Row, Col)
RowBegin2 := Row[0]
ColBegin2 := Col[0]
RowEnd2 := Row[|Row| - 1]
ColEnd2 := Col[|Col| - 1]
RowM1 := (RowBegin1 + RowEnd1) / 2
ColM1 := (ColBegin1 + ColEnd1) / 2
RowM2 := (RowBegin2 + RowEnd2) / 2
ColM2 := (ColBegin2 + ColEnd2) / 2
Phi := atan2(ColM2 - ColM1,RowM2 - RowM1)
Length1 := sqrt(pow(ColM2 - ColM1,2) + pow(RowM2 - RowM1,2)) / 2
Row := (RowM1 + RowM2) / 2
Column := (ColM1 + ColM2) / 2
//现在在图像中进行实际测量。
gen_measure_rectangle2 (Row, Column, Phi + rad(90), Length1 + 7, 8, 768, 576, 'nearest_neighbor', MeasureHandle) //准备提取垂直于矩形的直边。
measure_pos (Image, MeasureHandle, 1, 20, 'all', 'all', RowEdge, ColumnEdge, Amplitude, Distance1) //提取垂直于矩形或环形弧的直线边。
close_measure (MeasureHandle)   //将图像点转换为世界坐标系统的平面z = 0。
Rows := [RowEdge[0],RowEdge[|RowEdge| - 1]]
Columns := [ColumnEdge[0],ColumnEdge[|RowEdge| - 1]]
//要考虑校准表的厚度,摄像机姿态给出的z值必须根据表格的厚度进行平移。 如果要添加更正,请激活以下行。 
//set_origin_pose(Pose,0,0,0.0045,Pose)将两个边界点转换为世界坐标系。
set_origin_pose (Pose, 0, 0, 0.0045, Pose)
//将两个边界点转换为世界坐标系。
image_points_to_world_plane (CamParam, Pose, Rows, Columns, 'm', SX, SY)
Width := sqrt(pow(SX[0] - SX[1],2) + pow(SY[0] - SY[1],2))
dev_display (Image)
dev_set_line_width (3)
dev_set_draw ('margin')
disp_rectangle2 (WindowHandle, Row, Column, Phi + rad(90), Length1 + 7, 8)
dev_set_color ('red')
dev_set_draw ('fill')
disp_circle (WindowHandle, Rows, Columns, gen_tuple_const(|Rows|,3.5))
dev_set_draw ('margin')
disp_message (WindowHandle, 'Width = ' + (Width * 100)$'8.5f' + 'cm', 'image', 48, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop () 
//现在,测量校准标记的大小。 
// 提取图像中的椭圆。
erosion_circle (RegionFillUp, ROI, 22.5) //侵蚀具有圆形结构元素的区域。
reduce_domain (Image, ROI, ImageReduced) //运算符reduce_domain将给定图像的定义域缩小到指定区域。 
//新定义域的计算方式是旧定义域与区域的交集。 因此,新的定义域可以是该区域的一个子集。 矩阵的大小没有改变。
edges_sub_pix (ImageReduced, Edges, 'canny', 1, 20, 60)  //使用Deriche,Lanser,Shen或Canny滤镜提取子像素精确边缘。
* Fit ellipses to extracted edges to get their axes.
fit_ellipse_contour_xld (Edges, 'fitzgibbon', -1, 2, 0, 200, 3, 2, Row, Column, Phi, Radius1, Radius2, StartPhi, EndPhi, PointOrder)
//使用Deriche,Lanser,Shen或Canny滤镜提取子像素精确边缘。
MeanRadius1 := mean(Radius1)
MeanRadius2 := mean(Radius2)
DevRadius1 := deviation(Radius1)  。
DevRadius2 := deviation(Radius2)
//将椭圆转换为世界坐标,它们应该是圆形,并将圆形从米转换为毫米,以便我们可以看到它们。
contour_to_world_plane_xld (Edges, WorldCircles, CamParam, Pose, 'mm')
* Fit ellipses to the circles in world coordinates to get their axes.
fit_ellipse_contour_xld (WorldCircles, 'fitzgibbon', -1, 2, 0, 200, 3, 2, Row, Column, Phi, RadiusW1, RadiusW2, StartPhi, EndPhi, PointOrder) //近似XLD轮廓由椭圆或椭圆弧组成。
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 (Edges)
dev_set_color ('blue')
disp_message (WindowHandle, 'Image: Mean radii: (' + MeanRadius1$'6.3f' + ',' + MeanRadius2$'6.3f' + ') pixels', 'image', 8, 12, 'black', 'true')
disp_message (WindowHandle, '       Std. dev.:  (' + (DevRadius1 / MeanRadius1 * 100)$'6.3f' + ',' + (DevRadius2 / MeanRadius2 * 100)$'6.3f' + ') %       Std. dev.:  (' + (DevRadius1 / MeanRadius1 * 100)$'6.3f' + ',' + (DevRadius2 / MeanRadius2 * 100)$'6.3f' + ') %', 'image', 30, 12, 'black', 'true')
disp_message (WindowHandle, 'World: Mean radii: (' + (MeanRadiusW1 / 10)$'6.3f' + ',' + (MeanRadiusW2 / 10)$'6.3f' + ') cm', 'image', 52, 12, 'black', 'true')
disp_message (WindowHandle, '       Std. dev.:  (' + (DevRadiusW1 / MeanRadiusW1 * 100)$'6.3f' + ',' + (DevRadiusW2 / MeanRadiusW2 * 100)$'6.3f' + ') %', 'image', 74, 12, 'black', 'true')
* 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324661557&siteId=291194637