当前位置: 首页 > backend >正文

基于线结构光模型的工件孔洞检查

文章目录

      • 1,目的。
      • 2,难点。
      • 3,处理流程图。
      • 3,程序分析。
        • 3.1,建立参考物3D对象。
        • 3.2,创建表面匹配模型。
        • 3.3,匹配被测对象获取位姿,被测对象与参考对像对齐。
        • 3.4,分析获取表示异常的点云。
        • 3.5,对异常点云进行分类定性。
          • 3.5.1,对点云进行平面拟合,分析(重点)。
          • 3.5.2,确定表示孔洞缺失、多余、偏大、偏小的点云。
          • 3.5.3,点云对称性分析,确定表示孔洞错位的点云
          • 3.5.4,表示未确定异常原因的点云。
        • 3.6,显示。
      • 4,完整程序。

1,目的。

从提供的视差图中分析工件的孔洞是否存在缺失,多余,偏大,偏小,错位等异常。

如下所示:

在这里插入图片描述在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2,难点。

  • 拟合出通过点云所有点的 2D Region,并通过对 2D Region进行相应2D计算判断出被拟合点云表示的是孔洞缺失、多余、偏大、偏小哪一种情况。
  • 异常点云对称性分析,查找出对称的点云,从而确定哪些点云表示孔洞错位

3,处理流程图。

与参考对象表面匹配对齐
参考对象对被测对象的\n点云距离大于阈值
被测对象对参考对象的\n点云距离大于阈值
平面拟合
圆形系数ok
圆形系数not ok
点云对称性not ok
点云对称性ok
Start
建立参考3D 对象
被测的 3D 对象
两者点云距离计算
被测对象缺少或者多余的点云
通过点云所有点的 2D Region
已定义的异常类型
未定义的异常类型
孔洞缺少
孔洞多余
孔洞偏大
孔洞偏小
未知类型
孔洞错位
结果显示
End

3,程序分析。

3.1,建立参考物3D对象。
* ------------------1,创建用作参照物的3D对象* 1.1,读取描述3D对象轮廓的视差图。
* Create a sheet-of-light model to collect the disparities
* and set the calibration information for the reconstruction.
* tif文件:标准的位图文件,部分设备生成的深度图,点云数据采用此格式存储
read_image (Disparity, 'sheet_of_light/injection_mold_01_disparity')
get_image_size (Disparity, Width, Height)
* 处理的光条数量(即扫描次数)
NumProfiles := Height
gen_rectangle1 (Rectangle, 0, 0, Height - 1, Width - 1)* 1.2,创建线结构光三维测量模型
create_sheet_of_light_model (Rectangle, [], [], SheetOfLightModelID)
* 相机内参
CameraParam := [0.016,-1250.34,4.65114e-006,4.65e-006,623.43,515.23,1280,1024]
* 相机外参
CameraPose := [0.0013952482819,-0.0025835234583,-0.53764418409,337.80940798,359.84685912,358.46883832,0]
* 光平面在世界坐标系的位姿
LightplanePose := [-0.047567497224,-0.73091602504,0.0016815300297,271.32238394,0.40428170089,359.66058824,0]
* 移动时位姿变化/步(该位姿在世界坐标系)
MovementPose := [-2.5e-005,-1.5e-4,-1.25e-006,0.0,0.0,0.0,0]
* 定义校准模式,决定输出的坐标性类型
set_sheet_of_light_param (SheetOfLightModelID, 'calibration', 'xyz')
* 定义三维坐标输出的单位,m表示米
set_sheet_of_light_param (SheetOfLightModelID, 'scale', 'm')
* 设置相机的内参
set_sheet_of_light_param (SheetOfLightModelID, 'camera_parameter', CameraParam)
* 设置相机的姿态
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)
* 
* Init display
dev_update_off ()
dev_close_window ()
dev_open_window_fit_image (Disparity, 0, 0, 500, 480, WindowHandle1)get_window_extents (WindowHandle1, Row, Column, Width1, Height1)
dev_open_window_fit_image (Disparity, 0, Width1 + 8, 500, 480, WindowHandle2)
set_display_font (WindowHandle1, 16, 'mono', 'true', 'false')
set_display_font (WindowHandle2, 16, 'mono', 'true', 'false')
dev_set_window (WindowHandle1)
* 
* 1.3,定义异常类型对应的文本和颜色
ErrorTypesText := ['unknown','additional hole','missing hole','hole too large','hole too small','wrong position','unknown (missing in test object)','unknown (missing in reference object)']
ErrorTypesColor := ['white','magenta','red','blue','yellow','cyan','white','white']
* 
* Set the disparity image of the reference object
* 1.4,将视差图图像设置到 线结构光测量模型中
set_profile_sheet_of_light (Disparity, SheetOfLightModelID, [])
* * 1.5,获取标准参照物的3D对象
get_sheet_of_light_result_object_model_3d (SheetOfLightModelID, ReferenceOrig)
* 显示原始图
visualize_object_model_3d (WindowHandle1, ReferenceOrig, [], [], ['lut','intensity','disp_pose'], ['color1','coord_z','true'], [], [], [], PoseOut2)
* 去除参照物的背景
select_points_object_model_3d (ReferenceOrig, 'point_coord_z', 0.01, 1, Reference)
* 1.6,显示参考对象(标准物)
visualize_object_model_3d (WindowHandle2,  Reference, [], [], ['lut','intensity','disp_pose'], ['color1','coord_z','true'], [], [], [], PoseOut2)
* Clean up
clear_object_model_3d (ReferenceOrig)

如图所示:参考对象

在这里插入图片描述

