Halcon 像机标定原理推导

您所在的位置:网站首页 棋盘格泛黄是正品吗 Halcon 像机标定原理推导

Halcon 像机标定原理推导

2024-03-14 13:16| 来源: 网络整理| 查看: 265

一、 平移和旋转矩阵推导

平移:

 

二、标定流程

最详细、最完整的相机标定讲解-CSDN博客

相机标定步骤:

1、打印一张棋盘格,把它贴在一个平面上,作为标定物。 2、通过调整标定物或摄像机的方向,为标定物拍摄一些不同方向的照片。 3、从照片中提取棋盘格角点。 4、估算理想无畸变的情况下,五个内参和六个外参。 5、应用最小二乘法估算实际存在径向畸变下的畸变系数。 6、极大似然法,优化估计,提升估计精度。

坐标系介绍:

摄像机坐标系 、 图像坐标系、像素坐标系 和 世界坐标系(参考坐标系) 。

像素坐标系:

描述物体成像后的像点在数字图像中的坐标,单位是像素个数 

图像坐标系:

描述了投影变换的过程,是沟通像素坐标系的 单位M

相机坐标系:

相机坐标系是以相机的光轴作为Z轴,是一个很重要的桥梁,沟通了图像坐标系,单位是M

世界坐标系:

是一个参考坐标系,单位是M

坐标转换基础 示意图如下:

 是相机坐标系 Z 轴与像平面夹角,一般情况下 Z 轴与像平面垂 直, 值为 90 度。 一、图像坐标系(x,y)----->像素坐标系(u,v)--平移

1.两坐标轴互相垂直

 

在这个过程中其实就是一个单位换算,距离单位、 像素单位的换算(像素与毫米间的线性关系)。

 二、相机坐标系(Xc,Yc,Zc)---->图像坐标系(x,y,1) 

小孔成像的原理---相似三角形

3D--->2D  

  

 当相机平面和像平面平行的时候cos(90)=0,那么此时就是红色字体的部分

 到次内参的部分已经全部完成:

 从上面我们可以看出有6个未知数(Sx, Sy,cx,cy,f,selta)

 三、世界坐标系(Xw,Yw,Zw)至相机坐标系(Xc,Yc,Zc)

 3维的旋转平移

最后一步:四个坐标之间矩阵相乘

 1.外参数矩阵。告诉你现实世界点(世界坐标)是怎样经过旋转和平移,然后落到另一个现实世界点(摄像机坐标)上。 2.内参数矩阵。告诉你上述那个点在1的基础上,是如何继续经过摄像机的镜头、并通过针孔成像和电子转化而成为像素点的。

