相机标定是视觉引导的第一个课,此课不过关,后面难以为继,出了问题可能都不好找。我当初这块也是疑惑了很久,
经过理论和实验算是总结了一点小经验。关于标定这块没有想好如何规划,先想到哪里写哪里,后面在慢慢整理。视觉定位太
需要实践了,个人感觉理论就是那些初中知识,但是要想完全用好,需要用丰富的现场实验经验。
本系列标定文章大概覆盖以下几点内容
1.9点标定
2.12 点标定
3.坐标归一化
4.海康VM 单点标定原理和测试
5.相机静止运动标定的区别
6.相机轴标定
为了更生动描述9/12点标定,也为了大家能更容易理解坐标系转换关系,只引入机械坐标系和相机坐标系,其他的坐标系就不提了,免得大家混。
特意通过Halcon写了一段模拟机械手运动进行标定的程序。先简单介绍下这个模拟程序。下图就是模拟的一个简单使用场景,XYZθ轴,上相机固定。
可以想象一下吸盘上吸玻璃片,玻璃片上有容易定位识别的边或者线。相机通过识别边线的交点来作为标定的特征点
分几步将机构做了简化示意图
1.机械坐标系 在Halcon中定义了机械坐标系 10000*10000,原点位于左上角,为了方便计算,原点往下为X轴,原点往右边为Y轴。
2.XYZθ 模组,只留了末端法兰盘和其连接的治具。以下图简化XYZθ模组
3.相机 蓝色框表示相机视野 2000*2000 像素。像素坐标尺寸和机械坐标尺寸是1:1,且相机视野的2个轴与机械坐标对齐,现实世界很难做倒,
这里只是模拟仿真,便于计算和理解。这样只要计算下图小圆圈的中心坐标,减去相机视野左角坐标 就可以得出像素坐标。
在此之前我们不妨思考一下如下问题
1.9点标定的意义是什么,为什么要进行9点标定
2.12点标定的意义是什么,为什么要进行12点标定。12点标定 放到下篇文章再讲
对于9点标定 应该很好理解,将相机坐标系映射到机械坐标系,这样像素坐标就可以转换为机械坐标,将像素的偏移数据转换为机械坐标的偏移 引导机械补偿偏移。
如果需要补偿旋转偏移基本的都需要12点标定。12点标定就比9点标定多了一个3点旋转标定
关于机械坐标的疑问
有一个疑问,就是XYZθ 设备读取的机械坐标到底表示的是设备那个点的坐标,这个容易引起困惑。其实这个容易理解,这个坐标可以表示Z轴上任意一点的坐标。
一旦确定这个坐标表示的是Z轴上的那个点,机械坐标系就被锚定了,在这之前 这个机械坐标系像是飘忽不定一样。对于有旋转轴的设备,此机械坐标一般表示的是末端法兰盘中心的坐标。
对于Scara 水平多关节机器人 对应的就是第四轴 中心点,对于普通6轴机器人就是末端旋转轴的中心。但是对于没有旋转轴的设备,标定时候的机械坐标表示哪个机械位置似乎显的不
太重要,应为绝大多数情况下计算的都是相对偏移量。绝对位置也可以通过示教位置加上相对偏移来获取。
标定的流程为,机构带着标定物,移动9次,相机在标定物上方拍9次照,这样共得到9组像素和机械坐标数据。联立方程组可解出像素坐标到机械坐标的转移矩阵。下面视频演示9点标定流程
仿真流程看如下代码 基于Halcon
*窗口坐标 宽度 dev_update_window('off') winw:=10000 winh:=10000 dev_open_window(0, 0, winw, winh, 'black', WindowHandle) set_system ('clip_region', 'false') dev_clear_window() dev_set_draw ('margin') gen_region_line(xaxis, 10, 10, 10, winw) gen_region_line(yaxis, 10, 10, winw, 10) dev_set_color ('red') dev_display(xaxis) dev_display(yaxis) *定义相机视野长宽 camstartrow:=5000 camstartcol:=5000 cam_width:=1000 cam_degre:=0 *定义相机左上角坐标,后面计算像素坐标用 cam_origin_row:=camstartrow-cam_width cam_origin_col:=camstartcol-cam_width *生成相机区域 gen_rectangle2(camrect, camstartrow, camstartcol, cam_degre, cam_width, cam_width) dev_set_color ('blue') dev_set_draw ('margin') dev_display(camrect) *定义 Arm 法兰盘位置 arm_center_row:=3000 arm_center_col:=5000 gen_circle(arm_center, arm_center_row, arm_center_col, 200) *定义末端工具 可以理解为一更长杆一端连接在法兰盘中心,一端带着吸盘 ,初始将吸盘的中心也放到相机中心 gen_region_line(tool,arm_center_row,arm_center_col,camstartrow,camstartcol) *定义吸盘 gen_circle(tool_center, camstartrow, camstartcol, 100) concat_obj(arm_center,tool,ObjectsConcat) concat_obj(ObjectsConcat, tool_center, Tool_ARM) dev_set_color ('pink') dev_set_draw ('margin') dev_display(Tool_ARM) *定义2个轴的移动步长系数 move9Row:=[ 0, 1, 1, 0, -1, -1, -1, 0, 1 ] move9Col:=[ 0, 0, 1, 1, 1, 0, -1, -1, -1 ] *机械坐标 xwolrd:=[] yworld:=[] *像素坐标 row_pixel:=[] col_pixel:=[] *每次移动补偿 step:=500.0 for Index := 0 to 8 by 1 *构建每次平移矩阵 hom_mat2d_identity(HomMat2DIdentity) hom_mat2d_translate(HomMat2DIdentity, move9Row[Index]*step, move9Col[Index]*step, HomMat2DTranslate) *模拟九点获取机械坐标,假设此时机械坐标就表示法兰盘中心的坐标 tuple_concat(xwolrd,arm_center_row+move9Row[Index]*step,xwolrd) tuple_concat(yworld,arm_center_col+move9Col[Index]*step,yworld) *模拟移动机械臂 affine_trans_region(Tool_ARM, RegionAffineTrans, HomMat2DTranslate, 'nearest_neighbor') *计算移动后机械臂的坐标,这里(Row[2],Column[2]),刚好是吸盘(小圆圈)的坐标 area_center(RegionAffineTrans, Area, Row, Column) tuple_concat(row_pixel,Row[2]-(cam_origin_row), row_pixel) tuple_concat(col_pixel,Column[2]-(cam_origin_col), col_pixel) dev_display(RegionAffineTrans) endfor disp_cross(WindowHandle, row_pixel, col_pixel, 10,0) *上面模拟九点标定以后 计算标定数据,HomMat2D 就是9点标定的转移矩阵 vector_to_hom_mat2d(row_pixel, col_pixel, xwolrd, yworld, HomMat2D) *验算Qx1 Qy1 与 xwolrd,yworld 可以说完全一致 affine_trans_point_2d(HomMat2D, row_pixel, col_pixel, Qx1, Qy1) *模拟X Y 移动(800,800) hom_mat2d_identity(HomMat2DIdentity) hom_mat2d_translate(HomMat2DIdentity, 800, 800, HomMat2DTranslate) affine_trans_region(Tool_ARM, RegionAffineTrans, HomMat2DTranslate, 'nearest_neighbor') dev_set_color ('green') dev_display(RegionAffineTrans) *取像素坐标 area_center(RegionAffineTrans, Area, Row, Column) px:=Row[2]-cam_origin_row py:=Column[2]-cam_origin_col *通过像素坐标计算机械坐标 affine_trans_point_2d(HomMat2D,px,py,qx,qy) dev_set_color ('green') disp_cross(WindowHandle, px, px, 80, 0) dev_set_color ('red') disp_cross(WindowHandle, qx, qy, 80, 0)
上面代码 模拟了9点标定的过程。机械坐标表示的是法兰盘中心坐标也就是图中那个大圈圆心坐标。
代码最后模拟XY 分别移动(800,800),来验证标定是否正确。蓝色表示移动后的位置。(qx,qy)(3800,5800) 在下图用红色十字标出,在大圆中心,符合预期。
此处有一个疑问:像素空间中的一个点的像素坐标,经过上面标定数据转换后,得到坐标是否能对应此像素坐标在机械坐标空间的真实坐标。很显然,不一定,这取决与标定时 机械坐标指的是哪机械点的坐标。
如上图 点2的像素坐标(px,py) (1799.5,1799.5), 经过标定转化后的坐标 应该为 (5800,5800),但是实际情况是(3800,5800),偏移到了点1。理论和实际存在(2000,0)的固定偏移。 为何会出现这种情况,
这种偏移是在标定时引入的。因为标定时像素对应机械坐标就是大圆圈的坐标,如果取的时小圆圈的坐标就不存在偏移。实际场景也是很难取得像素点对应的真实机械坐标。对于没有角度偏移的使用场景,这种
固定偏差的存在不影响我们引导定位。因为应为绝大多数情况下计算的都是相对偏移量。绝对位置也可以通过示教位置加上相对偏移来得到。
系列文章
疑问留言 或者 添加下面2种方式 交流 加群(277957302)
暂无评论