激光三角測量標定與應用

文章目錄

      • 1,介紹。
      • 2,技術原理
      • 3,類型。
        • 3.1,直射式
        • 3.2,斜射式
        • 3.3,兩種三角位移傳感器特性的比較
      • 4,什么是光片?
      • 5,主要的算子。
        • 1,create_sheet_of_light_model
        • 2,measure_profile_sheet_of_light
        • 3,get_sheet_of_light_result
      • 6,三角標定測量代碼詳解。
        • 6.1, 相機標定參數預設置。
        • 6.2,標定相機。
        • 6.3,計算LightPanelPose(光平面的位姿)。
        • 6.4,計算MovementPose。
        • 6.5,激光三角應用。
      • 7,完整代碼。

1,介紹。

三角激光測量是一種位移測量方法,其最大的優點是非接觸性測量。通過三維激光掃描獲取的圖像紋理豐富,分辨率高,具有更好的深度和范圍信息,能更好的滿足微小產品的視覺檢測需求,故在工業應用和基礎科學研究中被廣泛使用,對微小產品表面平面度測量技術的研究就顯得尤為重要。

2,技術原理

激光器發出的激光照射到被測物體表面,激光在被測物表面形成反射,返回到成像器,從而計算出物體的高度。由于入射光和反射光構成一個三角形,所以這種方法被稱為三角測量法。如果激光線投射到物體表面的高度不同,則發光線條不會是一條直線,而是一條表現物體表面高度輪廓的線。通過這條輪廓線,就可以得到物體表面的高度差。

視差圖中的每一行存儲一條輪廓線的值,這里的相機必須是固定的,這樣每一行掃描到的輪廓線才能和視差圖中對應的行平行。而被測物體應當是運動,這樣才能獲得完整的輪廓線。如果系統未經過校準,則不會返回點在世界坐標系的三維坐標,但是仍然可以得到視差圖像,以及測量結果的置信分數。注意,這里的視差圖像有所不同,雙目視覺中的視差圖像體現了左右圖中對應的像素灰度值差,而片光測量結果的視差圖中保存的是被檢測到的輪廓線的子像素。

3,類型。

按照發射角度的不同,激光三角法按入射光線與被測對象表面法線方向所成的角度分為直射式與斜射式。

3.1,直射式

激光器發出的光線,經會聚透鏡聚焦后垂直入射到被測物體表面,物體移動或表面變化導致入射光點沿入射光軸移動。接收透鏡接收來自入射光點處的散射光,并將其成像在光點位置探測器(如PSD,CCD)敏感面上,但由于傳感器激光光束與被測面垂直,因此只有一個準確的調焦位置,其余位置的像都處于不同程度的離焦狀態。

在這里插入圖片描述

