Halcon 像机标定原理推导

一、 平移和旋转矩阵推导

平移:

 

二、标定流程


相机标定步骤:

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

坐标转换基础

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

一、图像坐标系(x,y)至像素坐标系(u,v)

1.两坐标轴互相垂直

扫描二维码关注公众号,回复: 14454217 查看本文章

 

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

据三角形相似性原理得

 

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

 3维的旋转平移

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

 1.外参数矩阵。告诉你现实世界点(世界坐标)是怎样经过旋转和平移,然后落到另一个现实世界点(摄像机坐标)上。

2.内参数矩阵。告诉你上述那个点在1的基础上,是如何继续经过摄像机的镜头、并通过针孔成像和电子转化而成为像素点的。

gen_caltab (
7, //x方向的标记数;

7, //y方向的标记数;

0.0075, //标记点圆心之间的距离,单位:米;

0.5, //标记点直径与标记点圆心之间距离的比值;

‘C:/Users/Administrator/Desktop/caltab.descr’,//标定板的描述文件的保 存路径;

‘caltab.ps’,//描述标定板的一些信息,打印标定板时会用到)

            fx    0   u0   0
    K =  0    fy   v0    0
            0    0     1    0
相机的内参矩阵,和焦距

相机内参

CameraParameters := [0.0375147,     -270.806,      8.30152e-006,   8.3e-006,  647.48, 520.914,   1280,      960]

相机标定之后的外参数

R   T

0    1

是一个4*4 的矩阵

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

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

* **********************************************************
* 使用标定助手标定图像
* **********************************************************
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')

 三、畸变

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

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

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

*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)将上边的映射关系作用到产生畸变的物体当中,完成畸变校正

猜你喜欢

转载自blog.csdn.net/weixin_39354845/article/details/122955961#comments_22428770