在机器视觉测量项目中,对一些长条形的产品测量可能单个相机视野不够,需要两个或两个以上相机做拼接。
但相机安装的空间位置不同,需要对两个相机作融合标定。
首先:将两个相机架设好后,分别标定好两个相机内参。
这里两个相机分辨率为640*480,镜头16mm的。 用30mm标定板标定了内参。(内参标定方法这里就不介绍了)。
两相机内参分别为:
CamParam1 := [0.01619,-734.789,7.402e-006,7.4e-006,324.911,256.894,640,480]
CamParam2 := [0.0162584,-763.35,7.39842e-006,7.4e-006,324.176,245.371,640,480]
这里内参主要为了矫正镜头径向畸变。
第二步:需要一个双标定板,就是两个30mm的标定板连一块,相距64.88mm
把这玩意放在相机下,每个相机看到一块标定板。
相机1:
相机2:
然后分别获取标定板的Pose1,Pose2
halcon代码如下:
CaltabName := 'caltab_30mm.descr'
create_calib_data ('calibration_object', 2, 1, CalibDataID)
set_calib_data_calib_object (CalibDataID, 0, CaltabName)
set_calib_data_cam_param (CalibDataID, 0, 'area_scan_division', CamParam1)
find_calib_object (Image1, CalibDataID, 0, 0, 0, [], [])
get_calib_data_observ_points (CalibDataID, 0, 0, 0, RCoord1, CCoord1, Index1, Pose1)
get_calib_data_observ_contours (Caltab, CalibDataID, 'caltab', 0, 0, 0)
set_calib_data_cam_param (CalibDataID, 1, 'area_scan_division', CamParam2)
find_calib_object (Image2, CalibDataID, 1, 0, 0, [], [])
get_calib_data_observ_points (CalibDataID, 1, 0, 0, RCoord2, CCoord2, Index2, Pose2)
get_calib_data_observ_contours (Caltab, CalibDataID, 'caltab', 1, 0, 0)
第三步: 知道Pose后,可以对图像作投影变换,就是把图像拉到z=0的平面。这样投影变换过来图像可能不再是个矩形,导致矩形的图部分像素没有意义。我们可以把图像裁剪到边缘不需要的部分,来达到整张矩形图都有意义。还有两个图像拼接肯定要剪掉一部分啊。
对第一张图进行处理:上左下剪掉7%,右边剪20%。(因为右边双相机重叠部分比较多)。然后我们算出剪去后的图像坐上角的实际坐标,和右上角的实际坐标。(这是为了下面一步,第二张图像的拼接)。还有得到投影映射的map图。
halcon代码如下:
DistancePlates := 0.06488
ThicknessCaliper := 2.9 / 1000.0
ThicknessPlate := 5.65 / 1000.0
DiffHeight := ThicknessPlate - ThicknessCaliper
PixelSize := 0.0001
BorderInPercent := 7
OverlapInPercent := 20
get_image_size (Image1, WidthImage1, HeightImage1)
ULRow := HeightImage1 * BorderInPercent / 100.0
ULCol := WidthImage1 * BorderInPercent / 100.0
image_points_to_world_plane (CamParam1, Pose1, ULRow, ULCol, 'm', ULX, ULY)
LowerRow := HeightImage1 * (100 - BorderInPercent) / 100.0
RightCol := WidthImage1 * (100 - OverlapInPercent / 2.0) / 100.0
image_points_to_world_plane (CamParam1, Pose1, LowerRow, ULCol, 'm', X1, LowerY)
image_points_to_world_plane (CamParam1, Pose1, ULRow, RightCol, 'm', RightX, Y1)
HeightRect := int((LowerY - ULY) / PixelSize)
WidthRect := int((RightX - ULX) / PixelSize)
set_origin_pose (Pose1, ULX, ULY, DiffHeight, PoseNewOrigin1)
gen_image_to_world_plane_map (MapSingle1, CamParam1, PoseNewOrigin1, Width, Height, WidthRect, HeightRect, PixelSize, 'bilinear')
第四步: 在第三步里我们得到的map图,即能将第一张图裁剪拉正了。第四步就是把第二张图拉正裁剪,然后拼在第一张图的右边。
我们知道:这两个标定板相距64.88mm,即X轴相距64.88mm。第一张图处理后左上角位置是距离标定板原点ULX和ULY,当然这坐标是负值。那么右上角(第二张图要拼的角),位置为ULX+PixelSize*WidthRect,ULY。
怎么拼接呢?当然是找到第一张图右上角在第二张图张的坐标位置。很明显:只要X轴减去个64.88就好了啊。然后将这个点作为第二张图的原点,得到个newPose,找到映射图就好了啊。 这个点在第二张图的坐标为:(ULX+PixelSize*WidthRect-0.006488,ULY)。
halcon代码:
hom_mat3d_identity (HomMat3DIdentity)
hom_mat3d_translate_local (HomMat3DIdentity, ULX + PixelSize * WidthRect, ULY, DiffHeight, cp1Hur1)
hom_mat3d_translate_local (HomMat3DIdentity, DistancePlates, 0, 0, cp1Hcp2)
hom_mat3d_invert (cp1Hcp2, cp2Hcp1)
hom_mat3d_compose (cp2Hcp1, cp1Hur1, cp2Hul2)
pose_to_hom_mat3d (Pose2, cam2Hcp2)
hom_mat3d_compose (cam2Hcp2, cp2Hul2, cam2Hul2)
hom_mat3d_to_pose (cam2Hul2, PoseNewOrigin2)
gen_image_to_world_plane_map (MapSingle2, CamParam2, PoseNewOrigin2, Width, Height, WidthRect, HeightRect, PixelSize, 'bilinear')
得到两张映射图后,map_image一下,title_image一下,就成了。
如:相机1:
相机2:
处理后:
是吧!