3.2,创建表面匹配模型。
* -----------------------2,创建基于表面的 3D 匹配模型,采样距离与物体直径的比例为:0.02
*-------------------------
create_surface_model (Reference, 0.02, [], [], SurfaceModelID)
* 
* Display reference object
dev_clear_window ()
get_window_extents (WindowHandle1, Row2, Column2, Width2, Height2)
dev_set_part (0, 0, Height2 - 1, Width2 - 1)
Introduction := '这个例子展示了一个校准的'
Introduction[1] := '用于表面比较的线性结构光.'
Introduction[2] := '在这个例子中展示:'
Introduction[3] := '检查孔的位置,数量,大小是否有异常.'
disp_message (WindowHandle1, Introduction, 'window', 12, 12, 'white', 'false')* 2.1,创建标准 3D 模型显示位姿
create_pose (0.0244755,0.0707748,2.10414,-0.0,0.0,-0.0, 'Rp+T', 'gba', 'point', PoseDisplay)
Title := '参考对象(标准物)'
Instructions[0] := 'Rotate: Left button'
Instructions[1] := 'Zoom:   Shift + left button'
Instructions[2] := 'Move:   Ctrl  + left button'* 2.2,显示参考对象
visualize_object_model_3d (WindowHandle2, Reference, [], PoseDisplay, ['lut','intensity'], ['color1','coord_z'], Title, [], Instructions, PoseOut)
* 
* Display the reference object in the second window for comparison with the
* test object
dev_set_window (WindowHandle2)
get_window_extents (WindowHandle2, Row2, Column2, Width2, Height2)
dev_set_part (0, 0, Height2 - 1, Width2 - 1)
dev_clear_window ()
disp_object_model_3d (WindowHandle2, Reference, [], PoseDisplay, ['lut','intensity'], ['color1','coord_z'])
disp_message (WindowHandle2, 'Reference object', 'window', 12, 12, 'black', 'true')
* 
3.3,匹配被测对象获取位姿,被测对象与参考对像对齐。
*---------------------------3,查找被测 3D 对象
* Main loop
NumScenes := 6
MaxDist := 0.001
for SceneIndex := 1 to NumScenes by 1dev_set_window (WindowHandle1)dev_clear_window ()disp_message (WindowHandle1, 'Match test object with reference object ...', 'window', 12, 12, 'black', 'true')* 3.1, 读取被测的视差图像read_image (Disparity, 'sheet_of_light/injection_mold_' + SceneIndex$'02d' + '_disparity')* 3.2,复位线结构光模型中的视差图像. 其他的设置保持不变reset_sheet_of_light_model (SheetOfLightModelID)* 3.3,设置需要测量轮廓的视差图set_profile_sheet_of_light (Disparity, SheetOfLightModelID, [])* 3.4,使用线性结构光测量模型中解析出 待检测的 3D 对象get_sheet_of_light_result_object_model_3d (SheetOfLightModelID, TestObjectOrig)* 去除背景select_points_object_model_3d (TestObjectOrig, 'point_coord_z', 0.01, 1, TestObject)clear_object_model_3d (TestObjectOrig)*3.5,显示被测的3D对象点云visualize_object_model_3d (WindowHandle1, TestObject, [], [], ['lut','intensity'], ['color1','coord_z'], [], [], [], PoseOut3)disp_message (WindowHandle1, 'Match test object ' + SceneIndex + ' with reference object...', 'window', 12, 12, 'black', 'true')wait_seconds (1)* 3.6,检测标准 3D 模型 相对于 被测 3D 模型的位姿  find_surface_model (SurfaceModelID, TestObject, 0.02, 0.5, 0, 'false', 'pose_ref_sub_sampling', 1, Pose, Score, NotUsed)* 被测 3D 点云模型相对于标准 3D 模型的位姿pose_invert (Pose, PosesInvert)* 3.7,刚体变化检测对象到参考对象rigid_trans_object_model_3d (TestObject, PosesInvert, TestObjectTrans)* 3.8,显示测试对象对齐后状态disp_object_model_3d (WindowHandle1,TestObjectTrans, [],  PoseDisplay, ['lut','intensity','disp_pose'], ['color1','coord_z','true'])

如图所示,对齐前:

在这里插入图片描述

对齐后:

在这里插入图片描述

3.4,分析获取表示异常的点云。
*---------------------4,分析被测对象与参考 3D 对象的点云差异* 4.1,----情况1:被测 3D 对象点云缺失(有额外的孔洞)----* 4.1.1,测量3D参考对象与被测3D对象的各点的距离distance_object_model_3d (Reference, TestObjectTrans, [], 0.0, [], [])* 4.1.2,筛选出被测 3D 对象缺少的点云select_points_object_model_3d (Reference, '&distance', MaxDist, 1, ObjectModel3DThresholded)ToClear := ObjectModel3DThresholded* 4.1.3,显示被测 3D 对象相对参照 3D 对象缺失的点云disp_object_model_3d (WindowHandle1, ObjectModel3DThresholded, [], [], ['lut','intensity','disp_pose'], ['color1','coord_z','true'])* 4.1.4,处理 被测 3D 对象相对参照 3D 对象缺失的点云get_object_model_3d_params (ObjectModel3DThresholded, 'num_points', NumPoints)if (NumPoints > 0)* Calculate connected components, the distance threshold should* be greater than the distance between two scan lines (> MovementPose[1])connection_object_model_3d (ObjectModel3DThresholded, 'distance_3d', 0.001, ObjectModel3DConnected)ToClear := [ToClear,ObjectModel3DConnected]* 计算测试对象上缺少的点云(保留主要部分,去掉噪声)select_object_model_3d (ObjectModel3DConnected, 'num_points', 'and', 200, 1000000, SurfacePointsMissingInTestObject)elseSurfacePointsMissingInTestObject := []endif* Clean upclear_object_model_3d (ToClear)* *----4.2,情况2:被测 3D 对象点云多余(缺少孔洞)----* 4.2.1,反过来测量被测3D 对象与 参考3D 对象的各点距离,求出被测3D 对象多出的点云distance_object_model_3d (TestObjectTrans, Reference, [], 0.0, [], [])* 4.2.2,筛选出被测 3D 对象多出的点云块select_points_object_model_3d (TestObjectTrans, '&distance', MaxDist, 1, ObjectModel3DThresholded)ToClear := ObjectModel3DThresholdedtry* Calculate connected components, the distance threshold should* be greater than the distance between two scan lines (> MovementPose[1])connection_object_model_3d (ObjectModel3DThresholded, 'distance_3d', 0.001, ObjectModel3DConnected)ToClear := [ToClear,ObjectModel3DConnected]* ,处理 被测 3D 对象相对参照 3D 对象多出的点云select_object_model_3d (ObjectModel3DConnected, 'num_points', 'and', 200, 1000000, SurfacePointsMissingInReference)catch (Exception)SurfacePointsMissingInReference := []endtry* Clean upclear_object_model_3d (ToClear)

表示异常的点云: 可见被测对象缺少孔洞

在这里插入图片描述