halcon  标定  gen_caltab ( 7, //x方向的标记数; 7, //y方向的标记数; 0.0075, //标记点圆心之间的距离,单位:米; 0.5, //标记点直径与标记点圆心之间距离的比值; ‘C:/Users/Administrator/Desktop/caltab.descr’,//标定板的描述文件的保 存路径; ‘caltab.ps’,//描述标定板的一些信息,打印标定板时会用到)  标定文件 :

标定中记录的是标定板的物理坐标

模式 

通用模式

 

多项式模式 

结果分析 

* Calibration 01: Code generated by Calibration 01 CameraParameters := ['area_scan_polynomial', 0.00839696, 焦距长 1978.45, 径向畸变系数K1 2.43869e+07, 径向畸变系数K2 -2.86552e+12,径向畸变系数K3 0.39432, 切向畸变系数p1 -0.126256, 切向畸变系数p2 8.34956e-06, //单位像素的宽是8.34um 8.3e-06,//单位像素的高是8.3um 350.495, 图像坐标系原点在像素坐标系原点的位置 294.846,图像坐标系原点在像素坐标系原点的位置 768, 图库的大小 576] 图库的大小 CameraPose := [-0.275525,0.104421,2.28401,6.7113,323.595,32.4834,0] stop () 对应的内矩阵为             fx    0   u0   0     K =   0    fy   v0    0             0    0     1    0 就是 8.34956e-06 0 350.495 0 K= 0 8.3e-06 294.846 0 0 0 1 焦距f=0.00839696 m (注意单位是m) 模型不一样 * Calibration 01: Code generated by Calibration 01 CameraParameters := ['area_scan_division',0.00839081,-1987.45,8.35072e-06,8.3e-06,362.43,291.71,768,576] CameraPose := [-0.302872,0.111578,2.27866,6.68474,322.99,32.6195,0] stop ()

相机标定之后的外参数

R   T

0    1

是一个4*4 的矩阵

相机位姿,即外参(旋转矩阵+平移矢量)

CameraPose := [-0.0091626,-0.00625214,0.700967,2.46926,358.933,179.443,0]

代码标定 NumImages := 10 read_image (Images, 'calib/calib-3d-coord-' + [1:NumImages]$'02d') for I := 1 to NumImages by 1 select_obj (Images, Image, I) dev_display (Image) Message := 'Find calibration plate in\nall calibration images (' + I + '/' + NumImages + ')' disp_message (WindowHandle1, Message, 'window', 12, 12, 'black', 'true') * Find the calibration plate find_calib_object (Image, CalibDataID, 0, 0, I - 1, [], []) 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) *draw 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 (WindowHandle1, 'black', 'true') stop () calibrate_cameras (CalibDataID, Error) get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam) gen_empty_obj (Maps) 添加厚度  ImgPath := '3d_machine_vision/calib/' dev_close_window () dev_open_window (0, 0, 652, 494, 'black', WindowHandle) dev_update_off () dev_set_draw ('margin') dev_set_line_width (3) set_display_font (WindowHandle, 14, 'mono', 'true', 'false') * * Calibrate the camera. * *初始化标定板参数 *0.016 焦距 *0 Kappa初始值 *0.0000074, 0.0000074 X和Y像素当量 *326, 247 图像中心 *652, 494 图像大小 gen_cam_par_area_scan_division (0.016, 0, 0.0000074, 0.0000074, 326, 247, 652, 494, StartCamPar) create_calib_data ('calibration_object', 1, 1, CalibDataID) set_calib_data_cam_param (CalibDataID, 0, [], StartCamPar) *设置描述信息 set_calib_data_calib_object (CalibDataID, 0, 'caltab_30mm.descr') *描述一个X和Y方向黑点个数为7、间距为0.0125、标定比例0.5、caltab.descr:生成的标定板文件 * gen_caltab (7, 7, 0.0125, 0.5, 'caltab.descr', 'caltab.ps') NumImages := 10 * Note, we do not use the image from which the pose of the measurement plane can be derived for I := 1 to NumImages by 1 read_image (Image, ImgPath + 'calib_' + I$'02d') dev_display (Image) *寻找标定板 find_calib_object (Image, CalibDataID, 0, 0, I, [], []) get_calib_data_observ_contours (Caltab, CalibDataID, 'caltab', 0, 0, I) dev_set_color ('green') dev_display (Caltab) endfor *执行标定 *Error:成功校准后,以像素为单位返回优化的反投影的均方根误差(RMSE),如果与0.1相差较大,则校准效果不佳 calibrate_cameras (CalibDataID, Error) curIndex:=10 *获取内参 get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam) *获取外参:位姿 *先读取一个标定板,读取基于此标定板下的相机的位姿 *所以只需要一张标定板图像就可以获取相机的外参(基于此标定板的外参),Index是索引为10的标定板图像 get_calib_data (CalibDataID, 'calib_obj_pose', [0,curIndex], 'pose', CameraPose) disp_3d_coord_system (WindowHandle, CamParam, CameraPose, 0.01) CalTabThickness:=0.5 *重新设置原点,Z方向偏移0.5 set_origin_pose (CameraPose, 0, 0, CalTabThickness, PoseNewOrigin) disp_3d_coord_system (WindowHandle, CamParam, PoseNewOrigin, 0.01) * Write the internal camera parameters to a file write_cam_par (CamParam, 'camera_parameters.dat') Message := 'Interior camera parameters have' Message[1] := 'been written to file' disp_message (WindowHandle, Message, 'window', 12, 12, 'red', 'false') * clear_calib_data (CalibDataID)

