赞
踩
StartCamPar := [0.016,0,0.0000074,0.0000074,326,247,652,494]
set_calib_data_cam_param (CalibDataID, 0, ‘area_scan_division’, StartCamPar)
1.1 相机型号
1.2 参数设置(这里只讲面阵相机)
1.3 畸变类型的选择
1.4 标定时个参数值的确定技巧
Or:
K1, K2, K3,P1, P2:可全部初始化为0
Sx: 由CCD\CMOS确定建议取值如下:
Full image (640480) Subsampling (320240)
1/3"-Chip 0.0000055 m 0.0000110 m
1/2"-Chip 0.0000086 m 0.0000172 m
2/3"-Chip 0.0000110 m 0.0000220 m
Sy: 由CCD\CMOS确定建议取值如下:
for example:
Full image (640480) Subsampling (320240)
1/3"-Chip 0.0000055 m 0.0000110 m
1/2"-Chip 0.0000086 m 0.0000172 m
2/3"-Chip 0.0000110 m 0.0000220 m
Cx and Cy: 光心坐标初始值,建议取值如下:
for example:
Full image (640480) Subsampling (320240)
Cx 320.0 160.0
Cy 240.0 120.0
ImageWidth,ImageHeight:有实际图片大小来初始化该值
for example:
Full image (640480) Subsampling (320240)
ImageWidth 640 320
ImageHeight 480 240
CaltabName := 'caltab_30mm.descr'//标定板描述文件
set_calib_data_calib_object (CalibDataID, 0, CaltabName)
create_calib_data ('calibration_object', 1, 1, CalibDataID)
相机拍摄不同位姿下图片8-15张,拍摄图片时标定板尽量覆盖整个视场(标定板要根据工作距离、视场大小定制);拍摄图片上的圆直径不得小于10个像素
#### 5.加载所有图像,寻找标定板区域,确定圆心,将结果加载到组元中
for I := 1 to NumImages by 1
... acquire image ...(获取图像)
find_caltab (Image, Caltab, CaltabName, SizeGauss, MarkThresh, MinDiamMarks)
find_marks_and_pose (Image, Caltab, CaltabName, StartCamPar, StartThresh, \
DeltaThresh, MinThresh, Alpha, MinContLength, MaxDiamMarks, RCoord, CCoord, StartPose)
// 从标定数据模型中获取基于点的观测数据(49个点的坐标,索引,粗略估计被测校准物体相对于被测相机的姿态)
set_calib_data_observ_points (CalibDataID, 0, 0, I, RCoord, CCoord, 'all', StartPose)
endfor
下面将Halcon中提取目标点的大致原理说一下:
* 返回平均投影误差Errors
calibrate_cameras (CalibDataID, Errors)
本地函数: get_measure_positions
(Image : PlateRegion : CalibDataID, PoseIndex : Distance, Phi, RowCenter, ColumnCenter)
** 提取标定板(二值化、计算连通量、利用形状特征选择区域,填充空洞) * 形状特征有:每个连通区域的孔数;最小包围矩形长度的一半;最小的包围矩形的宽度的一半 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) * ** 从table(标定板表盘)的边框构造测量矩形: * 生成区域XLD轮廓 * 计算XLD轮廓的“回归线”的参数 gen_contour_region_xld (PlateRegion, Contours, 'center') segment_contours_xld (Contours, ContoursSplit, 'lines', 7, 4, 2) regress_contours_xld (ContoursSplit, RegressContours, 'no', 1) * 获取两边的垂直边框线(4选2) 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) * ** 测量线由table的两个垂直边框线的中心点构成: * 从对象数组中的选择对象(2选1) * 获得XLD轮廓所有坐标 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] * ** 现在在图像中进行实际测量: *从标定数据模型中获取基于点的观测数据(第21个点和第28个点的坐标) 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)] * 计算两条直线的交点(边框垂直边和标定板第21个点和第28个点的连接线的角点) * 计算两个点的距离 * 直线的方向 intersection_lines (Row1, Column1, Row2, Column2, RowBegin1, ColBegin1, RowEnd1, ColEnd1, RowA, ColA, IsOverlapping) 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 return ()
主函数 main
* * 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') * * 2.标定相机 * 为一个区域扫描相机生成一个相机参数数组,该参数数组设置为面阵相机的Division畸变模型模板: * CameraParam:[Focus, Kappa, Sx, Sy, Cx, Cy, ImageWidth, ImageHeight] CalTabDescrFile := 'caltab_big.descr' gen_cam_par_area_scan_division (0.008, 0, 0.0000086, 0.0000086, 384, 288, 768, 576, StartCamPar) * 创建haclon 标定数据模型('calibration_object'为标定设置类型,CalibDataID 数据模型的句柄 ) * 在标定数据模型中设置相机的类型和初始参数(StartCamPar 为初始参数) * 定义在标定模型中的标定对象(CalTabDescrFile 描述文件名) create_calib_data ('calibration_object', 1, 1, CalibDataID) set_calib_data_cam_param (CalibDataID, 0, [], StartCamPar) set_calib_data_calib_object (CalibDataID, 0, CalTabDescrFile) * * 3.采图 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') ***** 找到halcon 标定板,并在标定数据模型中设置提取的点和轮廓 ****** find_calib_object (Image, CalibDataID, 0, 0, I - 1, [], []) * 从标定数据模型中查询存储或计算的数据(O号相机数据,项目类型-'init_params'表示初始相机内部参数,StartCamPar 初始化数据) * 从标定数据模型中获取基于点的观测数据(49个点的坐标,索引,粗略估计“被测校准物体(标定板)”相对于被测相机的姿态) * 从校准数据模型中获取基于轮廓的观测数据(标定板轮廓,所观察到的校准对象位姿的索引) get_calib_data (CalibDataID, 'camera', 0, 'init_params', StartCamPar) get_calib_data_observ_points (CalibDataID, 0, 0, I - 1, Row, Column, Index, Pose) 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 () * *** 通过同时最小化处理 确定所有相机参数(Error:优化的反投影均方根误差(RMSE))*** calibrate_cameras (CalibDataID, Error) * 从标定数据模型中查询存储或计算的数据(0号相机的数据,项目类型-'params'表示优化后的相机内部参数,CamParam 输出数据) get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam) * ******** 4.Perform measurements 验证(1D 尺寸测量) ******** * for I := 1 to NumImages by 1 read_image (Image, 'calib/calib-3d-coord-' + I$'02d') * ** 一、现在,测量标定板的黑边的长度: * I-索引号; PlateRegion-标定板区域;Distance-垂直边框的距离; * Phi-公垂线的方向;RowCenter/ColumnCenter-table中心点坐标; * 生成一个矩形的XLD轮廓。 get_measure_positions (Image, PlateRegion, CalibDataID, I, Distance, Phi, RowCenter, ColumnCenter) gen_rectangle2_contour_xld (Rectangle, RowCenter, ColumnCenter, Phi, Distance * 0.52, 8) * ** 二、一维尺寸测量: * 1.设置测量区域:准备提取垂直于矩形的直边(MeasureHandle——测量矩形对象句柄) * 2.找寻你设定检测区域内的边缘:提取垂直于矩形或环形弧的直边 * (Amplitude-指定的是一个缩放,通过边界的坐标加上缩放的计算,可以计算出确切的距离就存在Distance里) * 3.删除一个测量对象 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) close_measure (MeasureHandle) Rows := [RowEdge[0],RowEdge[|RowEdge| - 1]] Columns := [ColumnEdge[0],ColumnEdge[|RowEdge| - 1]] gen_cross_contour_xld (Cross, Rows, Columns, 16, Phi) * ** 三、转换坐标:(相机坐标系->世界坐标系的转化) * 查询标定数据(所有标定对象的总体姿态或特定的标定对象姿态的数据 * 通过选择DataName中的以下参数,您可以查询在由calibrate_cameras执行标定期间, * 哪些标定对象位姿参数得到了(或已经得到了)优化) * 'pose'——优化标定对象位姿,相对于当前参考相机 get_calib_data (CalibDataID, 'calib_obj_pose', [0,I - 1], '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') stop () * ** 五、现在,测量标定标记(标定板上的标定点)的大小 * 提取图像中的椭圆 erosion_circle (PlateRegion, ROI, 17.5) reduce_domain (Image, ROI, ImageReduced) *使用Deriche, Lanser, Shen或Canny过滤器提取亚像素精确的边缘 edges_sub_pix (ImageReduced, Edges, 'canny', 1, 20, 60) select_contours_xld (Edges, SelectedEdges, 'contour_length', 20, 99999999, -0.5, 0.5) * Fit ellipses to extracted edges 将椭圆匹配到提取的边缘 * 由椭圆或椭圆弧构成的近似的XLD轮廓(输出椭圆参数) 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 ellipses to the circles in world coordinates 在世界坐标中将椭圆与圆匹配 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') if (I < 10) disp_continue_message (WindowHandle, 'black', 'true') stop () endif endfor clear_calib_data (CalibDataID)
结果:
1.read_image
2.find_calib_object 填充标定数据模型
3.calibrate_cameras (CalibDataID, Error) 矫正所有相机参数
4.验证相机标定结果:通过 1D mesuring
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。