3.5,对异常点云进行分类定性。
3.5.1,对点云进行平面拟合,分析(重点)。
*---------------------------------5,对被测物的异常点云块进行处理* Collect and classify errors* 5.1,被测3D 对象缺少,多出的点云部分集合ErrorObjects := [SurfacePointsMissingInTestObject,SurfacePointsMissingInReference]* 异常点云块提示信息ErrorSources := [gen_tuple_const(|SurfacePointsMissingInTestObject|,'missing in test'),gen_tuple_const(|SurfacePointsMissingInReference|,'missing in reference')]ErrorTypes := []gen_empty_obj (ErrorPatterns)* 异常的点云块数量NumErrors := |ErrorObjects|* 对异常部分点云块进行处理if (NumErrors > 0)for ErrorIndex := 0 to NumErrors - 1 by 1* 异常的点云ErrorObject := ErrorObjects[ErrorIndex]* 异常点云的文本信息ErrorSource := ErrorSources[ErrorIndex]* * 5.2,为异常的点云中拟合出一个通过这些点的Region* a plane through the points and then projecting the points into this plane.create_region_from_error_points (Region, ErrorObject)* * 5.3,分析所得到的二维拟合图形的形状 (the region)fill_up (Region, RegionFillUp)difference (RegionFillUp, Region, RegionDifference)circularity (Region, CircularityRegDilation)circularity (RegionFillUp, CircularityRegFillUp)circularity (RegionDifference, CircularityRegDifference)* area_center (Region, AreaRegDilation, Row1, Column1)area_center (RegionFillUp, AreaRegFillUp, Row1, Column1)area_center (RegionDifference, AreaRegDifference, Row1, Column1)* 
3.5.2,确定表示孔洞缺失、多余、偏大、偏小的点云。
 * 5.4,给异常点云块分类,确定对应的异常类型MinCircularity := 0.7if (CircularityRegDilation > MinCircularity and real(AreaRegDifference) / AreaRegDilation < 0.1)if (ErrorSource == 'missing in test')* 5.4.1,原因1:被测3D 对象孔洞多余ErrorType := 1else* 5.4.2,原因2:被测3D 对象孔洞缺少ErrorType := 2endifelseif (CircularityRegFillUp > MinCircularity and CircularityRegDifference > MinCircularity and real(AreaRegDifference) / AreaRegDilation > 0.1)if (ErrorSource == 'missing in test')* 5.4.3,原因3:被测 3D 对象 孔洞偏大ErrorType := 3else* 5.4.4,原因4:被测 3D 对象 孔洞偏小ErrorType := 4endifelse* 5.4.0,原因0:未知原因ErrorType := 0endif*ErrorType:0 原因未知,1被测 3D 对象孔洞多余,2 被测 3D 对象 缺少孔洞*           3:被测 3D 对象孔洞偏大, 4 被测 3D 对象孔洞偏小*           5 wrong position*          6 unknown (missing in test object)*          7 unknown (missing in reference object)ErrorTypes[ErrorIndex] := ErrorType* 连接由异常点云块拟合出来的异常区域concat_obj (ErrorPatterns, Region, ErrorPatterns)endfor
3.5.3,点云对称性分析,确定表示孔洞错位的点云
 * 5.5,对表示异常的点云进行分类* 5.5.1,类型1:表示缺失,多余,偏大,偏小类型的点云对象MaskKnown := ErrorTypes [!=] 0* 注意如果MaskKnown的数组长度与ErrorObjects数组长度不一致将无法执行select_mask* select_mask执行的结果为MaskKnown成员为true则保留ErrorObjects对应位置的对象ErrorObjectsKnown := select_mask(ErrorObjects,MaskKnown)ErrorTypesKnown := select_mask(ErrorTypes,MaskKnown)* 5.5.2,类型2:表示孔洞错位的点云对* 5.5.2.1,被测3D对象缺少的点云(这些点云未明确错误类型)MaskUnknownMIT := ErrorTypes [==] 0 and ErrorSources [==] 'missing in test'ErrorObjectsUnknownMIT := select_mask(ErrorObjects,MaskUnknownMIT)*  5.5.2.2,被测3D对象多余的点云(这些未明确错误类型)MaskUnknownMIR := ErrorTypes [==] 0 and ErrorSources [==] 'missing in reference'ErrorObjectsUnknownMIR := select_mask(ErrorObjects,MaskUnknownMIR)* ErrorObjectsWrongPos := []ErrorTypesWrongPos := []* MergedMIT := gen_tuple_const(|ErrorObjectsUnknownMIT|,false)MergedMIR := gen_tuple_const(|ErrorObjectsUnknownMIR|,false)* 对未明确异常原因的点云块进一步进行分类if (|ErrorObjectsUnknownMIT| > 0 and |ErrorObjectsUnknownMIR| > 0)for IndexMIT := 0 to |ErrorObjectsUnknownMIT| - 1 by 1if (MergedMIT[IndexMIT])continueendiffor IndexMIR := 0 to |ErrorObjectsUnknownMIR| - 1 by 1if (MergedMIR[IndexMIR])continueendif* Test if there are symmetric error objects* The parameter MaxHoleDiameter is used to speed up the search and to* make it more robust, because we are only interested in symmetric* error objects that are not further apart from each other than* the size of a hole.*判断是否有对称的错误对象,如果是则认为是孔洞位置错误*参数MaxHoleDiameter是用来加快搜索和*使它更健壮,因为我们只对对称感兴趣错误对象之间的距离小于洞的大小MaxHoleDiameter := 0.02*表示孔洞位置偏离的点云块对*=======*======= 判断被测物缺少的点云块与多余的点云块的对称性,如果对称性高则说明两个点云对称,即可判定孔洞错位test_symmetry_object_model_3d (ErrorObjectsUnknownMIT[IndexMIT], ErrorObjectsUnknownMIR[IndexMIR], MaxHoleDiameter, Rating)if (Rating > 70)* Merge the two symmetric errors into a new error object* 合并两个对称点云get_object_model_3d_params (ErrorObjectsUnknownMIT[IndexMIT], 'point_coord_x', X1)get_object_model_3d_params (ErrorObjectsUnknownMIT[IndexMIT], 'point_coord_y', Y1)get_object_model_3d_params (ErrorObjectsUnknownMIT[IndexMIT], 'point_coord_z', Z1)get_object_model_3d_params (ErrorObjectsUnknownMIR[IndexMIR], 'point_coord_x', X2)get_object_model_3d_params (ErrorObjectsUnknownMIR[IndexMIR], 'point_coord_y', Y2)get_object_model_3d_params (ErrorObjectsUnknownMIR[IndexMIR], 'point_coord_z', Z2)* 根据点 生成 3D 对象gen_object_model_3d_from_points ([X1,X2], [Y1,Y2], [Z1,Z2], ObjectModel3D)* Remember the new objectErrorObjectsWrongPos := [ErrorObjectsWrongPos,ObjectModel3D]* 表示错位的孔洞ErrorTypesWrongPos := [ErrorTypesWrongPos,5]* Mark merged objectMergedMIT[IndexMIT] := trueMergedMIR[IndexMIR] := truebreakendifendforendfor* Clean up* MergedMIT:表示错位的点云,如果元素为true则是孔洞错位,否则为未知