若光點在成像面上的位移為x`,利用相似三角形各邊之間的比例關系,可以求出背側面的位移:

x = a x ‘ s i n θ 2 b s i n θ ? x ‘ s i n ( θ 1 ? θ 2 ) x=\frac{ax^`sin\theta_2}{bsin\theta-x^`sin(\theta_1-\theta_2)} x=bsinθ?xsin(θ1??θ2?)axsinθ2??
式中,a為激光束光軸和接收光軸的交點到接收透鏡前主面的距離;b為接收透鏡后主面到成像面中心點的距離; θ 1 \theta_1 θ1?為激光束光軸與接收透鏡光軸之間的夾角; θ 2 \theta_2 θ2?為探測器與接收透鏡光軸之間的夾角。

3.2,斜射式

激光器發出的光和被測面的法線方向成一定角度入射到被測面上,同樣用接收透鏡接收光點在被測面的散射光或反射光。

若光點的像在探測器敏感面上移動x`,利用相似三角形的比例關系,則物體表面沿法線方向的移動距離為:

x = a x ‘ s i n θ 3 c o s θ 1 b s i n ( θ 1 + θ 2 ) ? x ‘ s i n ( θ 1 + θ 2 + θ 3 ) x=\frac{ax^`sin\theta_3cos\theta_1}{bsin(\theta_1+\theta_2)-x^`sin(\theta_1+\theta_2+\theta_3)} x=bsin(θ1?+θ2?)?xsin(θ1?+θ2?+θ3?)axsinθ3?cosθ1??
式中, θ 1 \theta_1 θ1?為激光束光軸與被測面的法線夾角; θ 2 \theta_2 θ2?為成像透鏡與被測面的法線夾角; θ 3 \theta_3 θ3?為探測器光軸與成像透鏡光軸之間的夾角。

3.3,兩種三角位移傳感器特性的比較

基于三角測量法的傳感器稱為激光三角位移傳感器,具體可以分為直射式激光三角位移傳感器和斜射式激光三角位移傳感器。這兩種傳感器都可以對被測面進行高精度、高速度的非接觸式測量,但比較起來有以下幾點區別:

  1. 斜射式可以接收來自被測物體的正反射光,比較適合測量表面接近鏡面的物體。直射式由于其接收散射光的特點,適合于測量散射性能好的表面。
  2. 直射式光斑較小,光強集中,不會因被測面不垂直而擴大光斑,而且一般體積比較小。斜射式傳感器分辨率高于直射式,但他的測量范圍較小,體積較大。

4,什么是光片?

光片技術的基本思想是將一條細的發光直線投影到要重建的物體的表面上,然后用相機對投影線進行成像,光片技術也稱線結構光。
在這里插入圖片描述

實物圖像

在這里插入圖片描述

?激光線的投影構成了一個稱為光平面或光片的平面。相機的光軸與光平面形成一個角度 α \alpha α,稱為三角測量角。激光線與相機視圖之間的交點取決于被測物體的高度。因此,如果激光線投射到的物體的高度不同,則該線不會稱為直線,而是表示物體的輪廓。

5,主要的算子。

1,create_sheet_of_light_model

用于光片技術(Sheet-of-Light,亦稱之為線性結構光)3D測量的關鍵算子,主要用于通過激光三角測量技術重建物體表面輪廓。該算子通過分析激光線在物體表面的變形來獲取高度信息,適用于工業檢測、逆向工程等領域。

?核心參數?:

參數類型說明典型值
ProfileRegion輸入包含處理輪廓的圖像ROI區域最小外接矩形
GenParamName輸入可調整的通用參數名稱'min_gray’等13種選項
GenParamValue輸入對應參數的值默認50
SheetOfLightModelID輸出光片模型句柄用于后續操作

?GenParamName可選值?:

  • ‘calibration’:校準相關參數

  • ‘method’:輪廓提取方法

  • ‘min_gray’:定義輪廓提取的最小灰度閾值,低于此值的像素將被忽略(默認50)。

  • ‘score_type’:評分類型

  • ‘scale_x/y/z’:各軸向縮放因子

  • ‘num_profiles’:指定處理的輪廓數量,影響多幀平均和運動補償效果。靜態測量:設置為1(單幀處理),運動物體:根據運動速度設置(如傳送帶場景常用50-500)

標定要求與area_scan_polynomial模型

線結構光系統標定必須使用area_scan_polynomial相機模型,原因如下:

  1. ?高精度需求?:多項式模型使用K1-K3三個參數描述徑向畸變,P1-P2兩個參數描述切向畸變,比division單參數模型精度更高
  2. ?畸變校正?:激光三角測量對鏡頭畸變敏感,polynomial模型能更好校正廣角鏡頭的桶形/枕形畸變
  3. ?系統架構?:標定過程需要相機內外參和激光平面參數,多項式模型提供更完整的參數空間
2,measure_profile_sheet_of_light

光片測量技術(Sheet-of-Light)中的關鍵操作,主要用于激光條紋剖面數據的精確提取與分析。其核心功能與特性如下:

一、功能定位

  1. ?核心作用?

    • 從光片模型生成的圖像中提取激光條紋的亞像素級剖面數據。
    • 輸出剖面點的坐標和灰度值,用于后續三維重建或缺陷檢測。
  2. ?技術關聯?

    • 需配合create_sheet_of_light_model創建的光片模型句柄使用。

二、參數解析

參數類型關鍵參數作用說明
?輸入參數?SheetOfLightHandle已創建的光片模型句柄2
ProfileImage包含激光條紋的輸入圖像
?輸出參數?Profile提取的剖面點坐標序列
GrayValues對應點的灰度值數組

三、典型應用場景

  1. ?工業三維測量?

    • 金屬零件表面輪廓重建(如連接桿的深度測量)
    • 注塑模具孔洞檢測(通過剖面灰度突變分析)
  2. ?流程示例?

    halconCopy Code* 創建光片模型
    create_sheet_of_light_model(ProfileRegion, ['min_gray'], [80], SheetOfLightHandle)* 處理單幀圖像
    read_image(ProfileImage, 'laser_profile_01.png')
    measure_profile_sheet_of_light(ProfileImage, SheetOfLightHandle, Profile, GrayValues)
    

四、性能優化建議

  1. ?參數調優?
    • 通過set_sheet_of_light_param調整'profile_width'(推薦3-10像素)提升條紋定位精度
    • 設置'min_gray'過濾環境光干擾
  2. ?硬件協同?
    • 使用高動態范圍相機避免激光過曝
    • 標定階段需保證激光平面與相機視角夾角>30°

該算子是實現激光三角測量三維重建的核心環節,其精度直接影響最終測量結果。

3,get_sheet_of_light_result

是光片測量技術(Sheet-of-Light)的核心數據提取接口,用于獲取線結構光三維測量的標定或未標定結果。其功能特性與使用方法如下:

一、核心功能

  1. ?數據輸出類型?

    • 支持5種結果類型通過
      參數指定:
      • 'disparity':未標定的視差圖像(亞像素行坐標)
      • 'score':條紋匹配質量評分(依賴'score_type'參數)
      • 'x'/'y'/'z':標定后的三維坐標點云

二、參數詳解

參數類別參數名作用說明
?輸入參數?SheetOfLightModelID已初始化的光片模型句柄
ResultName指定輸出數據類型(默認'disparity'
?輸出參數?ResultValue根據ResultName返回對應數據

三、典型應用場景

  1. ?工業三維檢測?
    • 使用'z'結果進行零件高度公差驗證
    • 通過'score'分析激光條紋質量,識別表面缺陷
  2. ?代碼示例?
halconCopy Code* 獲取標定后的三維坐標
get_sheet_of_light_result(ResultZ, SheetOfLightHandle, 'z')
* 可視化Z軸深度圖
dev_display(ResultZ)

6,三角標定測量代碼詳解。

6.1, 相機標定參數預設置。
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)
dev_set_draw ('margin')
dev_set_line_width (3)
dev_set_color ('lime green')
dev_set_lut ('default')
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
* 
* -------
* Part 1: 執行相機的標定
* -------
* 
* 1.1,默認的相機內參
StartParameters := [0.0125,0.0,0.0,0.0,0.0,0.0,0.000006,0.000006,376.0,120.0,752,240]* 1.2,標定板描述文件
* caltab_30mm.descr':Distance between mark centers [meter]: 0.00375
CalTabDescription := 'caltab_30mm.descr'* 1.3,標定板的厚度(單位:m)
CalTabThickness := .00063* 1.4,標定板圖像數量
NumCalibImages := 20
* 
* Initialize a calibration data model
create_calib_data ('calibration_object', 1, 1, CalibDataID)* 1.4,設置標定參數
* 'area_scan_polynomial':復雜畸變、需要亞像素級精度。至少需要15張標定圖像。
* 'division':至少需要5張標定圖像。
* 線結構光系統標定必須使用`area_scan_polynomial`相機模型
set_calib_data_cam_param (CalibDataID, 0, 'area_scan_polynomial', StartParameters)
set_calib_data_calib_object (CalibDataID, 0, CalTabDescription)

釋疑點:
area_scan_polynomialarea_scan_division是兩種不同的面陣相機畸變校正模型,其核心差異可通過以下對比體現:

. 參數結構與畸變建模能力

屬性division模型polynomial模型
?核心參數?單參數Kappa描述徑向畸變多參數組合(K1-K3徑向+P1-P2切向畸變)
?畸變類型?僅徑向畸變(桶形/枕形)徑向畸變 + 切向畸變 + 透視投影畸變6
?光學中心位置?固定在圖像中心可自定義中心位置

  • 適用場景對比
  1. ?division模型優勢?
    • 計算速度快(直接數學反演即可完成畸變校正)
    • 標定穩定性高(尤其適用于少量標定圖像或視野覆蓋不全的情況)
    • 典型應用:標準工業鏡頭(畸變率<5%)的場景
  2. ?polynomial模型優勢?
    • 支持高階非線性畸變校正(如廣角鏡頭/魚眼鏡頭的復雜畸變)
    • 可實現亞像素級精度(適用于超高精度測量需求)
    • 典型應用:醫療內窺鏡、大視場角工業檢測等場景

  • Halcon實現差異
  1. ?初始化參數示例?

    halconCopy Code* division模型參數示例
    CameraParamDivision := ['area_scan_division', 0.012, 0, 0.00000375, 0.00000375, 640, 480, 1280, 960]* polynomial模型參數示例
    CameraParamPoly := ['area_scan_polynomial', 0.016, 0.000005, 0.000005, 320, 240, 640, 480, 0.1, -0.05, 0.001]
    
    • polynomial模型參數包含畸變多項式系數(如K1-K3、P1-P2)且支持自定義光學中心坐標
  2. ?標定效率?

    指標division模型polynomial模型
    標定數據需求≥5張標定圖像8≥15張標定圖像
    計算耗時約1-2秒(典型值)約5-15秒(迭代計算)

  • 選型建議
場景特征推薦模型
簡單畸變、實時性要求高division模型
復雜畸變、需要亞像素級精度polynomial模型
廣角鏡頭(視場角>60°)polynomial模型

實際項目中建議先用division模型快速驗證系統可行性,若精度不達標則切換至polynomial模型進行精細標定。


6.2,標定相機。
* 1.5,標定圖像(包含各個水平角度,傾斜角度,不同位置但是需要全部在視野內的圖像)
* Collect mark positions and estimated poses for all
* calibration images
for Index := 1 to NumCalibImages by 1read_image (Image, 'sheet_of_light/connection_rod_calib_' + Index$'.2')dev_display (Image)* 后續標定板處于不同位置所對應的位姿與該索引對應,該索引不必從0開始find_calib_object (Image, CalibDataID, 0, 0, Index, [], [])get_calib_data_observ_points (CalibDataID, 0, 0, Index, Row, Column, _Index, Pose)get_calib_data_observ_contours (Contours, CalibDataID, 'caltab', 0, 0, Index)dev_set_color ('green')dev_display (Contours)gen_cross_contour_xld (Cross, Row, Column, 6, 0.785398)dev_set_color ('yellow')dev_display (Cross)
endfor
* 
* 1.6,執行標定
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 ()

注意點:

? 標定板的位置可以傾斜,旋轉,但必須在相機視野內。

在這里插入圖片描述


6.3,計算LightPanelPose(光平面的位姿)。
 * 2.1,獲取世界坐標系在相機坐標系的位姿Index := 19get_calib_data (CalibDataID, 'calib_obj_pose', [0,Index], 'pose', CalTabPose)* 相機的位姿即世界坐標系在相機坐標系的位姿set_origin_pose (CalTabPose, 0.0, 0.0, CalTabThickness, CameraPose)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)disp_message (WindowHandle, 'World coordinate system', 'window', 12, 12, 'black', 'true')disp_continue_message (WindowHandle, 'black', 'true')stop ()

