【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')

在这里插入图片描述

区域腐蚀

在这里插入图片描述

抠图

在这里插入图片描述

亚像素边缘提取

在这里插入图片描述

轮廓筛选

在这里插入图片描述

测量结果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhy29563

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值