3.5.4,表示未确定异常原因的点云。
 *5.5.3,类型3:unknown (missing in test object)for IndexMIT := |MergedMIT| - 1 to 0 by -1if (MergedMIT[IndexMIT])* 从表示未知原因的异常点云块集合中去除错位的点云块clear_object_model_3d (ErrorObjectsUnknownMIT[IndexMIT])tuple_remove (ErrorObjectsUnknownMIT, IndexMIT, ErrorObjectsUnknownMIT)endifendfor* 5.5.4,unknown (missing in reference object)for IndexMIR := |MergedMIR| - 1 to 0 by -1if (MergedMIR[IndexMIR])clear_object_model_3d (ErrorObjectsUnknownMIR[IndexMIR])tuple_remove (ErrorObjectsUnknownMIR, IndexMIR, ErrorObjectsUnknownMIR)endifendforendif* 
3.6,显示。
* 5.6,表示缺陷的点云对象汇总* ErrorObjectsKnown:表示孔洞缺少,偏大,偏小,多余的点云块;ErrorObjectsWrongPos:位置错误的点云块* ErrorObjectsUnknownMIT:unknown (missing in test object)* ErrorObjectsUnknownMIR:unknown (missing in reference object)ErrorObjectsFinal := [ErrorObjectsKnown,ErrorObjectsWrongPos,ErrorObjectsUnknownMIT,ErrorObjectsUnknownMIR]*  缺陷点云对象类型ErrorTypesFinal := [ErrorTypesKnown,ErrorTypesWrongPos,gen_tuple_const(|ErrorObjectsUnknownMIT|,6),gen_tuple_const(|ErrorObjectsUnknownMIR|,7)]elseErrorObjectsFinal := []ErrorTypesFinal := []endif* * 6,显示dev_set_window (WindowHandle1)dev_clear_window ()* TestObjectTrans:变换后的被测对象;ErrorObjectsFinal:表示被测对象异常部分的点云块ObjectModelsForVisualization := [TestObjectTrans,ErrorObjectsFinal]VisParamNames := ['point_size','alpha','point_size_0','alpha_0','color_0','intensity_0','color_' + [1:|ErrorTypesFinal|]]VisParamValues := [5.0,0.3,3.0,1.0,'gray','coord_z',subset(ErrorTypesColor,ErrorTypesFinal)]Labels := ['',subset(ErrorTypesText,ErrorTypesFinal)]* visualize_object_model_3d (WindowHandle1, ObjectModelsForVisualization, [], PoseDisplay, VisParamNames, VisParamValues, ['Test object ' + SceneIndex,'Number of errors: ' + NumErrors], Labels, Instructions, PoseOut1)dev_set_window (WindowHandle1)* * Clean up memoryclear_object_model_3d ([TestObject,TestObjectTrans,ErrorObjectsFinal])
endfor
* Clean up memory
clear_object_model_3d (Reference)
clear_sheet_of_light_model (SheetOfLightModelID)
clear_surface_model (SurfaceModelID)

在这里插入图片描述

4,完整程序。