内参矫正 

* Calibration 01: Code generated by Calibration 01 * 相机内参 CameraParameters := ['area_scan_division',0.00839081,-1987.45,8.35072e-06,8.3e-06, 362.43, 291.71, 768, 576] * 矫正后的内参 ['area_scan_division', 0.00839081, 0.0, 8.52659e-06,8.3954e-06, 361.554, 291.807, 768, 576] * 位姿 CameraPose := [-0.302872,0.111578,2.27866,6.68474,322.99,32.6195,0] stop () * 进行相机的径向畸变矫正 得到新的相机内参 一般来说切向畸变没有那么大。这里就想不管 change_radial_distortion_cam_par ('adaptive', CameraParameters, 0, NewCamParamOut) NumImages := 10 * read_image (Images, 'calib/calib-3d-coord-' + [1:NumImages]$'02d') for I := 1 to NumImages by 1 select_obj (Images, Image, I) *对发生径向畸变的图像形成映射,图像的映射到第一个参数中 gen_radial_distortion_map (Map, CameraParameters, NewCamParamOut, 'bilinear') * 对图像进行畸变矫正 map_image (Image, Map, ImageMapped) * ImageMapped 就是畸变矫正后的图像 * 将像素坐标---》实际坐标 image_points_to_world_plane (NewCamParamOut, CameraPose, 100, 100, 'm', X, Y) endfor code  * ********************************************************** * 使用标定助手标定图像 * ********************************************************** dev_update_window ('off') dev_close_window() dev_open_window(0, 0, 640, 480, 'black', WindowHandle) * 绘制轮廓线,不填充 dev_set_draw('margin') dev_set_line_width(3) set_display_font(WindowHandle, 14, 'mono', 'true', 'false') * 相机参数 CameraParameters := ['area_scan_division',0.0186694,-515.222,8.35294e-006,8.3e-006,241.908,254.532,640,480] * 相机位姿 CameraPose := [0.010563,-0.00289847,0.290847,358.416,32.4994,91.0794,0] * 加载图像 read_image (Image, 'scratch/scratch_calib_10.png') TmpCtrl_PlateDescription := 'D:/Program Files/MVTec/HALCON-18.11-Progress/calib/caltab_30mm.descr' TmpCtrl_FindCalObjParNames := ['gap_tolerance','alpha','skip_find_caltab'] TmpCtrl_FindCalObjParValues := [1,1,'false'] * 创建数据模型 create_calib_data ('calibration_object', 1, 1, CalibHandle) * 参数 set_calib_data_cam_param (CalibHandle, 0, [], CameraParameters) * 标定板初始化 set_calib_data_calib_object (CalibHandle, 0, TmpCtrl_PlateDescription) * 提取标记点 find_calib_object (Image, CalibHandle, 0, 0, 0, TmpCtrl_FindCalObjParNames, TmpCtrl_FindCalObjParValues) * 得到标记点的坐标 get_calib_data_observ_points (CalibHandle, 0, 0, 0, TmpCtrl_MarkRows, TmpCtrl_MarkColumns, TmpCtrl_Ind, CameraPose) * 标定板厚度 0.001 set_origin_pose (CameraPose, 0.0, 0.0, 0.001, CameraPose) * ********************************************************** * 测量结果 → 世界坐标 * ********************************************************** TmpCtrl_ImageRows := [TmpCtrl_MarkRows[0], TmpCtrl_MarkRows[1]] TmpCtrl_ImageColumns := [TmpCtrl_MarkColumns[0], TmpCtrl_MarkColumns[1]] * 得到一条线 gen_contour_polygon_xld (TmpObj_ImageContour, TmpCtrl_ImageRows, TmpCtrl_ImageColumns) * 图像坐标 → 世界坐标 image_points_to_world_plane (CameraParameters, CameraPose, TmpCtrl_ImageRows, TmpCtrl_ImageColumns, 'mm', TmpCtrl_WorldX, TmpCtrl_WorldY) * 计算世界坐标距离 distance_pp (TmpCtrl_WorldY[0], TmpCtrl_WorldX[0], TmpCtrl_WorldY[1], TmpCtrl_WorldX[1], TmpCtrl_Distance) * 显示结果 dev_display (Image) dev_set_color ('red') dev_display (TmpObj_ImageContour) * 按 F5 继续 disp_continue_message (WindowHandle, 'black', 'true') stop () * ********************************************************** * 轮廓 → 世界坐标 * ********************************************************** * 得到轮廓 gen_contour_polygon_xld (TmpObj_ImageContour, TmpCtrl_MarkRows, TmpCtrl_MarkColumns) * 轮廓 → 世界坐标 contour_to_world_plane_xld (TmpObj_ImageContour, TmpObj_WorldContour, CameraParameters, CameraPose, 'mm') * 提取中心点 get_contour_xld (TmpObj_WorldContour, TmpCtrl_WorldX, TmpCtrl_WorldY) * 显示结果 dev_display (Image) dev_set_color ('yellow') dev_display (TmpObj_ImageContour) * 按 F5 继续 disp_continue_message (WindowHandle, 'black', 'true') stop () * ********************************************************** * 图像矫正 * ********************************************************** * 图像宽度,mm → m TmpCtrl_RectificationWidth := 73 TmpCtrl_RectificationWidth := TmpCtrl_RectificationWidth / 1000.0 * 调整原点使得标定板大致居中 set_origin_pose (CameraPose, -0.5*TmpCtrl_RectificationWidth, -0.4*TmpCtrl_RectificationWidth, 0, TmpCtrl_RectificationPose) * 创建投射图 gen_image_to_world_plane_map (TmpObj_RectificationMap, CameraParameters, TmpCtrl_RectificationPose, 640, 480, 640, 480, TmpCtrl_RectificationWidth / 640, 'bilinear') * 释放内存 clear_calib_data (CalibHandle) * 使用投射图校准 map_image (Image, TmpObj_RectificationMap, TmpObj_RectifiedImage) * 显示结果 dev_display (TmpObj_RectifiedImage) dev_update_window ('on') 最新标定 dev_close_window () dev_open_window (0, 0, 768 / 2, 576 / 2, 'black', WindowHandle1) set_display_font (WindowHandle1, 14, 'mono', 'true', 'false') dev_update_off () dev_set_draw ('margin') dev_set_line_width (2) * * Calibrate the camera. * CalTabDescrFile := 'caltab_big.descr' * Make sure that the file 'CaltabName' is in the current directory, * the HALCONROOT/calib directory, or use an absolute path 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 read_image (Images, 'calib/calib-3d-coord-' + [1:NumImages]$'02d') for I := 1 to NumImages by 1 select_obj (Images, Image, I) dev_display (Image) Message := 'Find calibration plate in\nall calibration images (' + I + '/' + NumImages + ')' disp_message (WindowHandle1, Message, 'window', 12, 12, 'black', 'true') * Find the calibration plate find_calib_object (Image, CalibDataID, 0, 0, I - 1, [], []) 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) *draw 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 (WindowHandle1, 'black', 'true') stop () calibrate_cameras (CalibDataID, Error) get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam) gen_empty_obj (Maps) for I := 1 to NumImages by 1 * Obtain the pose of the calibration table get_calib_data (CalibDataID, 'calib_obj_pose', [0,I - 1], 'pose', Pose) set_origin_pose (Pose, -1.125, -1.0, 0, PoseNewOrigin) * Generate map gen_image_to_world_plane_map (MapSingle, CamParam, PoseNewOrigin, 768, 576, 900, 800, 0.0025, 'bilinear') concat_obj (Maps, MapSingle, Maps) endfor * * Map the images * dev_open_window (0, 391, 900 / 2, 800 / 2, 'black', WindowHandle2) set_display_font (WindowHandle2, 14, 'mono', 'true', 'false') Button := 0 NumImage := 1 for I := 1 to NumImages by 1 dev_set_window (WindowHandle1) dev_set_part (0, 0, 575, 767) dev_clear_window () select_obj (Images, Image, I) dev_display (Image) select_obj (Maps, MapSingle, I) map_image (Image, MapSingle, ImageMapped) dev_set_window (WindowHandle2) dev_set_part (0, 0, 799, 899) dev_clear_window () dev_display (ImageMapped) Message := 'Calibration image (' + I + '/' + NumImages + ')' disp_message (WindowHandle1, Message, 'window', 12, 12, 'black', 'true') Message := 'Mapped image' disp_message (WindowHandle2, Message, 'window', 12, 12, 'black', 'true') if (I < NumImages) disp_continue_message (WindowHandle1, 'black', 'true') stop () endif endfor  三、畸变

