机器视觉6-halcon高级教程
机器视觉6-halcon高级教程
- 双目立体视觉原理
- 视差
- 外极线几何
- 双目标定
- 双目立体视觉之Halcon标定
- 一.标定结果
- 二.Halcon标定过程
- 1.获取左右相机图像中标定板的区域;
- 2.提取左右相机图像中标定板的MARK点坐标和摄像机外部参数;
- 3.执行双目标定;
- 4.获取非标准外极线几何到标准外极线几何之间的变换矩阵;
- 5.通过变换矩阵对未校正的图像进行图像校正
- 6.显示图像校正后标准外极线几何时的图像.
- 双目立体视觉测量零件的高度
- 1.执行双目标定;
- 2.获取非标准外极线几何到标准外极线几何之间的变换矩阵;
- 3.通过变换矩阵对未校正的图像进行图像校正
- 4.计算左右摄像机的视差图像
- 5.通过视差计算距离图像
- 代码示例
- **1. 初始化设置与窗口管理**
- **2. 图像读取与参数定义**
- **3. 极线校正与图像映射**
- **4. 视差与深度计算**
- **5. 高度测量与结果显示**
- **优化**
双目立体视觉原理
双目立体视觉是一种基于视差原理的三维信息获取技术,通过模拟人类双眼的视觉机制,从不同视角采集图像并计算对应点的位置差异(视差),从而重建目标物体的三维几何信息。其核心流程包括图像采集、相机标定、立体匹配和三维重建,具体原理如下:
双目摄像机如同人的两个眼睛
视差
- 视差与深度关系
双目系统通过两个平行安装的相机(基线距离为 ( b ))同时拍摄同一场景。同一空间点 ( P ) 在左右图像中的水平像素坐标差称为视差 ( d ),深度 ( Z ) 可通过三角测量公式计算:
Z = b ⋅ f d Z = \frac{b \cdot f}{d} Z=db⋅f
其中 ( f ) 为相机焦距。视差越大,物体距离越近;视差趋近于0时,物体接近无限远。
坐标系以左相机为准,右相机相对于左相机是简单的平移,用坐标表示为(Tx,0,0
2. 极线约束与校正
为简化匹配过程,需对图像进行极线校正,使对应点在左右图像中位于同一水平线上。这通过标定相机内外参数并消除畸变实现,确保匹配搜索仅需在水平方向进行,显著降低计算复杂度。
视差公式
外极线几何
非标准外极线几何图
1.极平面
⒉极线
3.极点
4.极线约束
双目标定
双目标定技术获取非标准外极线几何到标准外极线几何的变换矩阵,校正两个相机的图像。根据两个相机的相对位姿,从而在标准外极线几何图像中获取物体在另一个相机成像中位置。
一、双目标定的定义与目的
双目标定是双目视觉系统的核心步骤,旨在确定双目相机的内参(焦距、主点、畸变系数)和外参(两相机间的旋转矩阵 ( R ) 和平移向量 ( T )),从而建立三维空间与二维图像之间的映射关系。其核心目标包括:
- 消除畸变:校正镜头畸变(径向畸变、切向畸变)对成像的影响。
- 坐标系对齐:通过外参矩阵实现左右相机坐标系的统一,便于后续立体匹配和三维重建。
二、双目标定流程
-
标定板准备
• 使用棋盘格标定板(如8×5黑白格),需保证打印精度高、表面平整且无反光,方格尺寸根据相机视场选择(短焦相机建议20mm,长焦相机建议60mm)。• 标定板应覆盖图像1/4至1/2区域,且在不同角度(俯仰、倾斜、平移)下拍摄15-60组图像以覆盖全视场。
-
图像采集与角点提取
• 左右相机同步拍摄标定板图像,确保标定板完整且无模糊。常用工具包括OpenCV或MATLAB脚本自动保存图像。• 使用Canny算子检测边缘,结合Zernike矩亚像素提取或椭圆拟合获取角点坐标,精度可达0.1像素。
-
单应性矩阵计算
• 通过针孔模型建立世界坐标系与图像坐标系的线性关系,求解单应性矩阵 ( H ) 描述平面投影变换。• 公式:( s \cdot [u \quad v \quad 1]^T = H \cdot [X \quad Y \quad 1]^T ),其中 ( s ) 为比例因子,( H ) 包含内参和外参信息。
-
参数优化
• 传统方法:基于最小二乘法或奇异值分解(SVD)求解初始参数,再通过Levenberg-Marquardt算法优化。• 智能优化算法:如混沌粒子群优化(CPSO),引入动态惯性权重和邻域混沌搜索,避免局部最优,提升标定精度。
-
立体校正
• 使用Bouguet算法将左右图像投影到同一极平面,使极线水平对齐,简化立体匹配计算。• 变换矩阵 ( R_{rect} ) 构造方式:基于平移向量 ( T ) 方向,使基线与成像平面平行。
三、关键技术解析
-
内参标定
• 焦距 ( f ):通过棋盘格角点计算归一化焦距 ( f_x, f_y ) 及主点 ( (c_x, c_y) )。• 畸变校正:二阶径向畸变(( k_1, k_2 ))和切向畸变(( p_1, p_2 ))模型,公式:
x c o r r e c t e d = x ( 1 + k 1 r 2 + k 2 r 4 ) + 2 p 1 x y + p 2 ( r 2 + 2 x 2 ) x_{corrected} = x(1 + k_1 r^2 + k_2 r^4) + 2p_1 xy + p_2 (r^2 + 2x^2) xcorrected=x(1+k1r2+k2r4)+2p1xy+p2(r2+2x2)
y c o r r e c t e d = y ( 1 + k 1 r 2 + k 2 r 4 ) + p 1 ( r 2 + 2 y 2 ) + 2 p 2 x y y_{corrected} = y(1 + k_1 r^2 + k_2 r^4) + p_1 (r^2 + 2y^2) + 2p_2 xy ycorrected=y(1+k1r2+k2r4)+p1(r2+2y2)+2p2xy
其中 r 2 = x 2 + y 2 r^2 = x^2 + y^2 r2=x2+y2 。
-
外参标定
• 旋转矩阵 ( R ):分解为绕X/Y/Z轴旋转角度 α , β , γ \alpha, \beta, \gamma α,β,γ,通过欧拉角或四元数表示。• 平移向量 ( T ):描述右相机相对于左相机的空间位移,基线长度 b = ∥ T ∥ b = \| T \| b=∥T∥ 直接影响深度分辨率。
-
标定工具与算法
• MATLAB工具箱:stereoCameraCalibrator
支持自动角点检测、参数优化及重投影误差分析。• OpenCV函数:
cv2.stereoCalibrate()
结合张正友平面标定法,适用于实时系统开发。
四、应用场景与优化建议
-
典型应用
• 机器人导航:结合SLAM技术实现环境三维建模与避障。• 工业检测:高精度测量零件尺寸(误差<0.1mm)。
• 自动驾驶:通过视差计算障碍物距离,支持路径规划。
-
优化建议
• 标定板多样性:使用多尺寸标定板适应不同工作距离。• 光照控制:均匀照明避免反光或阴影干扰角点检测。
• 动态标定:在相机移动或变焦后需重新标定。
五、常见问题与解决方案
-
重投影误差过大
• 原因:角点提取不准确或标定板姿态单一。• 解决:增加标定图像数量(建议≥20组),覆盖更多视角。
-
极线未对齐
• 原因:外参矩阵 ( R, T ) 计算误差。• 解决:使用Bouguet校正法强制极线水平化。
-
镜头畸变残留
• 原因:畸变模型阶数不足(如仅使用一阶径向畸变)。• 解决:扩展至二阶径向+切向畸变模型。
总结
双目标定是双目视觉系统的基石,其精度直接影响三维重建与测距的可靠性。通过合理设计标定流程、选择优化算法并严格把控拍摄条件,可实现亚毫米级标定精度。未来,结合深度学习的自标定方法有望进一步简化流程并提升鲁棒性。
双目立体视觉之Halcon标定
一.标定结果
二.Halcon标定过程
1.获取左右相机图像中标定板的区域;
find_caltab(Image : CalPlate : CalPlateDescr, SizeGauss, MarkThresh, MinDiamMarks :)
参数含义:
Image : 输入图像
CalPlate : 标定板区域
CalPlateDescr: 标定板描述文件
SizeGauss: 高斯滤波核;
MarkThresh, 提取mark的阈值
MinDiamMarks : 标定板中MARK圆的最小半径
2.提取左右相机图像中标定板的MARK点坐标和摄像机外部参数;
find_marks_and_pose(Image, CalPlateRegion : : CalPlateDescr, StartCamParam, StartThresh, DeltaThresh, MinThresh,Alpha, MinContLength, MaxDiamMarks : RCoord, CCoord, StartPose)
参数含义:
Image: 输入图像
CalPlateRegion: 标定板区域
CalPlateDescr: 标定板描述文件
StartCamParam: 摄像机内部参数
DeltaThresh: 提取MARK黑点所需的初始阈值
MinThresh: 提取MARK黑点步进阈值
Alpha: 提取MARK黑点轮廓的滤波参数
MinContLength: MARK黑点轮廓的最小长度
MaxDiamMarks: MARK黑点轮廓的最大直径
RCoord: 探测到MARK黑点的行坐标
CCoord: 探测到MARK黑点的列坐标
StartPose 输出摄像机外部参数
3.执行双目标定;
binocular_calibration( : : NX, NY, NZ, NRow1, NCol1, NRow2, NCol2, StartCamParam1, StartCamParam2, NStartPose1,NStartPose2, EstimateParams : CamParam1, CamParam2, NFinalPose1, NFinalPose2, RelPose, Errors)
参数含义:
NX: 标定板MARK点行坐标(经过排序的,单位是米)
NY: 标定板MARK点列坐标(经过排序的,单位是米)
NZ: 标定板MARK点Z坐标(经过排序的,单位是米)
NRow1: 左面相机中标定板提取出的MARK点行坐标(经过排序的,单位是像素)
NCol1: 左面相机中标定板提取出的MARK点列坐标(经过排序的,单位是像素)
NRow2: 右面相机中标定板提取出的MARK点行坐标(经过排序的,单位是像素)
NCol2: 右面相机中标定板提取出的MARK点列坐标(经过排序的,单位是像素)
StartCamParam1:左面相机的摄像机内部参数
StartCamParam2:右面相机的摄像机内部参数
NStartPose1: 左面相机的摄像机外部参数
NStartPose2: 右面相机的摄像机外部参数
EstimateParams: 选择要标定出哪些相机参数,”all”代表所有的参数
CamParam1: 标定后得到的左面相机的摄像机内部参数
CamParam2: 标定后得到的右面相机的摄像机内部参数
NFinalPose1: 标定后得到的左面相机的摄像机外部参数
NFinalPose2: 标定后得到的右面相机的摄像机外部参数
RelPose: 右边相机相对于左面相机的位姿
Errors 平均错误误差
4.获取非标准外极线几何到标准外极线几何之间的变换矩阵;
gen_binocular_rectification_map( : Map1, Map2 : CamParam1, CamParam2, RelPose, SubSampling, Method, MapType :CamParamRect1, CamParamRect2, CamPoseRect1, CamPoseRect2, RelPoseRect)
参数含义:
Map1:左面相机校正映射数据
Map2:右面相机校正映射数据
CamParam1:左面相机的摄像机内部参数
CamParam2:右面相机的摄像机内部参数
RelPose: 右相机相对左相机的位姿
SubSampling:采样因子
Method: 映射校正方法
MapType: 映射校正类型
CamParamRect1: 左面相机校正以后的摄像机内部参数
CamParamRect2: 右面相机校正以后的摄像机内部参数
CamPoseRect1: 校正以后的左面相机相对原始相机的位姿
CamPoseRect2:校正以后的右面相机相对原始相机的位姿
RelPoseRect:校正以后的右面相机相对校正以后的左面相机的位姿关系
5.通过变换矩阵对未校正的图像进行图像校正
map_image(Image, Map : ImageMapped : : )
参数含义:
Image: 待校正图像
Map: 相机校正映射数据
ImageMapped: 校正后的图像
6.显示图像校正后标准外极线几何时的图像.
check_epipolar_constraint(ImageRectifiedL, ImageRectifiedR : : RectCamParL, RectCamParR, WindowHandle1, WindowHandle2, CaltabFile :EpipolarError)
参数含义:
ImageRectifiedL:左面相机校正以后的图像
ImageRectifiedR:右面相机校正以后的图像
RectCamParL:左面相机校正以后的摄像机内部参数
RectCamParR:右面相机校正以后的摄像机内部参数
WindowHandle1:左面摄像机图像窗口
WindowHandle2:右面摄像机图像窗口
CaltabFile:标定板文件
EpipolarError:错误信息
*设置离线图像存放的路径
ImgPath := 'stereo/board/'Index := 1
*读取左边相机离线图像
read_image (ImageL, ImgPath + 'calib_l_' + Index$'02d')*读取右边相机离线图像
read_image (ImageR, ImgPath + 'calib_r_' + Index$'02d')*关闭已经打开的窗口
dev_close_window ()*关闭程序计数器,变量更新,图像更新窗口
dev_update_off ()*获取左边相机图像大小
get_image_size (ImageL, WidthL, HeightL)*创建左边的窗口
dev_open_window (0, 0, WidthL, HeightL, 'black', WindowHandle1)*设置区域填充模式为边缘模式
dev_set_draw ('margin')*设置输出对象的颜色为绿色
dev_set_color ('green')*设置字体信息
set_display_font (WindowHandle1, 14, 'mono', 'true', 'false')*获取右边相机图像大小
get_image_size (ImageR, WidthR, HeightR)*创建右边的窗口
dev_open_window (0, WidthL + 12, WidthL, HeightL, 'black', WindowHandle2)*设置区域填充模式为边缘模式
dev_set_draw ('margin')*设置输出对象的颜色为绿色
dev_set_color ('green')* 校正文件
CaltabFile := 'caltab_30mm.descr'*获取标定板中所有mark点的中心坐标
caltab_points (CaltabFile, X, Y, Z)* 设置左右两个相机的摄像机内部参数[Focus,Kappa,Sx,Sy,Cx,Cy,Whith,Height]
StartCamParL := [0.0125,0,1.48e-5,1.48e-5,WidthL / 2.0,HeightL / 2.0,WidthL,HeightL]
StartCamParR := StartCamParL
* Parameter settings for find_caltab and find_marks_and_pose
SizeGauss := 3
MarkThresh := 120
MinDiamMarks := 5
StartThresh := 128
DeltaThresh := 10
MinThresh := 18
Alpha := 0.9
MinContLength := 15
MaxDiamMarks := 100
* Create the tuples in which the image coordinates of the
* calibration marks and the initial poses will be accumulated
RowsL := []
ColsL := []
StartPosesL := []
RowsR := []
ColsR := []
StartPosesR := []
* Start the loop over the calibration images
for Index := 1 to 15 by 1* 读取左面相机拍照的标定板图像read_image (ImageL, ImgPath + 'calib_l_' + Index$'02d')* 读取右面相机拍照的标定板图像read_image (ImageR, ImgPath + 'calib_r_' + Index$'02d')* 分割左面相机拍照的标定板图像标定板区域find_caltab (ImageL, CaltabL, CaltabFile, SizeGauss, MarkThresh, MinDiamMarks)* 分割右面相机拍照的标定板图像标定板区域find_caltab (ImageR, CaltabR, CaltabFile, SizeGauss, MarkThresh, MinDiamMarks)*激活左面的窗口dev_set_window (WindowHandle1)*显示左面相机拍照的标定板图像dev_display (ImageL)*显示左面相机拍照的标定板图像标定板区域dev_display (CaltabL)*激活右面的窗口dev_set_window (WindowHandle2)*显示右面相机拍照的标定板图像dev_display (ImageR)*显示右面相机拍照的标定板图像标定板区域dev_display (CaltabR)*提取左面相机拍照的标定板中MARK点坐标和摄像机外部参数find_marks_and_pose (ImageL, CaltabL, CaltabFile, StartCamParL, StartThresh, DeltaThresh, MinThresh, Alpha, MinContLength, MaxDiamMarks, RCoordL, CCoordL, StartPoseL)*显示左面图像中标定板三维模型disp_caltab (WindowHandle1, CaltabFile, StartCamParL, StartPoseL, 1)*提取右面相机拍照的标定板中MARK点坐标和摄像机外部参数find_marks_and_pose (ImageR, CaltabR, CaltabFile, StartCamParR, StartThresh, DeltaThresh, MinThresh, Alpha, MinContLength, MaxDiamMarks, RCoordR, CCoordR, StartPoseR)*显示右面图像中标定板三维模型disp_caltab (WindowHandle2, CaltabFile, StartCamParR, StartPoseR, 1)*将17张左面相机拍照图像的MARK点行坐标连接起来RowsL := [RowsL,RCoordL]*将17张左面相机拍照图像的MARK点列坐标连接起来ColsL := [ColsL,CCoordL]*将左面相机的摄像机外部参数连接起来StartPosesL := [StartPosesL,StartPoseL]*将17张右面相机拍照图像的MARK点行坐标连接起来RowsR := [RowsR,RCoordR]*将17张右面相机拍照图像的MARK点列坐标连接起来ColsR := [ColsR,CCoordR]*将右面相机的摄像机外部参数连接起来StartPosesR := [StartPosesR,StartPoseR]
endfor* 执行双目标定
binocular_calibration (X, Y, Z, RowsL, ColsL, RowsR, ColsR, StartCamParL, StartCamParR, StartPosesL, StartPosesR, 'all', CamParamL, CamParamR, NFinalPoseL, NFinalPoseR, cLPcR, Errors)
* If required, save the results to disk:
* write_cam_par (CamParamL, 'cam_left-125.dat')
* write_cam_par (CamParamR, 'cam_right-125.dat')
* write_pose (cLPcR, 'pos_right2left.dat')* 获取非标准外极线几何到标准外极线几何之间的变换关系
gen_binocular_rectification_map (MapL, MapR, CamParamL, CamParamR, cLPcR, 1, 'geometric', 'bilinear', RectCamParL, RectCamParR, CamPoseRectL, CamPoseRectR, RectLPosRectR)*读取左相机拍照的一张图
read_image (ImageL, ImgPath + 'calib_l_01')*读取右相机拍照的一张图
read_image (ImageR, ImgPath + 'calib_r_01')*根据上述变换关系,对左相机拍照图进行校正
map_image (ImageL, MapL, ImageRectifiedL)*根据上述变换关系,对右相机拍照图进行校正
map_image (ImageR, MapR, ImageRectifiedR)*显示最后的双目标定结果,得到标准外极线几何时的图像.
check_epipolar_constraint (ImageRectifiedL, ImageRectifiedR, RectCamParL, RectCamParR, WindowHandle1, WindowHandle2, CaltabFile, EpipolarError)
以下是针对提供的HALCON双目相机标定与校正代码的逐步解释和优化建议:
逐步解释
-
初始化设置:
• 定义图像路径ImgPath
,初始化索引Index
。• 读取左右相机的第一对标定板图像(可能用于测试,后续循环处理所有图像)。
-
窗口管理:
• 关闭已有窗口,禁用自动更新以提高性能。• 根据左图像尺寸创建左窗口,设置绘图参数(边缘模式、颜色、字体)。
• 创建右窗口,位置在左窗口右侧,使用左图像尺寸(假设左右图像尺寸相同)。
-
标定板参数:
• 加载标定板描述文件caltab_30mm.descr
,获取标定板点的世界坐标(X, Y, Z)
。• 初始化左右相机的内部参数(焦距、畸变、像素尺寸、中心点等)。
-
参数配置:
• 设置find_caltab
和find_marks_and_pose
的参数(高斯滤波、阈值、标记尺寸等)。• 初始化数组存储左右相机的图像坐标和初始位姿。
-
循环处理标定图像:
• 遍历15对图像,逐对处理:◦ 读取左右图像,检测标定板区域
CaltabL/R
并显示。◦ 提取标记点坐标
(RCoordL/R, CCoordL/R)
和初始位姿StartPoseL/R
。◦ 显示标定板3D模型,收集坐标和位姿数据。
-
双目标定:
• 使用binocular_calibration
优化相机参数和相对位姿,输出最终参数CamParamL/R
和cLPcR
。 -
生成校正映射:
• 调用gen_binocular_rectification_map
生成校正映射MapL/R
,将图像校正为标准极线几何。 -
验证校正结果:
• 读取并校正一对图像,使用check_epipolar_constraint
检查极线误差,验证校正效果。
优化建议
-
窗口尺寸适配:
* 获取右图像实际尺寸 get_image_size (ImageR, WidthR, HeightR) * 创建右窗口时使用实际尺寸 dev_open_window (0, WidthL + 12, WidthR, HeightR, 'black', WindowHandle2)
确保右窗口尺寸与右图像匹配,避免显示不全。
-
错误处理:
tryfind_caltab (ImageL, CaltabL, CaltabFile, SizeGauss, MarkThresh, MinDiamMarks) catch (Exception)* 处理异常,如打印错误信息并跳出循环dev_disp_text ('标定板检测失败: ' + Exception, 'window', WindowHandle1, 'left', 'red', 'box')break endtry
添加异常捕获,增强鲁棒性。
-
字符串格式化修正:
* 使用正确的格式化语法 IndexStr := Index$'02d' read_image (ImageL, ImgPath + 'calib_l_' + IndexStr)
确保文件名正确生成,避免因格式错误导致读取失败。
-
参数保存:
* 保存标定结果 write_cam_par (CamParamL, 'cam_left_final.dat') write_cam_par (CamParamR, 'cam_right_final.dat') write_pose (cLPcR, 'stereo_pose.dat') * 保存校正映射 write_map (MapL, 'map_left.bin') write_map (MapR, 'map_right.bin')
便于后续应用,无需重复标定。
-
循环结构优化:
for Index := 1 to 15 by 1* 统一处理左右图像process_stereo_pair (Index, ImgPath, WindowHandle1, WindowHandle2, ...) endfor
封装重复操作为函数,提升代码可读性和维护性。
-
动态参数调整:
• 可交互式调整MarkThresh
等参数,或通过循环寻找最佳参数组合,确保标定板检测稳定。 -
可视化增强:
* 在显示校正结果时叠加极线 disp_epipolar_line (ImageRectifiedL, ImageRectifiedR, RectCamParL, RectCamParR, WindowHandle1, WindowHandle2)
直观展示极线对齐效果。
修正后的关键代码片段
* 创建右窗口时使用右图像尺寸
get_image_size (ImageR, WidthR, HeightR)
dev_open_window (0, WidthL + 12, WidthR, HeightR, 'black', WindowHandle2)* 循环处理中添加错误处理
for Index := 1 to 15 by 1tryread_image (ImageL, ImgPath + 'calib_l_' + Index$'02d')read_image (ImageR, ImgPath + 'calib_r_' + Index$'02d')* 检测标定板find_caltab (ImageL, CaltabL, CaltabFile, SizeGauss, MarkThresh, MinDiamMarks)find_caltab (ImageR, CaltabR, CaltabFile, SizeGauss, MarkThresh, MinDiamMarks)* 提取标记点及位姿find_marks_and_pose (...)* 收集数据...catch (Exception)dev_clear_window ()dev_disp_text ('错误: ' + Exception, 'window', WindowHandle1, 'left', 'red', 'box')breakendtry
endfor* 标定后保存参数
write_cam_par (CamParamL, 'cam_left_final.dat')
write_cam_par (CamParamR, 'cam_right_final.dat')
write_pose (cLPcR, 'stereo_pose.dat')
总结
通过修正窗口尺寸、增强错误处理、优化参数保存及代码结构,提升了程序的稳健性和实用性。确保实际应用中左右相机图像尺寸一致或正确适配,参数文件路径正确,并根据实际标定场景调整检测参数,以获得最佳标定效果。
双目立体视觉测量零件的高度
高度测量步骤:
1.执行双目标定;
binocular_calibration( : : NX, NY, NZ, NRow1, NCol1, NRow2, NCol2, StartCamParam1, StartCamParam2, NStartPose1,NStartPose2, EstimateParams : CamParam1, CamParam2, NFinalPose1, NFinalPose2, RelPose, Errors)
参数含义:
NX: 标定板MARK点行坐标(经过排序的,单位是米)
NY: 标定板MARK点列坐标(经过排序的,单位是米)
NZ: 标定板MARK点Z坐标(经过排序的,单位是米)
NRow1: 左面相机中标定板提取出的MARK点行坐标(经过排序的,单位是像素)
NCol1: 左面相机中标定板提取出的MARK点列坐标(经过排序的,单位是像素)
NRow2: 右面相机中标定板提取出的MARK点行坐标(经过排序的,单位是像素)
NCol2: 右面相机中标定板提取出的MARK点列坐标(经过排序的,单位是像素)
StartCamParam1:左面相机的摄像机内部参数
StartCamParam2:右面相机的摄像机内部参数
NStartPose1: 左面相机的摄像机外部参数
NStartPose2: 右面相机的摄像机外部参数
EstimateParams: 选择要标定出哪些相机参数,”all”代表所有的参数
CamParam1: 标定后得到的左面相机的摄像机内部参数
CamParam2: 标定后得到的右面相机的摄像机内部参数
NFinalPose1: 标定后得到的左面相机的摄像机外部参数
NFinalPose2: 标定后得到的右面相机的摄像机外部参数
RelPose: 右边相机相对于左面相机的位姿
Errors 平均错误误差
2.获取非标准外极线几何到标准外极线几何之间的变换矩阵;
gen_binocular_rectification_map( : Map1, Map2 : CamParam1, CamParam2, RelPose, SubSampling, Method, MapType :CamParamRect1, CamParamRect2, CamPoseRect1, CamPoseRect2, RelPoseRect)
参数含义:
Map1:左面相机校正映射数据
Map2:右面相机校正映射数据
CamParam1:左面相机的摄像机内部参数
CamParam2:右面相机的摄像机内部参数
RelPose: 右相机相对左相机的位姿
SubSampling:采样因子
Method: 映射校正方法
MapType: 映射校正类型
CamParamRect1: 左面相机校正以后的摄像机内部参数
CamParamRect2: 右面相机校正以后的摄像机内部参数
CamPoseRect1: 校正以后的左面相机相对原始相机的位姿
CamPoseRect2:校正以后的右面相机相对原始相机的位姿
RelPoseRect:校正以后的右面相机相对校正以后的左面相机的位姿关系
3.通过变换矩阵对未校正的图像进行图像校正
map_image(Image, Map : ImageMapped : : )
参数含义:
Image: 待校正图像
Map: 相机校正映射数据
ImageMapped: 校正后的图像
4.计算左右摄像机的视差图像
binocular_disparity(ImageRect1, ImageRect2 : Disparity, Score : Method, MaskWidth, MaskHeight, TextureThresh,MinDisparity, MaxDisparity, NumLevels, ScoreThresh, Filter, SubDisparity:)
参数含义:
ImageRect1:左边相机校正后的图像
ImageRect2:右边相机校正后的图像
Disparity:视差映射图
Score:视差值得匹配分数
Method:匹配方法
MaskWidth:校正窗口的宽度
MaskHeight:校正窗口的高度
TextureThresh:匹配需要的阈值
MinDisparity:视差的最小值
MaxDisparity:视差的最大值
NumLevels:金字塔层级
ScoreThresh:相关函数的最小分值,保证匹配质量
Filter:增加匹配的鲁棒性
SubDisparity :视差图是否采用亚像素
5.通过视差计算距离图像
binocular_distance_mg(ImageRect1, ImageRect2 : Distance, Score : CamParamRect1, CamParamRect2, RelPoseRect,GrayConstancy, GradientConstancy, Smoothness, InitialGuess, CalculateScore, MGParamName, MGParamValue : )
参数含义:
ImageRect1:左边相机校正后的图像
ImageRect2:右边相机校正后的图像
Distance:距离图像
Score:视差值得匹配分数
CamParamRect1:左边相机校正后的摄像机内部参数
CamParamRect2:右边相机校正后的摄像机内部参数
RelPoseRect:校正后的右相机相对左相机的位姿
GrayConstancy:距离图像中灰度值的权重
GradientConstancy:距离图像中梯度的权重
Smoothness:图像滤波权重
InitialGuess:初始的视差
CalculateScore:匹配分数
MGParamName:多重网格算法
MGParamValue :
//多重网格法:求解偏微分问题离散方程的一种快速迭代方法
代码示例
*关闭图像窗口更新
dev_update_window ('off')*关闭变量更新
dev_update_var ('off')*关闭程序计数器更新
dev_update_pc ('off')*关闭窗口
dev_close_window ()*打开新窗口
dev_open_window (0, 0, 672, 484, 'black', WindowHandle)*设置字体显示信息
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')*读取左面相机采集的图像
read_image (ImageL, 'stereo/board/board_l_01')*读取右面相机采集的图像
read_image (ImageR, 'stereo/board/board_r_01')*获取图像的大小
get_image_size (ImageR, Width, Height)*根据双目立体视觉标定获取到左右相机的摄像机内部参数和右相机相对左相机的位姿
*左相机的摄像机内部参数
CamParamL := [0.0130507774353,-665.817817207,1.4803417027e-5,1.48e-5,155.89225769,126.70664978,320,240]
*右相机的摄像机内部参数
CamParamR := [0.0131776504517,-731.860636733,1.47997569293e-5,1.48e-5,162.98210144,119.301040649,320,240]
*右相机相对左相机的位姿
RelPose := [0.153573364258,-0.00373362231255,0.0447351264954,0.174289124775,319.843388114,359.894955219,0]*获取非标准外极限图像和标准外极限图像之间的变换矩阵(映射图像)
gen_binocular_rectification_map (MapL, MapR, CamParamL, CamParamR, RelPose, 1, 'geometric', 'bilinear', RectCamParL, RectCamParR, CamPoseRectL, CamPoseRectR, RectLPosRectR)*根据变换矩阵对左边相机进行图像校正
map_image (ImageL, MapL, ImageRectifiedL)*根据变换矩阵对右边相机进行图像校正
map_image (ImageR, MapR, ImageRectifiedR)binocular_disparity (ImageRectifiedL, ImageRectifiedR, Disparity, Score1, 'ncc', 17, 17, 5, 0, 60, 1, 0.1, 'none', 'none')
*根据左右相机的校正图像计算深度信息
binocular_distance_mg (ImageRectifiedL, ImageRectifiedR, Distance, Score, RectCamParL, RectCamParR, RectLPosRectR, 1, 10, 5, 0, 'false', 'default_parameters', 'accurate')*清除窗口内容
dev_clear_window ()*显示距离图像
dev_display (Distance)*计算IC的高度
gen_rectangle2 (IC, 107.276, 62.0363, rad(-25.6343), 7.64174, 6.41978)
gen_rectangle2 (PCB, 101.986, 145.771, rad(4.75463), 7.97698, 6.76498)
get_grayval (Distance, 107.276, 62.0363, IC_Grayval)
get_grayval (Distance, 101.986, 145.771, PCB_Grayval)
IC_Height:=(PCB_Grayval-IC_Grayval)*100*显示结果
dev_display (ImageRectifiedL)
set_tposition (WindowHandle, 103, 54)
write_string (WindowHandle, 'IC零件的高度是:'+IC_Height+'cm')
1. 初始化设置与窗口管理
* 关闭窗口更新、变量更新、程序计数器更新
dev_update_window ('off')
dev_update_var ('off')
dev_update_pc ('off')
* 关闭所有窗口并打开新窗口
dev_close_window ()
dev_open_window (0, 0, 672, 484, 'black', WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
• 功能:
关闭自动更新以提高性能,创建新窗口并设置字体。
• 关键点:
• dev_update_off
系列命令用于禁用HDevelop的自动刷新,减少资源占用。
• dev_open_window
参数依次为窗口左上角坐标、宽度、高度、背景颜色和窗口句柄。
2. 图像读取与参数定义
* 读取左右相机图像
read_image (ImageL, 'stereo/board/board_l_01')
read_image (ImageR, 'stereo/board/board_r_01')
get_image_size (ImageR, Width, Height)* 定义相机参数和相对位姿
CamParamL := [0.01305..., ...] ; 左相机内参
CamParamR := [0.01317..., ...] ; 右相机内参
RelPose := [0.15357..., ...] ; 右相机相对于左相机的位姿
• 参数解析:
• 内参:[Focus, Kappa, Sx, Sy, Cx, Cy, Width, Height]
◦ `Focus`:焦距(单位:米),远心镜头设为0。 ◦ `Kappa`:畸变系数,通常初始化为0(Division模型)。 ◦ 问题:用户代码中`Kappa`值异常(如-665),需检查是否误用参数。
• 位姿:[Tx, Ty, Tz, RotX, RotY, RotZ, Angle]
(轴角表示法)。
◦ 需验证`RelPose`是否为标定输出的正确格式(单位是否为弧度)。
3. 极线校正与图像映射
* 生成校正映射并校正图像
gen_binocular_rectification_map (MapL, MapR, CamParamL, CamParamR, RelPose, ...)
map_image (ImageL, MapL, ImageRectifiedL)
map_image (ImageR, MapR, ImageRectifiedR)
• 功能:
将原始图像投影到公共平面,消除极线倾斜,使匹配点位于同一行。
• 参数说明:
• gen_binocular_rectification_map
:输入内参、相对位姿,输出映射表MapL/R
和校正后参数。
• map_image
:根据映射表对图像进行几何变换。
4. 视差与深度计算
* 计算视差图
binocular_disparity (ImageRectifiedL, ImageRectifiedR, Disparity, ..., 'ncc', 17, 17, ...)
* 计算深度图
binocular_distance_mg (..., Distance, ...)
• 算法细节:
• 视差计算:使用归一化互相关(NCC)方法,窗口大小17x17,适用于纹理丰富场景,但可能降低实时性。
• 深度转换:基于视差图与校正参数,通过三角测量生成三维距离图。
5. 高度测量与结果显示
* 在距离图上定义IC和PCB区域
gen_rectangle2 (IC, 107.276, 62.0363, rad(-25.6343), 7.64174, 6.41978)
gen_rectangle2 (PCB, 101.986, 145.771, rad(4.75463), 7.97698, 6.76498)
* 获取灰度值计算高度差
get_grayval (Distance, IC_Grayval, PCB_Grayval)
IC_Height := (PCB_Grayval - IC_Grayval) * 100
* 显示结果
dev_display (ImageRectifiedL)
write_string (WindowHandle, 'IC高度: ' + IC_Height + 'cm')
• 关键点:
• get_grayval
:假设Distance
图像的像素值表示实际距离(单位:米/毫米),需确认单位一致性。
• 问题:rad()
函数在HALCON中需替换为tuple_rad
或直接输入弧度值,否则可能报错。
• 结果需格式化输出,如IC_Height$'.2f'
,避免字符串拼接错误。
优化
-
参数验证:
• 检查CamParamL/R
中的畸变系数Kappa
是否合理(通常接近0)。• 确认
RelPose
的旋转参数单位是否为弧度。 -
性能优化:
• 缩小视差计算窗口(如9x9)以提升速度。 -
异常处理:
• 添加try-catch
块捕获read_image
或标定步骤的异常。 -
单位与显示:
• 明确Distance
的单位,调整高度计算系数(如毫米则无需*100
)。
相关文章:

机器视觉6-halcon高级教程
机器视觉6-halcon高级教程 双目立体视觉原理视差外极线几何双目标定 双目立体视觉之Halcon标定一.标定结果二.Halcon标定过程1.获取左右相机图像中标定板的区域;2.提取左右相机图像中标定板的MARK点坐标和摄像机外部参数;3.执行双目标定;4.获取非标准外极线几何到标…...

YOLOv8 的双 Backbone 架构:解锁目标检测新性能
一、开篇:为何踏上双 Backbone 探索之路 在目标检测的领域中,YOLOv8 凭借其高效与精准脱颖而出,成为众多开发者和研究者的得力工具。然而,传统的单 Backbone 架构,尽管已经在诸多场景中表现出色,但仍存在一…...

1.4 TypeScript 编译是如何工作的?
TypeScript 是 JavaScript 的超集,最显著的优势是引入了静态类型检查。它能帮助开发者在编写代码阶段捕获错误,从而提升代码的健壮性和可维护性。虽然 TypeScript 本身不能直接在浏览器或 Node.js 中运行,但它可以被编译成标准的 JavaScript&…...
【HTML-4】HTML段落标签:构建内容结构的基础
在网页开发中,段落标签<p>是最基础也是最重要的HTML元素之一。这篇博客将深入探讨段落标签的用法、最佳实践以及相关技术细节。 1. 段落标签的基本用法 HTML段落标签用于定义文本段落,浏览器会自动在段落前后添加一定的空白(margin&a…...
国际前沿知识系列五:时间序列建模方法在头部撞击运动学测量数据降噪中的应用
目录 国际前沿知识系列五:时间序列建模方法在头部撞击运动学测量数据降噪中的应用 一、引言 二、时间序列建模方法 (一)ARIMA 模型 (二)指数平滑法 (三)小波变换 三、实际案例分析 &…...
未授权访问漏洞利用链实战总结
一、渗透测试核心思路 攻击链路径: 未授权访问 → 接口信息泄露 → 敏感数据获取 → 账户爆破 → 权限提升 → 系统控制 二、关键步骤拆解与分析 信息收集阶段 初始突破口: 系统登录页看似无效,但通过JS文件分析发现隐藏接口(如 …...
Centos上搭建 OpenResty
一、OpenResty简介 OpenResty 是基于 Nginx 的扩展平台,完全兼容 Nginx 的核心功能(如 HTTP 服务和反向代理),同时通过内嵌 LuaJIT 支持,允许开发者用 Lua 脚本灵活扩展业务逻辑。它简化了动态逻辑的实现。 二、安装…...

Web 服务、 Nfs 服务器以及 Dns 服务器综合实验
要求: 1.web 服务的资源文件通过 nfs 服务器共享 www.luntan.com 2.确保所有主机时间同步 3.定义本地 dns 服务器解析 web 主机域名 实验: 主机服务程序192.168.96.142dns、nfs192.168.96.132web 服务器说明: 设备 IP服务端 192…...
保证数据库 + redis在读写分离场景中事务的一致性
在 Spring Boot 中实现数据库与 Redis 的一致性,特别是处理读写分离时,确保数据修改的事务一致性是一个常见的挑战。因为 Redis 是一个内存数据库,通常用于缓存,而关系型数据库是持久化存储,两者之间的数据同步和一致性…...

汇编语言的子程序魔法:解锁四则运算的奥秘
在嵌入式系统的世界里,汇编语言就像是魔法师手中的魔杖,能够直接操控硬件,实现各种神奇的功能。今天,我将带你走进一场充满乐趣的实验:如何用汇编语言实现四则运算,并将它们封装成子程序。这不仅是一次技术…...

快速解决Linux 中yum镜像拉取失败问题
在linux中使用yum命令拉取镜像的时候,如果出现如下类似报错: 我这里是安装Erlang环境也是同样报错: 其实就是网络环境的问题,更换为国内的镜像源就行了,可以选择cmd的ssh连接方式(命令:ssh root192.168.xxx…...
C#核心概念解析:析构函数、readonly与this关键字
🔍 析构函数:资源清理的最后防线 核心作用 析构函数(~ClassName)在对象销毁前执行,专用于释放非托管资源(如文件句柄、非托管内存)。托管资源(如.NET对象)由GC自动回收…...

HarmonyOS基础组件:Button三种类型的使用
简介 HarmonyOS在明年将正式不再兼容Android原生功能,这意味着对于客户端的小伙伴不得不开始学习HarmonyOS开发语言。本篇文章主要介绍鸿蒙中的Button使用。 HarmonyOS中的Button相较于Android原生来说,功能比较丰富,扩展性高,减…...
深入理解设计模式之适配器模式
深入理解设计模式之适配器模式 1. 适配器模式概述 适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将一个类的接口转换为客户端所期望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的类能够协同工作,扮演了"转换器&quo…...
预训练模型:深度学习的通用特征引擎
预训练模型是深度学习领域的重要技术,其核心思想是通过大规模数据预先学习通用特征,再迁移到具体任务中进行微调。以下是其定义、原理及与其他模型的对比分析: 一、预训练模型的定义与原理 基本概念 预训练模型(Pre-trained Model…...
C++题解(33)2025年顺德区中小学生程序设计展示活动(初中组C++)U560876 美丽数(一)和 U560878 美丽数(二)题解
U560876 美丽数(一) 题目描述 小明很喜欢3和5这两个数字,他将能被3或5整除的数叫做美丽数。现在给你一个整数n,你能告诉小明第n个美丽数是多少吗? 输入格式 输入有多行,每行只有一个整数${n_i}$。 输出格式…...

产业互联网+三融战略:重构企业增长密码
产业互联网时代:用"三融"重构企业增长飞轮 在产业互联网浪潮下,企业面临资源分散、资金短缺、人才难聚的三重挑战。本文提出的"融人、融资、融资源"顶层设计,正为新时代企业构建增长新引擎。 一、三级合伙人体系&#x…...
centos yum源,docker源
yum源repo文件: wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repodocker源repo文件: yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo安装docker和docker c…...
通过设备节点获取已注册的 i2c client
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言代码分析 前言 另一个驱动通过设备节点 获取已注册的i2c client 代码分析 #include <linux/kernel.h> #include <linux/init.h> #include <li…...

Centos系统资源镜像配置
主要体现 yum 命令执行报错,排除网络连接问题 解决步骤: 下载安装工具 # 安装 wget curl vim yum install -y wget curl vim 原有repo文件备份 # 进入配置文件所在文件夹 cd /etc/yum.repos.d# 创建 backup 文件夹 mkdir backup# 备份文件放置文件夹 m…...

【Linux网络篇】:Socket网络套接字以及简单的UDP网络程序编写
✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨ 文章所属专栏:Linux篇–CSDN博客 文章目录 网络编程套接字一.预备知识1.理解源IP地址和目的IP地址2.认识端…...

学习路之uniapp--unipush2.0推送功能--给自己发通知
学习路之uniapp--unipush2.0推送功能--给自己发通知 一、绑定云空间及创建云函数二、编写发送界面三、效果后期展望: 一、绑定云空间及创建云函数 package.json {"name": "server-push","dependencies": {},"main": "…...
Java面向对象 一
系列文章目录 Java面向对象 二-CSDN博客 目录 系列文章目录 前言 一、初步认识面向对象 1.类和对象的简单理解 2.类的构成 二、类的实例化 1.对象的创建 2.对象的初始化 三、this引用的作用 四、构造方法 1.构造方法的提供 2.对象的构造 3.构造方法的重载 4.th…...
怎么开发一个网络协议模块(C语言框架)之(二) 数据结构设计
一、数据结构设计模板分析 (gdb) p gVrrpInstance $3 = { INT4 socketV4 = 107, .... vrrpStatisticsEntry_t SvrrpStatistics = {delIp4Count = 0, delIp6Count = 0, delIp4Error = 0, delIp6Error = 0, addIp4Count = 0, addIp6Count = 3, addIp4Error = 0, addIp6Error …...
30天自制操作系统day5(vram和显存)(GDT和IDT)(c语言结构体)(汇编-c)(ai辅助整理)
day5 harib02d c语言结构体的一些解释 struct BOOTINFO { char cyls, leds, vmode, reserve; short scrnx, scrny; char *vram; }; //最开始的struct命令只是把一串变量声明集中起来,统一叫做“struct BOOTINFO”。 //最初是1字节的变量cyls,接着是1字…...
【音频】drc 限幅器、多带限幅器、压缩器、多带压缩器
以下是关于 DRC 限幅器、多带限幅器、压缩器、多带压缩器的详细解释,它们均为音频处理领域的动态范围控制设备,主要用于调整音频信号的动态范围(即最大音量与最小音量的差值),以优化音质或满足特定播放需求: 一、DRC 限幅器(Dynamic Range Compression Limiter) 核心功…...

leetcode hot100刷题日记——12.反转链表
解答: /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(n…...
osgEarth中视角由跟随模式切换到漫游模式后没有鼠标拖拽功能问题分析及解决方法
遇到了一个棘手的问题,就是在由跟随模式切换到漫游模式的时候,鼠标无法实现拖拽功能。后来发现是前面给自己挖的坑。 因为要实现鼠标点选某个模型后,模型需要变红色显示,所以添加了一个事件处理程序。 // 创建 场景中模型的点选功能 事件处理程序 ModelSelectionHandler* …...
STM32中断优先级分组有哪几种?
STM32中断优先级分组主要有以下5种: 分组0:所有16位用于子优先级,没有抢占优先级。此时可配置的子优先级为0~15,共16级,适用于系统中对中断实时性要求不高,且中断源较多,需要更多子优先级来区分不同中断的情况。分组1:最高1位用于抢占优先级,最低3位用于子优先级。可配…...

《Python语言程序设计》第4章第8题3个个位数之间比大小。‘a小于b而b大于c’这是最有漏洞的一个对比,请问我如何判断a和c
升序来做这个题 比如123就变成321 需要比对3个数 这不是比对2个数。a和b比对 我们可以直接写 if a>b: print(ab) else print(ba) 但是现在是3个数abc 如果进行if比对呢 if a > b >c: print(a,b,c) elif a < b >c: print(bca) … 简洁的代码变成了复杂的代码段。…...