*参考案例库:check_for_holes_sheet_of_light.hdev* 这个例子展示了线结构光模型的用法
* 通过点云表面比较,检查孔洞的缺失,多余,偏大,偏小与错位。* 结果是否对齐显示
DisplayAlignmentResult := false* ------------------1,创建用作参照物的3D对象* 1.1,读取描述3D对象轮廓的视差图。
* Create a sheet-of-light model to collect the disparities
* and set the calibration information for the reconstruction.
* tif文件:标准的位图文件,部分设备生成的深度图,点云数据采用此格式存储
read_image (Disparity, 'sheet_of_light/injection_mold_01_disparity')
get_image_size (Disparity, Width, Height)
* 处理的光条数量(即扫描次数)
NumProfiles := Height
gen_rectangle1 (Rectangle, 0, 0, Height - 1, Width - 1)* 1.2,创建线结构光三维测量模型
create_sheet_of_light_model (Rectangle, [], [], SheetOfLightModelID)
* 相机内参
CameraParam := [0.016,-1250.34,4.65114e-006,4.65e-006,623.43,515.23,1280,1024]
* 相机外参
CameraPose := [0.0013952482819,-0.0025835234583,-0.53764418409,337.80940798,359.84685912,358.46883832,0]
* 光平面在世界坐标系的位姿
LightplanePose := [-0.047567497224,-0.73091602504,0.0016815300297,271.32238394,0.40428170089,359.66058824,0]
* 移动时位姿变化/步(该位姿在世界坐标系)
MovementPose := [-2.5e-005,-1.5e-4,-1.25e-006,0.0,0.0,0.0,0]
* 定义校准模式,决定输出的坐标性类型
set_sheet_of_light_param (SheetOfLightModelID, 'calibration', 'xyz')
* 定义三维坐标输出的单位,m表示米
set_sheet_of_light_param (SheetOfLightModelID, 'scale', 'm')
* 设置相机的内参
set_sheet_of_light_param (SheetOfLightModelID, 'camera_parameter', CameraParam)
* 设置相机的姿态
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)
* 
* Init display
dev_update_off ()
dev_close_window ()
dev_open_window_fit_image (Disparity, 0, 0, 500, 480, WindowHandle1)get_window_extents (WindowHandle1, Row, Column, Width1, Height1)
dev_open_window_fit_image (Disparity, 0, Width1 + 8, 500, 480, WindowHandle2)
set_display_font (WindowHandle1, 16, 'mono', 'true', 'false')
set_display_font (WindowHandle2, 16, 'mono', 'true', 'false')
dev_set_window (WindowHandle1)
* 
* 1.3,定义异常类型对应的文本和颜色
ErrorTypesText := ['unknown','additional hole','missing hole','hole too large','hole too small','wrong position','unknown (missing in test object)','unknown (missing in reference object)']
ErrorTypesColor := ['white','magenta','red','blue','yellow','cyan','white','white']
* 
* Set the disparity image of the reference object
* 1.4,将视差图图像设置到 线结构光测量模型中
set_profile_sheet_of_light (Disparity, SheetOfLightModelID, [])
* * 1.5,获取标准参照物的3D对象
get_sheet_of_light_result_object_model_3d (SheetOfLightModelID, ReferenceOrig)
* 显示原始图
visualize_object_model_3d (WindowHandle1, ReferenceOrig, [], [], ['lut','intensity','disp_pose'], ['color1','coord_z','true'], [], [], [], PoseOut2)
* 去除参照物的背景
select_points_object_model_3d (ReferenceOrig, 'point_coord_z', 0.01, 1, Reference)
* 1.6,显示参考对象(标准物)
visualize_object_model_3d (WindowHandle2,  Reference, [], [], ['lut','intensity','disp_pose'], ['color1','coord_z','true'], [], [], [], PoseOut2)
* Clean up
clear_object_model_3d (ReferenceOrig)
* 
*------------------------
* -----------------------2,创建基于表面的 3D 匹配模型,采样距离与物体直径的比例为:0.02
*-------------------------
create_surface_model (Reference, 0.02, [], [], SurfaceModelID)
* 
* Display reference object
dev_clear_window ()
get_window_extents (WindowHandle1, Row2, Column2, Width2, Height2)
dev_set_part (0, 0, Height2 - 1, Width2 - 1)
Introduction := '这个例子展示了一个校准的'
Introduction[1] := '用于表面比较的线性结构光.'
Introduction[2] := '在这个例子中展示:'
Introduction[3] := '检查孔的位置,数量,大小是否有异常.'
disp_message (WindowHandle1, Introduction, 'window', 12, 12, 'white', 'false')* 2.1,创建标准 3D 模型显示位姿
create_pose (0.0244755,0.0707748,2.10414,-0.0,0.0,-0.0, 'Rp+T', 'gba', 'point', PoseDisplay)
Title := '参考对象(标准物)'
Instructions[0] := 'Rotate: Left button'
Instructions[1] := 'Zoom:   Shift + left button'
Instructions[2] := 'Move:   Ctrl  + left button'* 2.2,显示参考对象
visualize_object_model_3d (WindowHandle2, Reference, [], PoseDisplay, ['lut','intensity'], ['color1','coord_z'], Title, [], Instructions, PoseOut)
* 
* Display the reference object in the second window for comparison with the
* test object
dev_set_window (WindowHandle2)
get_window_extents (WindowHandle2, Row2, Column2, Width2, Height2)
dev_set_part (0, 0, Height2 - 1, Width2 - 1)
dev_clear_window ()
disp_object_model_3d (WindowHandle2, Reference, [], PoseDisplay, ['lut','intensity'], ['color1','coord_z'])
disp_message (WindowHandle2, 'Reference object', 'window', 12, 12, 'black', 'true')
* 
*---------------------------3,查找被测 3D 对象
* Main loop
NumScenes := 6
MaxDist := 0.001
for SceneIndex := 1 to NumScenes by 1dev_set_window (WindowHandle1)dev_clear_window ()disp_message (WindowHandle1, 'Match test object with reference object ...', 'window', 12, 12, 'black', 'true')* 3.1, 读取被测的视差图像read_image (Disparity, 'sheet_of_light/injection_mold_' + SceneIndex$'02d' + '_disparity')* 3.2,复位线结构光模型中的视差图像. 其他的设置保持不变reset_sheet_of_light_model (SheetOfLightModelID)* 3.3,设置需要测量轮廓的视差图set_profile_sheet_of_light (Disparity, SheetOfLightModelID, [])* 3.4,使用线性结构光测量模型中解析出 待检测的 3D 对象get_sheet_of_light_result_object_model_3d (SheetOfLightModelID, TestObjectOrig)* 去除背景select_points_object_model_3d (TestObjectOrig, 'point_coord_z', 0.01, 1, TestObject)clear_object_model_3d (TestObjectOrig)*3.5,显示被测的3D对象点云visualize_object_model_3d (WindowHandle1, TestObject, [], [], ['lut','intensity'], ['color1','coord_z'], [], [], [], PoseOut3)disp_message (WindowHandle1, 'Match test object ' + SceneIndex + ' with reference object...', 'window', 12, 12, 'black', 'true')wait_seconds (1)* 3.6,检测标准 3D 模型 相对于 被测 3D 模型的位姿  find_surface_model (SurfaceModelID, TestObject, 0.02, 0.5, 0, 'false', 'pose_ref_sub_sampling', 1, Pose, Score, NotUsed)* 被测 3D 点云模型相对于标准 3D 模型的位姿pose_invert (Pose, PosesInvert)* 3.7,刚体变化检测对象到参考对象rigid_trans_object_model_3d (TestObject, PosesInvert, TestObjectTrans)* 3.8,显示测试对象对齐后状态
*     disp_object_model_3d (WindowHandle1,TestObjectTrans, [],  PoseDisplay, ['lut','intensity','disp_pose'], ['color1','coord_z','true'])visualize_object_model_3d (WindowHandle1,TestObjectTrans, [],  PoseDisplay, ['lut','intensity','disp_pose'],['color1','coord_z','true'], [], [], [], PoseOut4)if (DisplayAlignmentResult)* ...and together with the reference object (if desired, see above)visualize_object_model_3d (WindowHandle1, [Reference,TestObjectTrans], [], PoseDisplay, ['color_0','color_1'], ['forest green','gray'], 'Result of surface based matching:\nTest object (gray) and reference (green)', [], [], PoseOut)endif* *---------------------4,分析被测对象与参考 3D 对象的点云差异* 4.1,----情况1:被测 3D 对象点云缺失(有额外的孔洞)----* 4.1.1,测量3D参考对象与被测3D对象的各点的距离distance_object_model_3d (Reference, TestObjectTrans, [], 0.0, [], [])* 4.1.2,筛选出被测 3D 对象缺少的点云select_points_object_model_3d (Reference, '&distance', MaxDist, 1, ObjectModel3DThresholded)ToClear := ObjectModel3DThresholded* 4.1.3,显示被测 3D 对象相对参照 3D 对象缺失的点云disp_object_model_3d (WindowHandle1, ObjectModel3DThresholded, [], [], ['lut','intensity','disp_pose'], ['color1','coord_z','true'])* 4.1.4,处理 被测 3D 对象相对参照 3D 对象缺失的点云get_object_model_3d_params (ObjectModel3DThresholded, 'num_points', NumPoints)if (NumPoints > 0)* Calculate connected components, the distance threshold should* be greater than the distance between two scan lines (> MovementPose[1])connection_object_model_3d (ObjectModel3DThresholded, 'distance_3d', 0.001, ObjectModel3DConnected)ToClear := [ToClear,ObjectModel3DConnected]* 计算测试对象上缺少的点云(保留主要部分,去掉噪声)select_object_model_3d (ObjectModel3DConnected, 'num_points', 'and', 200, 1000000, SurfacePointsMissingInTestObject)elseSurfacePointsMissingInTestObject := []endif* Clean upclear_object_model_3d (ToClear)* *----4.2,情况2:被测 3D 对象点云多余(缺少孔洞)----* 4.2.1,反过来测量被测3D 对象与 参考3D 对象的各点距离,求出被测3D 对象多出的点云distance_object_model_3d (TestObjectTrans, Reference, [], 0.0, [], [])* 4.2.2,筛选出被测 3D 对象多出的点云块select_points_object_model_3d (TestObjectTrans, '&distance', MaxDist, 1, ObjectModel3DThresholded)ToClear := ObjectModel3DThresholdedtry* Calculate connected components, the distance threshold should* be greater than the distance between two scan lines (> MovementPose[1])connection_object_model_3d (ObjectModel3DThresholded, 'distance_3d', 0.001, ObjectModel3DConnected)ToClear := [ToClear,ObjectModel3DConnected]* ,处理 被测 3D 对象相对参照 3D 对象多出的点云select_object_model_3d (ObjectModel3DConnected, 'num_points', 'and', 200, 1000000, SurfacePointsMissingInReference)catch (Exception)SurfacePointsMissingInReference := []endtry* Clean upclear_object_model_3d (ToClear)* *---------------------------------5,对被测物的异常点云块进行处理* Collect and classify errors* 5.1,被测3D 对象缺少,多出的点云部分集合ErrorObjects := [SurfacePointsMissingInTestObject,SurfacePointsMissingInReference]* 异常点云块提示信息ErrorSources := [gen_tuple_const(|SurfacePointsMissingInTestObject|,'missing in test'),gen_tuple_const(|SurfacePointsMissingInReference|,'missing in reference')]ErrorTypes := []gen_empty_obj (ErrorPatterns)* 异常的点云块数量NumErrors := |ErrorObjects|* 对异常部分点云块进行处理if (NumErrors > 0)for ErrorIndex := 0 to NumErrors - 1 by 1* 异常的点云ErrorObject := ErrorObjects[ErrorIndex]* 异常点云的文本信息ErrorSource := ErrorSources[ErrorIndex]* * 5.2,为异常的点云中拟合出一个通过这些点的Region* a plane through the points and then projecting the points into this plane.create_region_from_error_points (Region, ErrorObject)* * 5.3,分析所得到的二维拟合图形的形状 (the region)fill_up (Region, RegionFillUp)difference (RegionFillUp, Region, RegionDifference)circularity (Region, CircularityRegDilation)circularity (RegionFillUp, CircularityRegFillUp)circularity (RegionDifference, CircularityRegDifference)* area_center (Region, AreaRegDilation, Row1, Column1)area_center (RegionFillUp, AreaRegFillUp, Row1, Column1)area_center (RegionDifference, AreaRegDifference, Row1, Column1)* * 5.4,给异常点云块分类,确定对应的异常类型MinCircularity := 0.7if (CircularityRegDilation > MinCircularity and real(AreaRegDifference) / AreaRegDilation < 0.1)if (ErrorSource == 'missing in test')* 5.4.1,原因1:被测3D 对象孔洞多余ErrorType := 1else* 5.4.2,原因2:被测3D 对象孔洞缺少ErrorType := 2endifelseif (CircularityRegFillUp > MinCircularity and CircularityRegDifference > MinCircularity and real(AreaRegDifference) / AreaRegDilation > 0.1)if (ErrorSource == 'missing in test')* 5.4.3,原因3:被测 3D 对象 孔洞偏大ErrorType := 3else* 5.4.4,原因4:被测 3D 对象 孔洞偏小ErrorType := 4endifelse* 5.4.0,原因0:未知原因ErrorType := 0endif*ErrorType:0 原因未知,1被测 3D 对象孔洞多余,2 被测 3D 对象 缺少孔洞*           3:被测 3D 对象孔洞偏大, 4 被测 3D 对象孔洞偏小*           5 wrong position*          6 unknown (missing in test object)*          7 unknown (missing in reference object)ErrorTypes[ErrorIndex] := ErrorType* 连接由异常点云块拟合出来的异常区域concat_obj (ErrorPatterns, Region, ErrorPatterns)endfor* 5.5,对表示异常的点云进行分类* 5.5.1,类型1:表示缺失,多余,偏大,偏小类型的点云对象MaskKnown := ErrorTypes [!=] 0* 注意如果MaskKnown的数组长度与ErrorObjects数组长度不一致将无法执行select_mask* select_mask执行的结果为MaskKnown成员为true则保留ErrorObjects对应位置的对象ErrorObjectsKnown := select_mask(ErrorObjects,MaskKnown)ErrorTypesKnown := select_mask(ErrorTypes,MaskKnown)* 5.5.2,类型2:表示孔洞错位的点云对* 5.5.2.1,被测3D对象缺少的点云(这些点云未明确错误类型)MaskUnknownMIT := ErrorTypes [==] 0 and ErrorSources [==] 'missing in test'ErrorObjectsUnknownMIT := select_mask(ErrorObjects,MaskUnknownMIT)*  5.5.2.2,被测3D对象多余的点云(这些未明确错误类型)MaskUnknownMIR := ErrorTypes [==] 0 and ErrorSources [==] 'missing in reference'ErrorObjectsUnknownMIR := select_mask(ErrorObjects,MaskUnknownMIR)* ErrorObjectsWrongPos := []ErrorTypesWrongPos := []* MergedMIT := gen_tuple_const(|ErrorObjectsUnknownMIT|,false)MergedMIR := gen_tuple_const(|ErrorObjectsUnknownMIR|,false)* 对未明确异常原因的点云块进一步进行分类if (|ErrorObjectsUnknownMIT| > 0 and |ErrorObjectsUnknownMIR| > 0)for IndexMIT := 0 to |ErrorObjectsUnknownMIT| - 1 by 1if (MergedMIT[IndexMIT])continueendiffor IndexMIR := 0 to |ErrorObjectsUnknownMIR| - 1 by 1if (MergedMIR[IndexMIR])continueendif* Test if there are symmetric error objects* The parameter MaxHoleDiameter is used to speed up the search and to* make it more robust, because we are only interested in symmetric* error objects that are not further apart from each other than* the size of a hole.*判断是否有对称的错误对象,如果是则认为是孔洞位置错误*参数MaxHoleDiameter是用来加快搜索和*使它更健壮,因为我们只对对称感兴趣错误对象之间的距离小于洞的大小MaxHoleDiameter := 0.02*表示孔洞位置偏离的点云块对*=======*======= 判断被测物缺少的点云块与多余的点云块的对称性,如果对称性高则说明两个点云对称,即可判定孔洞错位test_symmetry_object_model_3d (ErrorObjectsUnknownMIT[IndexMIT], ErrorObjectsUnknownMIR[IndexMIR], MaxHoleDiameter, Rating)if (Rating > 70)* Merge the two symmetric errors into a new error object* 合并两个对称点云get_object_model_3d_params (ErrorObjectsUnknownMIT[IndexMIT], 'point_coord_x', X1)get_object_model_3d_params (ErrorObjectsUnknownMIT[IndexMIT], 'point_coord_y', Y1)get_object_model_3d_params (ErrorObjectsUnknownMIT[IndexMIT], 'point_coord_z', Z1)get_object_model_3d_params (ErrorObjectsUnknownMIR[IndexMIR], 'point_coord_x', X2)get_object_model_3d_params (ErrorObjectsUnknownMIR[IndexMIR], 'point_coord_y', Y2)get_object_model_3d_params (ErrorObjectsUnknownMIR[IndexMIR], 'point_coord_z', Z2)* 根据点 生成 3D 对象gen_object_model_3d_from_points ([X1,X2], [Y1,Y2], [Z1,Z2], ObjectModel3D)* Remember the new objectErrorObjectsWrongPos := [ErrorObjectsWrongPos,ObjectModel3D]* 表示错位的孔洞ErrorTypesWrongPos := [ErrorTypesWrongPos,5]* Mark merged objectMergedMIT[IndexMIT] := trueMergedMIR[IndexMIR] := truebreakendifendforendfor* Clean up* MergedMIT:表示错位的点云,如果元素为true则是孔洞错位,否则为未知*5.5.3,类型3:unknown (missing in test object)for IndexMIT := |MergedMIT| - 1 to 0 by -1if (MergedMIT[IndexMIT])* 从表示未知原因的异常点云块集合中去除错位的点云块clear_object_model_3d (ErrorObjectsUnknownMIT[IndexMIT])tuple_remove (ErrorObjectsUnknownMIT, IndexMIT, ErrorObjectsUnknownMIT)endifendfor* 5.5.4,unknown (missing in reference object)for IndexMIR := |MergedMIR| - 1 to 0 by -1if (MergedMIR[IndexMIR])clear_object_model_3d (ErrorObjectsUnknownMIR[IndexMIR])tuple_remove (ErrorObjectsUnknownMIR, IndexMIR, ErrorObjectsUnknownMIR)endifendforendif* * 5.6,表示缺陷的点云对象汇总* ErrorObjectsKnown:表示孔洞缺少,偏大,偏小,多余的点云块;ErrorObjectsWrongPos:位置错误的点云块* ErrorObjectsUnknownMIT:unknown (missing in test object)* ErrorObjectsUnknownMIR:unknown (missing in reference object)ErrorObjectsFinal := [ErrorObjectsKnown,ErrorObjectsWrongPos,ErrorObjectsUnknownMIT,ErrorObjectsUnknownMIR]*  缺陷点云对象类型ErrorTypesFinal := [ErrorTypesKnown,ErrorTypesWrongPos,gen_tuple_const(|ErrorObjectsUnknownMIT|,6),gen_tuple_const(|ErrorObjectsUnknownMIR|,7)]elseErrorObjectsFinal := []ErrorTypesFinal := []endif* * 6,显示dev_set_window (WindowHandle1)dev_clear_window ()* TestObjectTrans:变换后的被测对象;ErrorObjectsFinal:表示被测对象异常部分的点云块ObjectModelsForVisualization := [TestObjectTrans,ErrorObjectsFinal]VisParamNames := ['point_size','alpha','point_size_0','alpha_0','color_0','intensity_0','color_' + [1:|ErrorTypesFinal|]]VisParamValues := [5.0,0.3,3.0,1.0,'gray','coord_z',subset(ErrorTypesColor,ErrorTypesFinal)]Labels := ['',subset(ErrorTypesText,ErrorTypesFinal)]* visualize_object_model_3d (WindowHandle1, ObjectModelsForVisualization, [], PoseDisplay, VisParamNames, VisParamValues, ['Test object ' + SceneIndex,'Number of errors: ' + NumErrors], Labels, Instructions, PoseOut1)dev_set_window (WindowHandle1)* * Clean up memoryclear_object_model_3d ([TestObject,TestObjectTrans,ErrorObjectsFinal])
endfor
* Clean up memory
clear_object_model_3d (Reference)
clear_sheet_of_light_model (SheetOfLightModelID)
clear_surface_model (SurfaceModelID)

