带标定的激光三角测量代码实例

* This program demonstrates how to perform the calibration
* of a sheet-of-light measurement system.
* *本程式示范如何执行光片测量系统的校正工作。
* The measurement system consists of an area scan camera and
* a light line projector (e.g. a laser line projector). The
* position and the orientation of the projector with respect
* to the camera are fixed. In order to reconstruct the surface
* of the whole object (and not only single profiles), the
* object must be moved under the measurement system,
* or alternatively the measurement system over the object.
* *测量系统由一个面扫描相机和一个光线投影仪(例如激光线投影仪)组成。投影仪相对于照相机的位置和方向是固定的。
*为了重建整个物体的表面(不仅是单个轮廓),必须在测量系统下移动物体,或者在测量系统上移动物体。
* Therefore, the calibration is performed in three steps:
* - At first we determine the internal and external
*   parameters of the camera by using the standard camera
*   calibration procedure.
*    首先使用标准相机校准程序确定相机的内外参数。
* - Then, we determine the orientation of the light plane with
*   respect to the world coordinate system. This is done by
*   computing a pose which is oriented such that the plane
*   defined by z=0 coincides with the light plane.
*然后,我们确定光平面相对于世界坐标系的方向。这是通过计算一个摆姿来实现的,
*这个摆姿的方向是由z=0定义的平面与光面重合。
* - At last, we calibrate the movement of the object between
*   the acquisition of two successive profiles. The transform
*   corresponding to this movement is also expressed with
*   respect to the world coordinate system.
* - Finally, we show how to apply the calibration transforms
*   to an already acquired disparity image.
* 最后,我们校准了目标在获取两个连续轮廓之间的移动。与此运动相对应的变换也表示与世界坐标系统有关。
*最后,我们展示了如何将校准转换应用到已经获得的视差图像上。
* Perform some initializations
* 执行一些初始化
dev_update_off ()
dev_close_window ()
read_image (ProfileImage, 'sheet_of_light/connection_rod_001.png')
get_image_size (ProfileImage, Width, Height)
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
*设置region的显示形式
dev_set_draw ('margin')
*设置线宽
dev_set_line_width (3)
*设置region的颜色
dev_set_color ('lime green')
*设置活动图形窗口的查找表。
dev_set_lut ('default')
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')

* -------
* Part 1: Perform the calibration of the camera
* 对相机进行校准
* -------

* Initialize some parameters required for the camera calibration
* 初始化相机校准所需的一些参数
StartParameters := [0.0125,0.0,0.0,0.0,0.0,0.0,0.000006,0.000006,376.0,120.0,752,240]
CalTabDescription := 'caltab_30mm.descr'
* Note that the thickness of the calibration target used for this example is 0.63 mm.
* If you adapt this example program to your application, it is necessary to determine
* the thickness of your specific calibration target and to use this value instead.
* 注意,本例使用的校准目标的厚度为0.63 mm。如果您将这个示例程序应用于您的应用程序,
* 那么有必要确定特定校准目标的厚度,并使用这个值。
CalTabThickness := .00063
NumCalibImages := 20

* Initialize a calibration data model
* 初始化一个校准数据模型。
create_calib_data ('calibration_object', 1, 1, CalibDataID)
*创建标定数据模型,用于存储标定数据,标定描述文件。 (指定标定类型:calibration_object  相机数量 标定板数量 标定板模型句柄)
set_calib_data_cam_param (CalibDataID, 0, 'area_scan_polynomial', StartParameters)
*设置相机参数和相机类型   (标定数据模型 相机索引,多相机时用 相机类型(线扫和面扫) 相机内参)
set_calib_data_calib_object (CalibDataID, 0, CalTabDescription)
*在标定模型中指定标定板所使用的标定板描述文件  (标定模型句柄 标定板索引 标定板描述文件) 
* Collect mark positions and estimated poses for all
* calibration images
* 收集所有校准图像的标记位置和估计的姿势
for Index := 1 to NumCalibImages by 1
    read_image (Image, 'sheet_of_light/connection_rod_calib_' + Index$'.2')
    dev_display (Image)
    find_calib_object (Image, CalibDataID, 0, 0, Index, [], [])
*   根据参数ID指定的标定数据模型以及calibobjdx(相机索引)标定模型描述,在图像中查找标准标定板,如果找到,则
    *提取标定板标志点的中心坐标和轮廓并评估标定板相对于相机的位姿
    get_calib_data_observ_points (CalibDataID, 0, 0, Index, Row, Column, _Index, Pose)