最详细、最完整的相机标定讲解_a083614的专栏-CSDN博客_相机标定方法

畸变一般可以分为:径向畸变、切向畸变 ps:畸变是相机本身的固有特性,和相机内参相同,标定一次之后即可。

畸变计算

 其中r^{2}=x^{2}+y^{2}

径向畸变来自于透镜形状。 切向畸变来自于整径向畸变(桶形畸变和枕形畸变): 实际摄像机的透镜总是在成像仪的边缘产生显著的畸变,这种现象来源于“筒形”或“鱼眼”的影响。 如下图,光线在原理透镜中心的地方比靠近中心的地方更加弯曲。对于常用的普通透镜来说,这种现象更加严重。筒形畸变在便宜的网络摄像机中非常厉害,但在高端摄像机中不明显,因为这些透镜系统做了很多消除径向畸变的工作。

*1、校正径向畸变,得到新的相机内参 change_radial_distortion_cam_par (‘adaptive’, CameraParameters, 0, CamParamOut) stop () Image Acquisition 02: Code generated by Image Acquisition 02 open_framegrabber (‘GigEVision’, 0, 0, 0, 0, 0, 0, ‘default’, -1, ‘default’, -1, ‘false’, ‘default’, ‘CAMERA_QBY_DM’, 0, -1, AcqHandle) grab_image_start (AcqHandle, -1) while (true) grab_image_async (Image, AcqHandle, -1) *2、对发生径向畸变的图像生成投影映射,图像的映射数据存在第一个参数中 gen_radial_distortion_map (Map, CameraParameters, CamParamOut, ‘bilinear’) *3、对图像进行畸变校正 map_image (Image, Map, ImageMapped) endwhile close_framegrabber (AcqHandle) 注意:相机标定之后,相机焦距、上下位置不能再动,否则需要重新标定。