本地函数:create_region_from_error_points (Region, ErrorObject)

拟合出一个通过点云所有点的平面

* 获取 3D 点云错误对象
get_object_model_3d_params (ErrorObject, 'point_coord_x', X)
get_object_model_3d_params (ErrorObject, 'point_coord_y', Y)
get_object_model_3d_params (ErrorObject, 'point_coord_z', Z)
* 确定一个通过所有点的近似平面的法向量
fit_plane (X, Y, Z, NX, NY, NZ, C)
hnf_to_hom_mat3d (NX, NY, NZ, C, HomMat3D)
* Project all points into the plane (just set Qz to zero)
affine_trans_point_3d (HomMat3D, X, Y, Z, Qx, Qy, Qz)
* Create a region from the 2D points
* - First, determine the necessary resolution
* 创建分类器
create_class_knn (2, KNNHandle)
Seq := [0:2:2 * |Qx| - 2]
Features[Seq] := Qx
Features[Seq + 1] := Qy
* 添加样本
add_sample_class_knn (KNNHandle, Features, 0)
* 训练分类器
train_class_knn (KNNHandle, [], [])
set_params_class_knn (KNNHandle, ['method','k'], ['neighbors_distance',4])
classify_class_knn (KNNHandle, Features, Result, Rating)
Seq4 := [0:4:4 * |Qx| - 4]
DistancesClosest := Rating[Seq4 + 1]
DistancesAway := Rating[Seq4 + 3]
clear_class_knn (KNNHandle)
Resolution := median(DistancesClosest) / sqrt(2)
DilationRad := median(DistancesAway) / Resolution
QxMin := min(Qx)
QxMax := max(Qx)
QyMin := min(Qy)
QyMax := max(Qy)
DQx := QxMax - QxMin
DQy := QyMax - QyMin
* - Then create the region from the appropriately scaled point coordinates
Rows := int((Qy - QyMin) / Resolution + 0.5)
Cols := int((Qx - QxMin) / Resolution + 0.5)
gen_region_points (RegionRaw, Rows, Cols)
* Dilate the region to fill up gaps between the points
dilation_circle (RegionRaw, Region, DilationRad)
return ()