*   此算子用来读取标定模型的点数据 点数据由算子set_calib_data_observ_points产生,参数cameradx calibobjdx calibobjposeldx
    *为指定要读取的点数据,参数row column,index,pose为输出读取到的结果
    get_calib_data_observ_contours (Contours, CalibDataID, 'last_caltab', 0, 0, Index)
    *此算子用来读取标定数据模型的轮廓数据(返回读取到的轮廓 标定数据模型 指定轮廓名称(选项有marks caltab last_caltab 其中
    *marks指标定板标志点的轮廓 caltab 指标定板轮廓 last_caltab指最终的标定结果轮廓。指的注意的是,caltab只有在find calib object
    *查找标定板对象时才有效,而last_caltab无论算子find_calib_object查找到标定对象与否都会有结果返回,) )
    dev_set_color ('green')
    dev_display (Contours)
    gen_cross_contour_xld (Cross, Row, Column, 6, 0.785398)
    *为每个输入点生成一个XLD形状的十字形轮廓。
    dev_set_color ('yellow')
    dev_display (Cross)
endfor

* Perform the actual calibration执行实际的校准
calibrate_cameras (CalibDataID, Errors)
*标定相机参数(标定模型句柄 最优化反向投影误差)
disp_message (WindowHandle, 'The camera calibration has been performed successfully', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()

* -------
* Part 2: Calibrate the orientation of the light plane
*         with respect to the world coordinate system
*         根据世界坐标系统校准光平面的方向
* -------
dev_set_colored (3)
MinThreshold := 80

* Definition of the world coordinate system (WCS):
* Here, the WCS is defined implicitly by choosing one
* specific calibration image. In order to take the thickness
* of the calibration table into account, we shift the origin
* of the pose that corresponds to the chosen calibration image
* (and that was computed during the calibration).
*世界坐标系(WCS)的定义:在这里,WCS是通过选择一个特定的校准图像来隐式定义的。
*为了考虑校准表的厚度,我们移动了与所选校准图像相对应的姿态的原点(在校准过程中计算)。
Index := 19
get_calib_data (CalibDataID, 'calib_obj_pose', [0,Index], 'pose', CalTabPose)
*获得储存在标定模型中的标定(模型 标定对象 位置)数据 
*参数itemtype指定要获取的数据类型,参数itemldx随itemtype而变化。(模型id 标定模型中数据项类型 相关数据类型索引 数据项名称 属性值)
set_origin_pose (CalTabPose, 0.0, 0.0, CalTabThickness, CameraPose)
*设置3d坐标原点(原始的3d位置 3d位置在各自坐标轴移动的距离(正像右下移动,负值相反) 新的3d位置)
read_image (CalTabImage1, 'sheet_of_light/connection_rod_calib_' + Index$'.2')
dev_display (CalTabImage1)
get_calib_data (CalibDataID, 'camera', 0, 'params', CameraParameters)
disp_3d_coord_system (WindowHandle, CameraParameters, CameraPose, .01)
*                     (窗口             摄像机参数 摄像机位姿 世界坐标轴中坐标轴长度)
*该程序使用窗口WindowHandle中的摄像机参数CamParam,在给定的姿态下显示三维坐标系。
*显示轴的长度可以用参数CoordAxesLength在世界坐标中指定
disp_message (WindowHandle, 'World coordinate system', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()

* Definition of a temporary coordinate system (TCS):
* The TCS is also defined implicitly by choosing another
* calibration image. Here again we shift the origin of
* the coordinate system in order to take the thickness
* of the calibration table into account.
**临时坐标系统(TCS)的定义:TCS也通过选择另一个校准图像隐式地定义。
*在这里,我们再次改变坐标系统的原点,以便将校准表的厚度考虑进去。
Index := 20
get_calib_data (CalibDataID, 'calib_obj_pose', [0,Index], 'pose', CalTabPose)
set_origin_pose (CalTabPose, 0.0, 0.0, CalTabThickness, TmpCameraPose)
read_image (CalTabImage2, 'sheet_of_light/connection_rod_calib_' + Index$'.2')
dev_display (CalTabImage2)
disp_3d_coord_system (WindowHandle, CameraParameters, TmpCameraPose, .01)
disp_message (WindowHandle, 'Temporary coordinate system', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()


* Compute the 3D coordinates of the light line points
* in the plane z=0 of the WCS  计算在世界坐标系中z=0平面上的光线点的三维坐标
dev_clear_window ()
read_image (ProfileImage1, 'sheet_of_light/connection_rod_lightline_019.png')
compute_3d_coordinates_of_light_line (ProfileImage1, MinThreshold, CameraParameters, [], CameraPose, X19, Y19, Z19)
*计算光线点的三维坐标
if (|X19| == 0 or |Y19| == 0 or |Z19| == 0)
    dev_display (ProfileImage1)
    disp_message (WindowHandle, 'The profile MUST be oriented horizontally\nfor successfull processing!\nThe program will exit.', 'window', 12, 12, 'black', 'true')
    return ()
endif

* Compute the 3D coordinates of the light line points
* in the plane z=0 of the TCS  
*计算在临时坐标系的平面z=0处的光线点的三维坐标。
read_image (ProfileImage2, 'sheet_of_light/connection_rod_lightline_020.png')
compute_3d_coordinates_of_light_line (ProfileImage2, MinThreshold, CameraParameters, TmpCameraPose, CameraPose, X20, Y20, Z20)
if (|X20| == 0 or |Y20| == 0 or |Z20| == 0)
    disp_message (WindowHandle, 'The profile MUST be oriented horizontally\nfor successfull processing!\nThe program will exit.', 'window', 12, 12, 'black', 'true')
    return ()
endif

* Fit the light plane in the 3D coordinates of the line
* points computed previously. Note that this requires
* nearly coplanar points. We must provide line points
* recorded at -at least- two different heights, in order
* to get an unambiguous solution. To obtain stable and
* accurate results, acquire the light line points at the
* bottom and at the top of the measurement volume.
*通过前面计算出的光线点的坐标来拟合激光平面(不同高度的光线点
*.注意这需要近共面点  需要提供两种不同高度的点  
*了获取稳定和准确的结果,需要得到在测量区的顶部和底部的光线点
fit_3d_plane_xyz ([X19,X20], [Y19,Y20], [Z19,Z20], Ox, Oy, Oz, Nx, Ny, Nz, MeanResidual)
if (|Nx| == 0 or |Ny| == 0 or |Nz| == 0)
    disp_message (WindowHandle, 'Too few 3d points have been provided to fit the light plane,\nor the points are (nearly) collinear!\nThe program will exit.', 'window', 12, 12, 'black', 'true')
    return ()
endif
if (MeanResidual > 5e-5)
    disp_message (WindowHandle, 'The light plane could not be fitted accurately!\nThe mean residual distance between the 3d-points and the\nfitted plane is too high (' + (MeanResidual * 1000)$'.3' + 'mm). Please check the\nquality and the correctness of those points.\nThe program will exit!', 'window', 12, 21, 'black', 'true')
    return ()
endif

* Compute the light plane pose: this pose must be oriented
* such that the plane defined by z=0 coincides with the
* light plane.
**计算光面位姿:这个位姿必须朝向使z=0定义的平面与光面重合。
get_light_plane_pose (Ox, Oy, Oz, Nx, Ny, Nz, LightPlanePose)
if (|LightPlanePose| != 7)
    disp_message (WindowHandle, 'The pose of the light plane could not be\ndetermined. Please verify that the vector\npassed at input of the procedure\nget_light_plane_pose() is not null.\nThe program will exit!', 'window', -1, -2, 'black', 'true')
    return ()
endif
String := ['LightPlanePose: ','  Tx    = ' + LightPlanePose[0]$'.3' + ' m','  Ty    = ' + LightPlanePose[1]$'.3' + ' m','  Tz    = ' + LightPlanePose[2]$'.3' + ' m','  alpha = ' + LightPlanePose[3]$'.4' + '°','  beta  = ' + LightPlanePose[4]$'.4' + '°','  gamma = ' + LightPlanePose[5]$'.4' + '°','  type  = ' + LightPlanePose[6]]
disp_message (WindowHandle, String, 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_clear_window ()

* -------
* Part 3: Calibration of the movement of the object between
*         the acquisition of two successive profiles
* -------标定对象在获取两个连续轮廓之间的运动

* In order to determine the movement of the object between
* two successive profile images, we acquire two images of a
* calibration table which describe the same movement.
* In order to get a good accuracy, we usually move the
* calibration table by more than one step.
*为了确定物体在两个连续的轮廓图像之间的运动,我们获得了描述同一运动的校准表的两个图像。
*为了获得良好的精度,我们通常将校准表移动不止一步
read_image (CaltabImagePos1, 'sheet_of_light/caltab_at_position_1.png')
read_image (CaltabImagePos20, 'sheet_of_light/caltab_at_position_2.png')
StepNumber := 19

* Set the optimized camera parameter as new start camera parameters for the
* calibration data model to extract the following poses using
* these calibrated parameters.
*将优化后的相机参数设置为校准数据模型的新启动相机参数,
*使用这些校准后的参数提取如下姿态。
set_calib_data_cam_param (CalibDataID, 0, 'area_scan_polynomial', CameraParameters)
*设置相机参数和相机类型   (标定数据模型 相机索引,多相机时用 相机类型(线扫和面扫) 相机内参)
* Compute the pose of the calibration table in each image
*计算每张图像中校准表的姿态。
find_calib_object (CaltabImagePos1, CalibDataID, 0, 0, NumCalibImages + 1, [], [])
*   根据参数ID指定的标定数据模型以及calibobjdx(相机索引)标定模型描述,在图像中查找标准标定板,如果找到,则
    *提取标定板标志点的中心坐标和轮廓并评估标定板相对于相机的位姿
* Extract the unoptimized pose from the calibration data model
* 从校准数据模型中提取未优化的姿态。
get_calib_data_observ_points (CalibDataID, 0, 0, NumCalibImages + 1, Row1, Column1, Index1, CameraPosePos1)
*   此算子用来读取标定模型的点数据 点数据由算子set_calib_data_observ_points产生,参数cameradx calibobjdx calibobjposeldx
    *为指定要读取的点数据,参数row column,index,pose为输出读取到的结果
find_calib_object (CaltabImagePos20, CalibDataID, 0, 0, NumCalibImages + 2, [], [])
*   根据参数ID指定的标定数据模型以及calibobjdx(相机索引)标定模型描述,在图像中查找标准标定板,如果找到,则
    *提取标定板标志点的中心坐标和轮廓并评估标定板相对于相机的位姿
get_calib_data_observ_points (CalibDataID, 0, 0, NumCalibImages + 2, Row1, Column1, Index1, CameraPosePos20)
*   此算子用来读取标定模型的点数据 点数据由算子set_calib_data_observ_points产生,参数cameradx calibobjdx calibobjposeldx
    *为指定要读取的点数据,参数row column,index,pose为输出读取到的结果
* Clear the model
clear_calib_data (CalibDataID)

* Compute the coordinates of the origin of the calibration
* table in the two positions with respect to the world
* coordinate system and determine the coordinates of the
* corresponding translation vector
*计算两个位置的校准表在世界坐标系下的坐标,并确定对应的平移向量的坐标。
set_origin_pose (CameraPosePos1, 0.0, 0.0, CalTabThickness, CameraPosePos1)
*设置3d坐标原点(原始的3d位置 3d位置在各自坐标轴移动的距离(正像右下移动,负值相反)
set_origin_pose (CameraPosePos20, 0.0, 0.0, CalTabThickness, CameraPosePos20)
**将一个三维姿态转换为一个齐次变换矩阵 
pose_to_hom_mat3d (CameraPosePos1, HomMat3DPos1ToCamera)
pose_to_hom_mat3d (CameraPosePos20, HomMat3DPos20ToCamera)
*CameraPose表示世界坐标系到到相机坐标系的关系
pose_to_hom_mat3d (CameraPose, HomMat3DWorldToCamera)
*hom_mat3d_invert进行坐标系关系的转换,相机坐标系到世界坐标系的关系 
hom_mat3d_invert (HomMat3DWorldToCamera, HomMat3DCameraToWorld) 
*将两个齐次三维变换矩阵相乘,左矩阵,右矩阵,输出矩阵(两个时刻的标定板相对于世界坐标系的位置) 
hom_mat3d_compose (HomMat3DCameraToWorld, HomMat3DPos1ToCamera, HomMat3DPos1ToWorld)
hom_mat3d_compose (HomMat3DCameraToWorld, HomMat3DPos20ToCamera, HomMat3DPos20ToWorld)
*进行仿射变换,求其运动的平移向量 
affine_trans_point_3d (HomMat3DPos1ToWorld, 0, 0, 0, StartX, StartY, StartZ)
affine_trans_point_3d (HomMat3DPos20ToWorld, 0, 0, 0, EndX, EndY, EndZ)
MovementPoseNSteps := [EndX - StartX,EndY - StartY,EndZ - StartZ,0,0,0,0]
MovementPose := MovementPoseNSteps / StepNumber
String := ['MovementPose: ','  Tx    = ' + MovementPose[0]$'.3' + ' m','  Ty    = ' + MovementPose[1]$'.3' + ' m','  Tz    = ' + MovementPose[2]$'.3' + ' m','  alpha = ' + MovementPose[3] + '°','  beta  = ' + MovementPose[4] + '°','  gamma = ' + MovementPose[5] + '°','  type  = ' + MovementPose[6]]
disp_message (WindowHandle, String, 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_clear_window ()

* -------
* Part 4: Apply the calibration transforms to an already
*         acquired disparity image.将校准转换应用于已经获得的视差图像。
* -------

* Read an already acquired disparity map from file
*从文件中读取已经获取的视差图
read_image (Disparity, 'sheet_of_light/connection_rod_disparity.tif')
* Create a model and set the required parameters
*创建一个模型并设置所需的参数
gen_rectangle1 (ProfileRegion, 120, 75, 195, 710)
create_sheet_of_light_model (ProfileRegion, ['min_gray','num_profiles','ambiguity_solving'], [70,290,'first'], SheetOfLightModelID)
*应用片光技术创建一个片光模型,用来3d测量(指定处理轮廓的区域 控制参数,用来调整片光模型的一般参数 上一参数所对应的参数值 创建片光模型的句柄  )
set_sheet_of_light_param (SheetOfLightModelID, 'calibration', 'xyz')
*清楚measureshandle参数指定的测量对象,并释放其占用的内存空间  (控制参数  控制参数 字符串  控制参数(字符串、整型,实数))
set_sheet_of_light_param (SheetOfLightModelID, 'scale', 'mm')
set_sheet_of_light_param (SheetOfLightModelID, 'camera_parameter', CameraParameters)
set_sheet_of_light_param (SheetOfLightModelID, 'camera_pose', CameraPose)
set_sheet_of_light_param (SheetOfLightModelID, 'lightplane_pose', LightPlanePose)
set_sheet_of_light_param (SheetOfLightModelID, 'movement_pose', MovementPose)

* Apply the calibration transforms and
* get the resulting calibrated coordinates
*应用校准变换并得到最终校准的坐标
apply_sheet_of_light_calibration (Disparity, SheetOfLightModelID)
*对异性图片进行标定变换,为了计算3d构造表面的标定坐标,首先读取异性图像,将其像存储在
*SheetOfLightModelID片光模型中,并对图像进行标定变换。异性图片可以由maesure_profile_sheet_of_light
*获取,或者从取像设备中获取
get_sheet_of_light_result (X, SheetOfLightModelID, 'x')
*此算子用来获取片光模型的测量结果,(获取的结果值  片光模型句柄 名称)
get_sheet_of_light_result (Y, SheetOfLightModelID, 'y')
get_sheet_of_light_result (Z, SheetOfLightModelID, 'z')
clear_sheet_of_light_model (SheetOfLightModelID)
* 清除由create_sheet_of_light_model创建的片光模型
*
* Display the resulting Z-coordinates
*显示生成的z坐标
dev_close_window ()
get_image_size (Disparity, Width, Height)
dev_open_window (Height + 10, 0, Width * .5, Height * .5, 'black', WindowHandle3)
set_display_font (WindowHandle3, 14, 'mono', 'true', 'false')
dev_set_lut ('temperature')
dev_display (Z)
disp_message (WindowHandle3, 'Calibrated Z-coordinates', 'window', 12, 12, 'black', 'true')

* Display the resulting Y-coordinates
dev_open_window ((Height + 10) * .5, 0, Width * .5, Height * .5, 'black', WindowHandle2)
set_display_font (WindowHandle2, 14, 'mono', 'true', 'false')
dev_display (Y)
disp_message (WindowHandle2, 'Calibrated Y-coordinates', 'window', 12, 12, 'black', 'true')

* Display the resulting X-coordinates
dev_open_window (0, 0, Width * .5, Height * .5, 'black', WindowHandle1)
dev_display (X)
set_display_font (WindowHandle1, 14, 'mono', 'true', 'false')
disp_message (WindowHandle1, 'Calibrated X-coordinates', 'window', 12, 12, 'black', 'true')
  • 1
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值