在這里插入圖片描述

在這里插入圖片描述

* 2.2,獲取臨時坐標系在相機坐標系的位置(此時的標定板相對于Index:=19的標定板旋轉了90度)
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 ()

在這里插入圖片描述

在這里插入圖片描述

read_image (ProfileImage1, 'sheet_of_light/connection_rod_lightline_019.png')* 2.3,計算索引為19被測物體(位于世界坐標系)激光輪廓線點在z=0的世界坐標系中的坐標
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
* 

ProfileImage1
在這里插入圖片描述

* 2.4,計算索引為20位于被測物體(位于臨時坐標系)激光輪廓線點在z=0的世界坐標系中的坐標
* Compute the 3D coordinates of the light line points
* in the plane z=0 of the TCS
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, '為了成功處理,輪廓需要是大致水平!\n程序將退出.', 'window', 12, 12, 'black', 'true')return ()
endif

ProfileImage2

在這里插入圖片描述

本地算子:compute_3d_coordinates_of_light_line

* coordinates to the plane z=0 of the local coordinate system.
* 計算線結構光打在被測物體上的輪廓線點的世界坐標*警告:如果配置文件不是大致水平方向X, Y和Z返回空元組。
* 
* Initialize the output controls
X := []
Y := []
Z := []
* 
* Check LocalCameraPose in order to determine if a transform
* has to be applied after the projection from the camera to
* the z=0 plane
if (LocalCameraPose == [])DoTransform := 0LocalCameraPose := ReferenceCameraPose
elseif (LocalCameraPose == ReferenceCameraPose)DoTransform := 0* 
elseDoTransform := 1
endif
* 
* Compute the pose for the projection of the
* local coordinate system to the plane z=0
pose_to_hom_mat3d (LocalCameraPose, HomMat3D_LocalToCam)
* 
* Compute the homography which transform the 3D-coordinates
* of points from the local coordinate system to the reference
* coordinate system
if (DoTransform)* 計算出臨時坐標系在世界坐標系的位姿pose_to_hom_mat3d (ReferenceCameraPose, HomMat3D_ReferenceToCam)hom_mat3d_invert (HomMat3D_ReferenceToCam, HomMat3D_CamToReference)hom_mat3d_compose (HomMat3D_CamToReference, HomMat3D_LocalToCam, HomMat3D_LocalToReference)
endif
* 
* Determine the profile region and test if the profile is
* oriented roughly horizontal
threshold (ProfileImage, Region, MinGray, 999999999)
orientation_region (Region, Phi)
if (cos(Phi) > cos(rad(135)) and cos(Phi) < cos(rad(45)))* The detected profile is NOT oriented roughly horizontal,* therefore return empty tuples X, Y and Z.return ()
endif
dilation_circle (Region, RegionDilation, 5.5)
smallest_rectangle1 (RegionDilation, Row1, Column1, Row2, Column2)
gen_rectangle1 (ProfileRegion, Row1, Column1, Row2, Column2)
get_domain (ProfileImage, Domain)
intersection (ProfileRegion, Domain, ProfileRegion)
* 
* 獲取光線上各點的坐標
create_sheet_of_light_model (ProfileRegion, ['min_gray','num_profiles'], [MinGray,1], SheetOfLightHandle)
* 從光片模型生成的圖像中提取激光條紋的亞像素剖面數據
* 輸出剖面點的坐標和灰度值,用于后面的三維重建和缺陷檢測
measure_profile_sheet_of_light (ProfileImage, SheetOfLightHandle, [])* 未標定的視差圖像(亞像素行坐標)
get_sheet_of_light_result (Disparity, SheetOfLightHandle, 'disparity')
clear_sheet_of_light_model (SheetOfLightHandle)
* 
* Get the 3D-coordinates of the points on the light line
* in the coordinate system defined by ReferenceCameraPose
get_domain (Disparity, DisparityDomain)
get_region_points (DisparityDomain, Rows, Columns)
* Disparities:在這里并非表示常見的灰度值,而是表示激光條紋在亞像素級的行坐標偏移量
get_grayval (Disparity, Rows, Columns, Disparities)
* 
* Project those points to the z=0 plane of the WCS
* 將激光條紋的坐標變化到世界坐標系
* Disparities已包含行方向的亞像素的偏移信息(如激光條紋中心的行坐標),因此行參數不需要補償
* 列需要補償的原因是:圖像可能從ROI(感興趣區域)的某一列開始采集,COumn1表示ROI起始列坐標
image_points_to_world_plane (CameraParameters, LocalCameraPose, Disparities, Columns + Column1, 1.0, X, Y)
tuple_gen_const (|Columns|, 0.0, Z)
* 
* If necessary, transform the 3D-coordinates from the
* 本地坐標系到參考坐標系
* system
if (DoTransform)* 從臨時坐標系切換到世界坐標系affine_trans_point_3d (HomMat3D_LocalToReference, X, Y, Z, X, Y, Z)*     hom_mat3d_to_pose (HomMat3D_LocalToReference, Pose)* pose 的z軸角度為90 度對應了index:=19與index:=20標定板的角度差異
endif
return ()