本地函数: test_symmetry_object_model_3d

评价两块点云的对称性

* OM1:被测 3D 对象缺少的点云块
* OM2:被测 3D 对象多余的点云块
Inspection := false
* 确定对称平面的假设
get_object_model_3d_params (OM1, 'point_coord_x', X1)
get_object_model_3d_params (OM1, 'point_coord_y', Y1)
get_object_model_3d_params (OM1, 'point_coord_z', Z1)
get_object_model_3d_params (OM2, 'point_coord_x', X2)
get_object_model_3d_params (OM2, 'point_coord_y', Y2)
get_object_model_3d_params (OM2, 'point_coord_z', Z2)
Center1 := [mean(X1),mean(Y1),mean(Z1)]
Center2 := [mean(X2),mean(Y2),mean(Z2)]
* 125*125:=96*96+75*75+28*28
Distance := sqrt(sum((Center1 - Center2) * (Center1 - Center2)))
if (Distance > MaxDistance)* 等级Rating := 0return ()
endif
a:=[1,34,38]
b:=sqrt(sum(a*a))
NSymm := Center2 - Center1
NSymm := NSymm / sqrt(sum(NSymm * NSymm))
PSymm := Center1 + 0.5 * (Center2 - Center1)
CSymm := sum(NSymm * PSymm)
if (CSymm < 0)NSymm := -NSymmCSymm := -CSymm
endif
hnf_to_hom_mat3d (NSymm[0], NSymm[1], NSymm[2], CSymm, HomMat3D)
hom_mat3d_to_pose (HomMat3D, Pose)
* 
* 
* Test hypothesis for symmetry plane
* 
* Transform all points into the coordinate system in which the
* symmetry plane is the plane z=0
hom_mat3d_invert (HomMat3D, HomMat3DInvert)
affine_trans_point_3d (HomMat3DInvert, X1, Y1, Z1, X1T, Y1T, Z1T)
affine_trans_point_3d (HomMat3DInvert, X2, Y2, Z2, X2T, Y2T, Z2T)
* 
* Create first KNN classifier to determine distance to closest points
create_class_knn (3, KNN1)
Seq1 := [0:3:3 * |X1T| - 3]
Features1 := gen_tuple_const(3 * |X1T|,0)
Features1[Seq1] := X1T
Features1[Seq1 + 1] := Y1T
Features1[Seq1 + 2] := Z1T
add_sample_class_knn (KNN1, Features1, 0)
train_class_knn (KNN1, [], [])
* 
* Create second KNN classifier to determine distance to closest points
create_class_knn (3, KNN2)
Seq2 := [0:3:3 * |X2T| - 3]
Features2 := gen_tuple_const(3 * |X2T|,0)
Features2[Seq2] := X2T
Features2[Seq2 + 1] := Y2T
Features2[Seq2 + 2] := Z2T
add_sample_class_knn (KNN2, Features2, 0)
train_class_knn (KNN2, [], [])
set_params_class_knn (KNN2, ['method','k'], ['neighbors_distance',1])
* 
* Determine the distance to the closest point in the other
* set of points for all points mirrored at the hypothedical
* symmetry plane. Note, mirroring is ease because we have
* transformed the points into the coordinate system in which
* the symmetry plane is the plane z=0. So mirroring is
* just switching the sign of the z coordinate.
* 
* - Determine mean distance within point set 1
set_params_class_knn (KNN1, ['method','k'], ['neighbors_distance',2])
classify_class_knn (KNN1, Features1, Result1, Rating1)
Rating1 := subset(Rating1,[1:2:|Rating1| - 1])
* - Determine mean distance within point set 2
set_params_class_knn (KNN2, ['method','k'], ['neighbors_distance',2])
classify_class_knn (KNN2, Features2, Result2, Rating2)
Rating2 := subset(Rating2,[1:2:|Rating2| - 1])
* - Determine mean distance of mirrored points from point set 1 within point set 2
set_params_class_knn (KNN1, ['method','k'], ['neighbors_distance',1])
Features1[Seq1 + 2] := -Z1T
classify_class_knn (KNN2, Features1, Result1In2, Rating1In2)
* - Determine mean distance of mirrored points from point set 2 within point set 1
Features2[Seq2 + 2] := -Z2T
classify_class_knn (KNN1, Features2, Result2In1, Rating2In1)
* 
* 
MeanRating1 := mean(Rating1)
StdDevRating1 := deviation(Rating1)
MeanRating2 := mean(Rating2)
StdDevRating2 := deviation(Rating2)
* 
PercBadRating2In1 := sum(Rating2In1 [>] MeanRating1 + 3 * StdDevRating1) / real(|Rating2In1|) * 100.0
PercBadRating1In2 := sum(Rating1In2 [>] MeanRating2 + 3 * StdDevRating2) / real(|Rating1In2|) * 100.0
Rating := 100.0 - mean([PercBadRating2In1,PercBadRating1In2])
* 
if (Inspection)dev_get_window (WindowHandle)gen_object_model_3d_from_points (X1T, Y1T, Z1T, OM1T)gen_object_model_3d_from_points (X2T, Y2T, Z2T, OM2T)gen_object_model_3d_from_points (X1T, Y1T, -Z1T, OM1TM)gen_object_model_3d_from_points (X2T, Y2T, -Z2T, OM2TM)visualize_object_model_3d (WindowHandle, [OM1T,OM2TM,OM2T], [], [], ['color_0','color_1','color_2','disp_pose'], ['red','green','gray','true'], 'Rating: ' + Rating, [], [], PoseOut)clear_object_model_3d ([OM1T,OM2T,OM1TM,OM2TM])
endif
* 
* Clean up
clear_class_knn (KNN1)
clear_class_knn (KNN2)
* 
return ()
http://www.xdnf.cn/news/9563.html