步骤:

1)通过标定求出相机内参。

2)通过有畸变的内参求出无畸变的内参。用chage_radial_distortion_cam_par()函数完成。

3)求出有畸变的内参和无畸变的内参之间的映射关系。用

gen_radial_distortion_map()函数

4)将上边的映射关系作用到产生畸变的物体当中,完成畸变校正

四、matalb 标定 生成标定板 J = (checkerboard(300,4,5)>0.5); figure, imshow(J);

 

基本步骤

https://gene2022.blog.csdn.net/article/details/124125912?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1-124125912-blog-103223103.235%5Ev40%5Epc_relevant_3m_sort_dl_base1&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1-124125912-blog-103223103.235%5Ev40%5Epc_relevant_3m_sort_dl_base1&utm_relevant_index=1icon-default.png?t=N7T8https://gene2022.blog.csdn.net/article/details/124125912?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~BlogCommendFromBaidu~Rate-1-124125912-blog-103223103.235%5Ev40%5Epc_relevant_3m_sort_dl_base1&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~BlogCommendFromBaidu~Rate-1-124125912-blog-103223103.235%5Ev40%5Epc_relevant_3m_sort_dl_base1&utm_relevant_index=1

1、加载文件

2、标定

 3、标定结果

 

Matlab的存储格式为(一般对于非球面相机,k3为0)

那么我可以看做是其畸变为

对应matlab 中的结果为:

4、径向畸变参数选择

 

5、结果分析



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3