釋疑點:

? 在Halcon中,get_grayval(Disparity, Rows, Columns, Disparities)獲取的信息取決于輸入圖像Disparity的數據類型和用途,具體可分為以下兩種情況:


1. 常規灰度圖像

Disparity為普通灰度圖像時:

  • ?獲取內容?:指定坐標點(Rows, Columns)的像素亮度值(灰度值)
  • ?數值范圍?:通常為0-255(8位圖像)或更大范圍(如16位圖像)
  • ?典型應用?:圖像分析、閾值分割等傳統視覺任務

2. 光片測量(Sheet-of-Light)視差圖像

Disparity由光片測量技術生成時(如通過get_sheet_of_light_result獲取):

  • ?獲取內容?:激光條紋的?亞像素級行坐標偏移量?(非亮度值)
  • ?數值特性?:浮點型數據,表示條紋中心相對于參考位置的精確位移
  • ?核心用途?:用于三維重建,需配合image_points_to_world_plane等算子計算世界坐標17

3. 關鍵區別總結

特征常規灰度圖像光片測量視差圖像來源
?數據本質?像素亮度幾何位置偏移量
?存儲形式?整數(如uint8/uint16)浮點數(float)
?典型操作?濾波、直方圖均衡化三維坐標投影

4. 使用建議

5. ?確認圖像類型?
通過get_image_type檢查Disparity的圖像類型(如’real’表示浮點型視差數據)

6. ?避免混淆?
光片測量中的“視差”是幾何量,與立體視覺中的視差概念不同


* 2.5,獲取光平面的法向量坐標Nx,Ny,Nz,和重心點坐標
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, '提供的3d點太少,無法擬合光平面,\nor 這些點(幾乎)共線!\n程序將退出.', 'window', 12, 12, 'black', 'true')return ()
endif
if (MeanResidual > 5e-5)disp_message (WindowHandle, '這個光平面不能擬合!\n的平均誤差距離\n高于擬合標準: (' + (MeanResidual * 1000)$'.3' + 'mm). \n請檢查這些點的質量和正確性.\n程序將退出!', 'window', 12, 21, 'black', 'true')return ()endif

本地算子:fit_3d_plane_xyz,獲取擬合光平面所需要的法向量。

* 
* WARNING: If the system of equations is under-determined
* (i.e. if it has too few input coordinates in X, Y, Z),
* it cannot be solved and the procedure returns empty tuples
* for X, Y, and Z
* 
* Perform some initializations
Ox := []
Oy := []
Oz := []
Nx := []
Ny := []
Nz := []
MeanResidual := []
* 
* Test the size of X, Y and Z, and return if necessary
Size := |X|
if (Size < 3 or Size != |Y| or Size != |Z|)return ()
endif
* 
* 計算重心點坐標
tuple_mean (X, Ox)
tuple_mean (Y, Oy)
tuple_mean (Z, Oz)
* 
*將方程組建立為矩陣M并計算
*其奇異值分解。奇異向量
*M的對應其最小奇異值有
*擬合平面的法向量坐標。
create_matrix (3, |X|, [X - Ox,Y - Oy,Z - Oz], MatrixID_Mt)
* 交換矩陣的行列
transpose_matrix (MatrixID_Mt, MatrixID_M)
* 計算一個矩陣的奇異值分解。
svd_matrix (MatrixID_M, 'reduced', 'right', MatrixID_U, MatrixID_S, MatrixID_V)
get_value_matrix (MatrixID_S, [0,1,2], [0,1,2], SingularvaluesOfM)
tuple_sort_index (SingularvaluesOfM, Indices)
* 
* Test if more than one singular value of M is (nearly) equal
* to zero. This indicates that the provided 3d points are
* inappropriate to fit the plane (e.g. they are nearly
* collinear or reduce to a single point).
* 檢驗是否有多個M的奇異值(近似)相等
* 到零。這表明所提供的3d點是
* 不適合擬合成平面(例如它們幾乎是)
* 共線或減少到一個點)。
if (SingularvaluesOfM[Indices[0]] < 1e-9 and SingularvaluesOfM[Indices[1]] < 1e-9)return ()
endif
* 
* 得到擬合平面的法向量坐標
get_value_matrix (MatrixID_V, [0,1,2], [Indices[0],Indices[0],Indices[0]], N)
create_matrix (3, 1, N, MatrixID_N)
Nx := N[0]
Ny := N[1]
Nz := N[2]
* 
* Compute the mean residual distance between the 3d points
* and the fitted plane, in order to guess the quality of
* the fitted plane:
* 計算三維點之間的平均差異距離
* 和擬合平面,以便猜測質量
* 擬合平面:
mult_matrix (MatrixID_M, MatrixID_N, 'AB', MatrixID_MN)
get_full_matrix (MatrixID_MN, Distances)
Distances := abs(Distances)
* 誤差值
MeanResidual := sum(Distances) / Size
* 
* Clear the matrices used in the procedure
clear_matrix ([MatrixID_MN,MatrixID_N,MatrixID_V,MatrixID_S,MatrixID_U,MatrixID_M,MatrixID_Mt])
return ()
* 2.6,根據重心點和法向量計算出光平面在世界坐標系的位姿
* 使得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* 2.7,顯示光平面位姿信息
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 ()