相关文章:

  • 第五章 面向对象(进阶)
  • CC工具箱2.0.6更新_免费_150+工具
  • 智能外呼机器人——客户筛选
  • 桃黑黑反斗战
  • Doris主键模型使用异步物化视图
  • Linux——数据链路层
  • 仿DeepSeek AI问答系统完整版(带RAG本地知识库+联网搜索+深度思考) +springboot+vue3
  • JS手写代码篇---Pomise.race
  • 2024 CKA模拟系统制作 | Step-By-Step | 11、题目搭建-查看可用节点数量
  • Mysql基础增删改查语句
  • XCTF-web-file_include
  • 智慧财务系统:企业数字化转型的核心引擎
  • [yolov11改进系列]基于yolov11引入混合标准卷积与深度可分离卷积GSConv用于轻量化网络的python源码+训练源码
  • Android获取设备信息
  • github actions入门指南
  • .NET 9正式发布,亮点是.NET Aspire和AI
  • Linux `vi/vim` 编辑器深度解析与高阶应用指南
  • Golang | 搜索哨兵-对接分布式gRPC服务
  • vue修改配置文件.env.development不生效
  • 2025-05-28 学习记录--Python-文件
  • 对象检测新纪元:D-FINE 模型超越 YOLO,带来更精准的实时检测!
  • 6.2 Q1|哈尔滨医科大学GBD发文 | 1990 年至 2019 年颗粒物污染导致的中风全球趋势和负担
  • Python后端开发实战:从0到1搭建高可用API服务
  • 医疗器械企业批记录数字化转型实操指南
  • LeetCode hot100-6
  • C# 基于 Windows 系统与 Visual Studio 2017 的 Messenger 消息传递机制详解:发布-订阅模式实现
  • Python 包管理工具 uv的一些常用指令
  • AWS 创建VPC 并且添加权限控制
  • CloudCompare——点云统计滤波
  • element ui 表格 勾选复选框后点击分页不保存之前的数据问题