光平面位姿:
在這里插入圖片描述


6.4,計算MovementPose。
* 3.1,計算標定板沿y axis 位移前后的位姿
read_image (CaltabImagePos1, 'sheet_of_light/caltab_at_position_1.png')
read_image (CaltabImagePos20, 'sheet_of_light/caltab_at_position_2.png')
StepNumber := 19* 標定板移動前(沿y axis 方向)
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, [], [])* 從標定數據模型中提取未優化位姿
get_calib_data_observ_points (CalibDataID, 0, 0, NumCalibImages + 1, Row1, Column1, Index1, CameraPosePos1)
dev_display (CaltabImagePos1)
disp_3d_coord_system (WindowHandle,CameraParameters, CameraPosePos1, 0.01)
* 標定板移動后(位置2相對位置1在y axis 上進行移動的些許)
find_calib_object (CaltabImagePos20, CalibDataID, 0, 0, NumCalibImages + 2, [], [])
get_calib_data_observ_points (CalibDataID, 0, 0, NumCalibImages + 2, Row1, Column1, Index1, CameraPosePos20)
dev_display (CaltabImagePos20)
disp_3d_coord_system (WindowHandle,CameraParameters, CameraPosePos20, 0.01)
* Clear the model
clear_calib_data (CalibDataID)

位移前:

在這里插入圖片描述

位移后:

在這里插入圖片描述

* 3.2,將在相機坐標系中的位姿轉換到世界坐標系
set_origin_pose (CameraPosePos1, 0.0, 0.0, CalTabThickness, CameraPosePos1)
set_origin_pose (CameraPosePos20, 0.0, 0.0, CalTabThickness, CameraPosePos20)
pose_to_hom_mat3d (CameraPosePos1, HomMat3DPos1ToCamera)
pose_to_hom_mat3d (CameraPosePos20, HomMat3DPos20ToCamera)
pose_to_hom_mat3d (CameraPose, HomMat3DWorldToCamera)
hom_mat3d_invert (HomMat3DWorldToCamera, HomMat3DCameraToWorld)
hom_mat3d_compose (HomMat3DCameraToWorld, HomMat3DPos1ToCamera, HomMat3DPos1ToWorld)
hom_mat3d_compose (HomMat3DCameraToWorld, HomMat3DPos20ToCamera, HomMat3DPos20ToWorld)* 3.3,計算觀察點(0,0,0)在位移前后的偏移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 / StepNumberString := ['標定板每一步移動的位姿\n(位置1到位置2共移動了19步)','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 ()

MovementPose信息:

在這里插入圖片描述


釋疑點:

MovementPose 的物理內涵與觸發機制


  • 參數定義與觸發邏輯
  1. ?核心意義?
    MovementPose 描述的是 ?物體在運動過程中相對于初始位姿的剛體變換?(包含旋轉矩陣 RR 和平移向量 TT),而非嚴格按時間間隔更新。其更新觸發取決于外部運動系統的反饋機制(如編碼器脈沖、機械臂位姿信號等)。
  2. ?時間關聯性?
    • 若運動系統以固定頻率(如每秒)反饋位姿數據,則 MovementPose 可能每秒更新一次
    • 但在 ?非勻速運動場景? 中,位姿更新頻率會動態調整,與時間間隔無直接綁定

  • 典型應用模式
  1. ?同步觸發模式?
    通過外部觸發信號(如機械臂到達指定位置時發送脈沖)更新 MovementPose,確保掃描動作與位姿數據嚴格同步。

  2. ?異步事件驅動?
    在自由運動場景(如傳送帶連續運行)中,根據運動系統實時推送的位姿流數據更新 MovementPose,此時更新頻率由硬件通信速率決定。


  • 技術對比
參數更新機制觸發條件適用場景
?時間驅動?固定采樣周期(如1秒)勻速運動且對實時性要求低的場景
?事件驅動?運動狀態變化(如位移超閾值)高精度動態掃描(工業檢測、機器人抓取)

?實際工程中?,通常采用事件驅動模式以保證點云數據與物體實際運動嚴格匹配。


6.5,激光三角應用。
* Part 4: 三角測量應用:生成3D點云。* 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)
* min_gray:輪廓提取的最小灰度值;num_profiles:提取的輪廓數量;ambiguity_solving:解決深度歧義的方法,值"first":優先選擇第一個有效解
create_sheet_of_light_model (ProfileRegion, ['min_gray','num_profiles','ambiguity_solving'], [70,290,'first'], SheetOfLightModelID)
set_sheet_of_light_param (SheetOfLightModelID, 'calibration', 'xyz')
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)
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)
* 
* 4.1,顯示生成的 Z-coordinates圖像
*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')
* 
* 4.2,顯示生成的 Y-coordinates圖像
dev_open_window ((Height + 10),  Width * .5, 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')
* 
* 4.3,顯示生成的 Z-coordinates圖像
dev_open_window (Height*1.5, 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')
* 合成 3D 點云模型,點云數據默認以世界坐標系為基礎進行渲染
xyz_to_object_model_3d (X, Y, Z, ObjectModel3D)*-----------
* part5: 顯示光平面與3D對象模型
* 光平面,這里的光平面位姿是指在世界坐標系中的位姿
gen_plane_object_model_3d (LightPlanePose, [-80,-80,80,80], [80,-80,-80,80], ObjectModel3D1)
dev_set_color ('red')
visualize_object_model_3d (WindowHandle,[ObjectModel3D,ObjectModel3D1],\[], [], ['lut','intensity','color_1','alpha_1','disp_pose'], ['color1','coord_z','red',0.6,'true'], [], [], [], PoseOut)

釋疑點:

visualize_object_model_3d 算子的默認顯示坐標系:

  1. ?核心坐標系關系?
    • 點云數據默認以?**世界坐標系(場景坐標系 SCS)**?為基礎進行渲染。此時虛擬相機的觀察視角會通過 CamParamPoseIn 參數調整,但點云本身的坐標仍與世界坐標系對齊。
  2. ?默認姿態與相機參數的影響?
    • PoseIn 參數為空時,算子會自動計算初始位姿,此時點云的顯示位置仍基于世界坐標系,但會通過虛擬相機的視角參數(如 CamParam)進行投影變換。
    • 若未顯式設置相機內參(CamParam 為空),算子會根據窗口尺寸生成默認參數,但坐標系基準不變。
  3. ?用戶交互對坐標系的修正?
    • 通過鼠標操作(旋轉、平移)調整點云姿態后,輸出的 PoseOut 參數表示點云在世界坐標系下的新位姿,而非相機坐標系下的相對位置。

總結:該算子默認以?世界坐標系?為基準渲染點云,虛擬相機僅提供觀察視角的變換,不會改變點云本身在世界坐標系中的實際坐標。


示意圖

在這里插入圖片描述

點云效果及光平面顯示

紅色為Light plane,紅軸為 x axis,綠軸為 y axis,藍軸為 z axis。

在這里插入圖片描述

7,完整代碼。

* 案例庫:cablibrate_sheet_of_light_calplate.hdev* 目的:
* 計算激光三角測量所需的LightPlanePose(光平面位姿)與MovementPose(每步移動位姿),完成激光三角測量* 描述:
* 通過計算結構光在亮處不同位姿的被測物上形成輪廓線的點坐標(世界坐標系)擬合出LightPlanePose
* 通過在y axis移動n步的標定板位姿變化計算出MovementPose(每步移動位姿)
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)
dev_set_draw ('margin')
dev_set_line_width (3)
dev_set_color ('lime green')
dev_set_lut ('default')
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
* 
* -------
* Part 1: 執行相機的標定
* -------
* 
* 1.1,默認的相機內參
StartParameters := [0.0125,0.0,0.0,0.0,0.0,0.0,0.000006,0.000006,376.0,120.0,752,240]* 1.2,標定板描述文件
* caltab_30mm.descr':Distance between mark centers [meter]: 0.00375
CalTabDescription := 'caltab_30mm.descr'* 1.3,標定板的厚度(單位:m)
CalTabThickness := .00063* 1.4,標定板圖像數量
NumCalibImages := 20
* 
* Initialize a calibration data model
create_calib_data ('calibration_object', 1, 1, CalibDataID)* 1.4,設置標定參數
* 'area_scan_polynomial':復雜畸變、需要亞像素級精度。至少需要15張標定圖像。
* 'division':至少需要5張標定圖像。
set_calib_data_cam_param (CalibDataID, 0, 'area_scan_polynomial', StartParameters)
set_calib_data_calib_object (CalibDataID, 0, CalTabDescription)* 1.5,標定圖像(包含各個水平角度,傾斜角度,不同位置但是需要全部在視野內的圖像)
* Collect mark positions and estimated poses for all
* calibration images
for Index := 1 to NumCalibImages by 1read_image (Image, 'sheet_of_light/connection_rod_calib_' + Index$'.2')dev_display (Image)* 后續標定板處于不同位置所對應的位姿與該索引對應,該索引不必從0開始find_calib_object (Image, CalibDataID, 0, 0, Index, [], [])get_calib_data_observ_points (CalibDataID, 0, 0, Index, Row, Column, _Index, Pose)get_calib_data_observ_contours (Contours, CalibDataID, 'caltab', 0, 0, Index)dev_set_color ('green')dev_display (Contours)gen_cross_contour_xld (Cross, Row, Column, 6, 0.785398)dev_set_color ('yellow')dev_display (Cross)
endfor
* 
* 1.6,執行標定
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: 計算光平面相對于世界坐標系的位姿
* -------
dev_set_colored (3)
MinThreshold := 80* 2.1,獲取世界坐標系在相機坐標系的位姿
Index := 19
get_calib_data (CalibDataID, 'calib_obj_pose', [0,Index], 'pose', CalTabPose)
set_origin_pose (CalTabPose, 0.0, 0.0, CalTabThickness, CameraPose)
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)
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.
* 2.2,獲取臨時坐標系在相機坐標系的位置(此時的標定板相對于Index:=19的標定板旋轉了90度)
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 ()* 
* dev_clear_window ()
read_image (ProfileImage1, 'sheet_of_light/connection_rod_lightline_019.png')* 2.3,計算索引為19被測物體(位于世界坐標系)激光輪廓線點在z=0的世界坐標系中的坐標
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
* 
* 2.4,計算索引為20位于被測物體(位于臨時坐標系)激光輪廓線點在z=0的世界坐標系中的坐標
* Compute the 3D coordinates of the light line points
* in the plane z=0 of the TCS
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, '為了成功處理,輪廓需要是大致水平!\n程序將退出.', 'window', 12, 12, 'black', 'true')return ()
endif
* * 2.5,獲取光平面的法向量坐標Nx,Ny,Nz,和重心點坐標
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, '提供的3d點太少,無法擬合光平面,\nor 這些點(幾乎)共線!\n程序將退出.', 'window', 12, 12, 'black', 'true')return ()
endif
if (MeanResidual > 5e-5)disp_message (WindowHandle, '這個光平面不能擬合!\n的平均誤差距離\n高于擬合標準: (' + (MeanResidual * 1000)$'.3' + 'mm). \n請檢查這些點的質量和正確性.\n程序將退出!', 'window', 12, 21, 'black', 'true')return ()endif
* 
* 2.6,根據重心點和法向量計算出光平面在世界坐標系的位姿
* 使得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* 2.7,顯示光平面位姿信息
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:獲取MovementPose(每移動一步的姿態)* 3.1,計算標定板沿y axis 位移前后的位姿
read_image (CaltabImagePos1, 'sheet_of_light/caltab_at_position_1.png')
read_image (CaltabImagePos20, 'sheet_of_light/caltab_at_position_2.png')
StepNumber := 19* 標定板移動前(沿y axis 方向)
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, [], [])* 從標定數據模型中提取未優化位姿
get_calib_data_observ_points (CalibDataID, 0, 0, NumCalibImages + 1, Row1, Column1, Index1, CameraPosePos1)
dev_display (CaltabImagePos1)
disp_3d_coord_system (WindowHandle,CameraParameters, CameraPosePos1, 0.01)
* 標定板移動后(位置2相對位置1在y axis 上進行移動的些許)
find_calib_object (CaltabImagePos20, CalibDataID, 0, 0, NumCalibImages + 2, [], [])
get_calib_data_observ_points (CalibDataID, 0, 0, NumCalibImages + 2, Row1, Column1, Index1, CameraPosePos20)
dev_display (CaltabImagePos20)
disp_3d_coord_system (WindowHandle,CameraParameters, CameraPosePos20, 0.01)
* Clear the model
clear_calib_data (CalibDataID)
* 
* 3.2,將在相機坐標系中的位姿轉換到世界坐標系
set_origin_pose (CameraPosePos1, 0.0, 0.0, CalTabThickness, CameraPosePos1)
set_origin_pose (CameraPosePos20, 0.0, 0.0, CalTabThickness, CameraPosePos20)
pose_to_hom_mat3d (CameraPosePos1, HomMat3DPos1ToCamera)
pose_to_hom_mat3d (CameraPosePos20, HomMat3DPos20ToCamera)
pose_to_hom_mat3d (CameraPose, HomMat3DWorldToCamera)
hom_mat3d_invert (HomMat3DWorldToCamera, HomMat3DCameraToWorld)
hom_mat3d_compose (HomMat3DCameraToWorld, HomMat3DPos1ToCamera, HomMat3DPos1ToWorld)
hom_mat3d_compose (HomMat3DCameraToWorld, HomMat3DPos20ToCamera, HomMat3DPos20ToWorld)* 3.3,計算觀察點(0,0,0)在位移前后的偏移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 / StepNumberString := ['標定板每一步移動的位姿\n(位置1到位置2共移動了19步)','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: 三角測量應用:生成3D點云。
* -------
* 
* 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)
* min_gray:輪廓提取的最小灰度值;num_profiles:提取的輪廓數量;ambiguity_solving:解決深度歧義的方法,值"first":優先選擇第一個有效解
create_sheet_of_light_model (ProfileRegion, ['min_gray','num_profiles','ambiguity_solving'], [70,290,'first'], SheetOfLightModelID)
set_sheet_of_light_param (SheetOfLightModelID, 'calibration', 'xyz')
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)
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)
* 
* 4.1,顯示生成的 Z-coordinates圖像
*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')
* 
* 4.2,顯示生成的 Y-coordinates圖像
dev_open_window ((Height + 10),  Width * .5, 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')
* 
* 4.3,顯示生成的 Z-coordinates圖像
dev_open_window (Height*1.5, 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')
* 合成 3D 點云模型,點云數據默認以世界坐標系為基礎進行渲染
xyz_to_object_model_3d (X, Y, Z, ObjectModel3D)*-----------
* part5: 顯示光平面與3D對象模型
* 光平面,這里的光平面位姿是指在世界坐標系中的位姿
gen_plane_object_model_3d (LightPlanePose, [-80,-80,80,80], [80,-80,-80,80], ObjectModel3D1)
dev_set_color ('red')
visualize_object_model_3d (WindowHandle,[ObjectModel3D,ObjectModel3D1],\[], [], ['lut','intensity','color_1','alpha_1','disp_pose'], ['color1','coord_z','red',0.6,'true'], [], [], [], PoseOut)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/83892.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/83892.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/83892.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

高可用消息隊列實戰:AWS SQS 在分布式系統中的核心解決方案

引言&#xff1a;消息隊列的“不可替代性” 在微服務架構和分布式系統盛行的今天&#xff0c;消息隊列&#xff08;Message Queue&#xff09; 已成為解決系統解耦、流量削峰、異步處理等難題的核心組件。然而&#xff0c;傳統的自建消息隊列&#xff08;如RabbitMQ、Kafka&am…

人工智能核心知識:AI Agent 的四種關鍵設計模式

人工智能核心知識&#xff1a;AI Agent 的四種關鍵設計模式 一、引言 在人工智能領域&#xff0c;AI Agent&#xff08;人工智能代理&#xff09;是實現智能行為和決策的核心實體。它能夠感知環境、做出決策并采取行動以完成特定任務。為了設計高效、靈活且適應性強的 AI Age…

平替BioLegend品牌-Elabscience PE Anti-Mouse Foxp3抗體:流式細胞術中的高效工具,助力免疫細胞分析!”

概述 調節性T細胞&#xff08;Treg&#xff09;在維持免疫耐受和抑制過度免疫反應中發揮關鍵作用&#xff0c;其標志性轉錄因子Foxp3&#xff08;Forkhead box P3&#xff09;是Treg功能研究的重要靶點。Elabscience 推出的抗小鼠Foxp3抗體&#xff08;3G3-E&#xff09;&…

編程日志5.13

鄰接表的基礎代碼 #include<iostream> using namespace std; //鄰接表的類聲明 class Graph {private: //結構體EdgeNode表示圖中的邊結點,包含頂點vertex、權重weight和指向下一個邊結點的指針next struct EdgeNode { int vertex; int weight; …

PowerBI 矩陣實現動態行內容(如前后銷售數據)統計數據,以及過濾同時為0的數據

我們有一張活動表 和 一張銷售表 我們想實現如下的效果&#xff0c;當選擇某個活動時&#xff0c;顯示活動前后3天的銷售對比圖&#xff0c;如下&#xff1a; 實現方法&#xff1a; 1.新建一個表&#xff0c;用于顯示列&#xff1a; 2.新建一個度量值&#xff0c;用SELECTEDVA…

Prompt Tuning:高效微調大模型的新利器

Prompt Tuning(提示調優)是什么 Prompt Tuning(提示調優) 是大模型參數高效微調(Parameter-Efficient Fine-Tuning, PEFT)的重要技術之一,其核心思想是通過優化 連續的提示向量(而非整個模型參數)來適配特定任務。以下是關于 Prompt Tuning 的詳細解析: 一、核心概念…

杰發科技AC7840——如何把結構體數據寫到Dflash中

1. 結構體數據被存放在Pflash中 正常情況下&#xff0c;可以看到全局變量的結構體數據被存放在Pflash中 數字部分存在RAM中 2. 最小編程單位 8字節編程&#xff0c;因此如果結構體存放在Dfalsh中&#xff0c;進行寫操作&#xff0c;需要寫8字節的倍數 第一種辦法&#xff1a;…

CSS 選擇器入門

一、CSS 選擇器基礎&#xff1a;快速掌握核心概念 什么是選擇器&#xff1f; CSS 選擇器就像 “網頁元素的遙控器”&#xff0c;用于定位 HTML 中的特定元素并應用樣式。 /* 結構&#xff1a;選擇器 { 屬性: 值; } */ p { color: red; } /* 選擇所有<p>元素&#xff0c;…

Anaconda3安裝教程(附加安裝包)Anaconda詳細安裝教程Anaconda3 最新版安裝教程

多環境隔離 可同時維護生產環境、開發環境、測試環境&#xff0c;例如&#xff1a; conda create -n ml python3.10 # 創建機器學習環境 conda activate ml # 激活環境三、Anaconda3 安裝教程 解壓Anaconda3安裝包 找到下載的 Anaconda3 安裝包&#xff08;.ex…

現代計算機圖形學Games101入門筆記(十七)

雙向路徑追蹤 外觀建模 散射介質 人的頭發不能用在動畫的毛發上。 動物的髓質Medulla特別大 雙層圓柱模型應用 BSSRDF是BRDF的延伸。 天鵝絨用BRDF不合理&#xff0c;轉成散射介質。 法線分布 光追很難處理微表面模型 光在微型細節上&#xff0c;光是一個波&#xff0c;會發生衍…

chrome源碼中WeakPtr 跨線程使用詳解:原理、風險與最佳實踐

base::WeakPtr 在 Chromium 中 不能安全地跨線程使用。這是一個很關鍵的點&#xff0c;下面詳細解釋原因及正確用法。 &#x1f50d;原理與使用 ? 先說答案&#xff1a; base::WeakPtr 本質上是**線程綁定&#xff08;thread-affine&#xff09;**的。不能在多個線程之間創建…

hysAnalyser 從MPEG-TS導出ES功能說明

摘要 hysAnalyser 是一款特色的 MPEG-TS 數據分析工具。本文主要介紹了 hysAnalyser 從MPEG-TS 中導出選定的 ES 或 PES 功能(版本v1.0.003)&#xff0c;以便用戶知悉和掌握這些功能&#xff0c;幫助分析和解決各種遇到ES或PES相關的實際問題。hysAnalyser 支持主流的MP1/MP2/…

C++(21):fstream的讀取和寫入

目錄 1 ios::out 2 ios::in和is_open 3 put()方法 4 get()方法 4.1 讀取單個字符 4.2 讀取多個字符 4.3 設置終結符 5 getline() 1 ios::out 打開文件用于寫入數據。如果文件不存在&#xff0c;則新建該文件&#xff1b;如果文件原來就存在&#xff0c;則打開時清除…

系統架構設計(十七):微服務數據一致性和高可用策略

數據一致性問題 問題本質 由于每個微服務擁有獨立數據庫&#xff0c;跨服務操作不能用傳統的數據庫事務&#xff0c;面臨“分布式事務”一致性挑戰。 數據一致性策略 策略核心思想應用場景優缺點強一致性&#xff08;Strong Consistency&#xff09;所有操作實時同步成功&a…

os agent智能體軟件 - 第三彈 - 純語音交互

前兩期期我們發布了產品的初級形態&#xff0c;那時候還只能是“軟件開發者”在本地配置使用&#xff0c;或者運行起來有個大黑框&#xff0c;使用起來美觀度太差。 到今天大概20天&#xff0c;我們的第3版已經出來了&#xff0c;不僅做成了電腦端的exe軟件&#xff08;任何人…

鏈表原理與實現:從單鏈表到LinkedList

1.鏈表的概念及結構 鏈表是一種物理存儲結構上非連續存儲結構&#xff0c;數據元素的邏輯順序是通過鏈表中的引用鏈接次序實現的 。 可以形象的理解&#xff0c;在邏輯上來看&#xff0c;鏈表就像是一節節火車車廂。 鏈表的分類&#xff1a;鏈表的結構有很多種&#xff0c;單向…

替換word中的excel

PostMapping("/make/report/target/performance/first") public AjaxResult makeTargetReportFirst(RequestBody MakeReportDTO makeReportDTO) {Map<String, String> textReplaceMap new HashMap<>();// 替換日期LocalDateTime nowData LocalDateTime…

深入探索百度智能云千帆AppBuilder:從零開始構建AI應用

在數字化轉型的浪潮中&#xff0c;企業對高效、智能的應用開發平臺的需求日益增長。百度智能云千帆AppBuilder&#xff08;以下簡稱AppBuilder&#xff09;憑借其強大的功能和靈活的開發方式&#xff0c;成為企業級大模型應用開發的理想選擇。本文將詳細介紹如何使用AppBuilder…

測試工程師要如何開展單元測試

單元測試是軟件開發過程中至關重要的環節&#xff0c;它通過驗證代碼的最小可測試單元(如函數、方法或類)是否按預期工作&#xff0c;幫助開發團隊在早期發現和修復缺陷&#xff0c;提升代碼質量和可維護性。以下是測試工程師開展單元測試的詳細步驟和方法&#xff1a; 一、理…

NODE-I916 I721模塊化電腦發布,AI算力與超低功耗的完美平衡

在智能工業與邊緣計算蓬勃發展的今天&#xff0c;企業對計算設備的性能與能效需求日益嚴苛。全新推出NODE-I916與NODE-I721模塊化電腦&#xff0c;分別搭載英特爾 酷睿? Ultra 平臺與Alder Lake-N平臺&#xff0c;以差異化CPU配置為核心&#xff0c;為AI推理、工業自動化及嵌入…