深入理解halcon相機標定

  • 博主寫作不容易,還是需要您鼓勵
  • 萬水千山總是情 , 先點個贊行不行
  • 最近有的人私信我,說看了我的《HALCON相機標定相機內參相機外參》https://blog.csdn.net/cashmood/article/details/100089295一文後,還是有不懂的地方,這裏給大家做一個深入的教程。

    相機標定簡介

    首先鏡頭有畸變,也就是說照出的圖像與實際不符產生了形變。即使工業鏡頭也是有千分之幾的畸變率的。
    上個圖告訴大家畸變
    在這裏插入圖片描述
    這個圖裏,第一個圖就是我們相機下的真實的形狀,後邊兩個就是照出來有畸變的圖片。

    其次鏡頭與相機無論你的機械結構精度多高,也不容易或者說沒辦法將相機安裝的特別正,那相機安裝不正也是會導致誤差的。大家想知道具體數學模型的話可以搜一下相機標定的理論方面的知識,我側重怎麼做。
    標定就是把上述兩個東西轉化成正常的。
    無論是在圖像測量或者機器視覺應用中,相機參數的標定都是非常關鍵的環節,其標定結果的精度及算法的穩定性直接影響相機工作產生結果的準確性。

    深度說明

    1、相機標定參數介紹

    在這裏插入圖片描述
    內參:確定攝像機從三維空間到二維空間的投影關係。
    針孔相機(FA鏡頭相機)模型爲6個參數(f,kSx,Sy,Cx,Cy);遠心鏡頭相機模型爲5個參數(f,Sx,Sy,Cx,Cy);線陣相機爲11個參數(f,k,Sx,Sy,Cx,Cy,Width,Highth,Vx,Vy,Vz)。
    其中:
    f爲焦距;
    k表示徑向畸變量級。如果k爲負值,畸變爲桶形畸變,如果爲正值,那麼畸變爲枕形畸變。
    Sx,Sy是縮放比例因子。對於針孔攝像機(FA鏡頭)表示圖像傳感器水平和垂直方向上相鄰像素之間的距離,初始值與真實值越接近計算速度越快。對於遠心攝像機模型,表示像素在世界座標系中的尺寸。
    Cx,Cy是圖像的主點,對於針孔相機,這個點是投影中心在成像平面上的垂直投影,同時也是徑向畸變的中心。對於遠心攝像機模型,只表示畸變的中心。
    Vx,Vy,Vz:線陣相機必須與被拍攝物體之間有相對移動才能拍攝到一幅有用的圖像。這是運動向量。Sx,Sy對於線陣相機是相鄰像元的水平和垂直距離。

    2、標定板詳細介紹

    問題1:halcon是否只能使用halcon專用的標定板?

    halcon提供了簡便、精準的標定算子與標定助手,這在實際使用中極大地方便了使用者
    在halcon中有兩種標定方式:
    halcon自帶例程中出現的,用halcon定義的標定板,如下圖:
    在這裏插入圖片描述
    用戶自定義標定板,用戶可以製作任何形狀、形式的標定板,如下圖:
    在這裏插入圖片描述
    所以,halcon並非只能使用專用標定板,也可以使用自定義標定板就可以進行標定。

    問題2:halcon標定板如何生成?

    使用gen_caltab算子來製作一個標定板
    gen_caltab( : : XNum, YNum, MarkDist, DiameterRatio, CalPlateDescr, CalPlatePSFile : )
    XNum:每行黑色標誌圓點的數量
    YNum:每列黑色標誌圓點的數量
    MarkDist:兩個就近黑色圓點中心之間的距離,單位是m
    DiameterRatio:黑色圓點直徑與兩圓點中心距離的比值
    CalPlateDescr:標定板描述文件的文件路徑
    CalPlatePSFile :標定板圖像文件路徑,可以用ps打開
    示例:
    gen_caltab( 7, 7, 0.1, 0.5, ‘caltab.descr’, ‘caltab.ps’)
    大家可以自己思考一下每個參數的含義
    行數:7
    列數:7
    黑色圓點半徑:0.05m
    圓點中心間距:0.1m

    問題3:halcon標定板如何擺放,拍照數量有無限制?

    並非拍照標定數量越多,越能取得高的精度,halcon建議拍攝數量在9-16張,並且對擺放位置做了建議。標定板佔標定視野的1/3-1/4,對於標定板成像灰度值應大於128,以便順利提取。如下圖所示:
    在這裏插入圖片描述

    標定步驟

    注意只介紹面陣相機,其他的相機和麪陣道理想同。

    1、設置相機內部初始值

    使用set_calib_data_cam_param 算子設置相機內部初始值

    set_calib_data_cam_param( : : CalibDataID, CameraIdx, CameraType, CameraParam : )
    CalibDataID:標定句柄
    CameraIdx:相機序號
    CameraType:相機模型種類;面陣相機Division畸變模型’area_scan_division’;polynomial畸變模型’area_scan_polynomial’。。。。。。
    CameraParam :與相機模型種類相對應的參數;面陣相機Division畸變模型’area_scan_division’([Focus, Kappa, Sx, Sy, Cx, Cy, ImageWidth, ImageHeight]);polynomial畸變模型’area_scan_polynomial’([Focus, K1, K2, K3, P1, P2, Sx, Sy, Cx, Cy, ImageWidth, ImageHeight])。。。。。。

    相機模型種類與相機參數對應表:
    在這裏插入圖片描述

    畸變類型選擇與參數確定技巧

    畸變模型選擇
    division畸變模型只適用於精度不高的,標定圖片數量較少的情況:
    polynomial畸變模型對徑向畸變、切向畸變都進行矯正,精度較高,花費時間較長。
    參數確定技巧
    Focus代表焦距,按照我們鏡頭參數進行填寫,遠心鏡頭填寫0

    Kappa爲畸變大小,因爲在標定之前,所以默認填寫0

    Sx, Sy像元的寬高填寫相機的像元尺寸。可以查相機手冊,或者諮詢相機廠家。
    Cx, Cy填寫圖像的中心座標
    ImageWidth, ImageHeight填寫圖像的寬高

    2、標定板初始化

    使用算子 set_calib_data_calib_object
    例如:
    CaltabDescr := ‘caltab_100mm.descr’
    set_calib_data_calib_object (CalibDataID, 0, CaltabDescr)
    這個比較簡單,大家看幫助就可以懂,就不進行介紹了

    3、創建標定數據模型

    使用算子 create_calib_data( : : CalibSetup, NumCameras, NumCalibObjects : CalibDataID)
    CalibSetup:創建的內容
    NumCameras:相機個數
    NumCalibObjects :標定項目數
    CalibDataID:標定句柄
    例如:
    create_calib_data (‘calibration_object’, 1, 1, CalibDataID)

    4、獲取標定圖片

    標定板爲正方形,尺寸大小爲要照射區域寬度的1/3,相機拍攝或者讀入9-16張圖片,拍攝圖片時標定板儘量覆蓋整個視場;標定板圓點的直徑不能小於10個像素。

    5、使用圖像進行相機內參標定,得到結果

    方式一:
    使用標定圖像,直接用halcon全自動,進行標定
    find_calib_object (Image, CalibDataID, CameraIndex, 0, PoseIndex, [], [])
    得到標定數據
    get_calib_data (CalibDataID, ‘camera’, 0, ‘type’, CameraType)

    方式二:
    1、尋找標定板區域,確定圓心,將結果加載到組元中
    find_caltab(Image : CalPlate : CalPlateDescr, SizeGauss, MarkThresh, MinDiamMarks : )
    find_marks_and_pose(Image, CalPlateRegion : : CalPlateDescr, StartCamParam, StartThresh, DeltaThresh, MinThresh, Alpha, MinContLength, MaxDiamMarks : RCoord, CCoord, StartPose)
    set_calib_data_observ_points( : : CalibDataID, CameraIdx, CalibObjIdx, CalibObjPoseIdx, Row, Column, Index, Pose : )
    原理:首先find_caltab算子對圖像高斯濾波(核大小爲SizeGauss),接着閾值分割(閾值大小爲MarkThresh)將標定板的區域找出來;find_marks_and_pose算子對區域中的圓進行分割,找到圓的個數,周長,座標等應該和標定板描述文件中的一致,否則會自動調整StartThresh,使得StartThresh按照DeltaThresh步長減小到MinDiamMarks ,直到找到準確的圓心。
    2、進行標定
    calibrate_cameras( : : CalibDataID : Error)
    返回平均投影誤差Error

    6、使用圖像進行相機外參標定,得到結果

    攝像機外參:決定攝像機座標系與世界座標系之間相對位置關係
    其中Pw爲世界座標,Pc爲攝像機座標,T=(Tx,Ty,Tz)是平移向量,R=(a,b,r)是旋轉矩陣,分別是繞攝像機座標系Z軸旋轉角度爲r;繞攝像機座標系Y軸旋轉角度爲b;繞攝像機座標系X軸旋轉角度爲a。6個參數組成攝像機外參(a,b,r,Tx,Ty,Tz)
    並且滿足下式:
    Pc=R*Pw+T

    具體步驟:
    set_calib_data_cam_param( : : CalibDataID, CameraIdx, CameraType, CameraParam : )
    set_calib_data_calib_object( : : CalibDataID, CalibObjIdx, CalibObjDescr : )
    find_calib_object(Image : : CalibDataID, CameraIdx, CalibObjIdx, CalibObjPoseIdx, GenParamName, GenParamValue : )
    get_calib_data_observ_contours( : Contours : CalibDataID, ContourName, CameraIdx, CalibObjIdx, CalibObjPoseIdx : )
    get_calib_data_observ_points( : : CalibDataID, CameraIdx, CalibObjIdx, CalibObjPoseIdx : Row, Column, Index, Pose)
    set_origin_pose( : : PoseIn, DX, DY, DZ : PoseNewOrigin)
    在這裏插入圖片描述

    Halcon相機標定代碼與解析

    **創建標定板
    gen_caltab(7,7,0.008,0.5,'48_48mm.descr','48_48mm.ps')
               
    *=======標定內參
    dev_close_window ()
    dev_open_window (0, 0, 652, 494, 'black', WindowHandle)
    dev_update_off ()
    dev_set_draw ('margin')
    dev_set_line_width (3)
    OpSystem := environment('OS')
    set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
               
    *標定相機
    StartCamPar := [0.0,0.0,0.0000299,0.0000299,4896/2,3264/2,4896,3264]
    create_calib_data ('calibration_object', 1, 1, CalibDataID)
    set_calib_data_cam_param (CalibDataID, 0, 'area_scan_telecentric_division', StartCamPar)
    set_calib_data_calib_object (CalibDataID, 0, '48_48mm.descr')
               
    
    for index := 1 to 13 by 1
        read_image (Image, '標定20/' + index + '.png')
        get_image_size(Image, Width, Height)
        dev_display (Image)
        find_calib_object (Image, CalibDataID, 0, 0, index, [], [])
        get_calib_data_observ_contours (Caltab, CalibDataID, 'caltab', 0, 0, index)
        dev_set_color ('green')
        dev_display (Caltab)
    endfor
               
    calibrate_cameras (CalibDataID, Error)
    get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam)
    get_calib_data (CalibDataID, 'calib_obj_pose', [0,1], 'pose', PoseCalib)
               
    *輸出計算的相機內參
    write_cam_par (CamParam, 'camera_parameters.dat')
               
               
    Message:= '相機內參已經寫入文件中'
    disp_message (WindowHandle, Message, 'window', 12, 12, 'red', 'false')
    clear_calib_data (CalibDataID)
    stop()
               
               
    *=====標定外參
    dev_set_draw ('margin')
    dev_set_line_width (1)
    set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
               
    *從文件中讀取內參 存儲文件:camera_parameters.dat
    try
        read_cam_par ('camera_parameters.dat', CamParam)
    catch (Exception)
        stop ()
    endtry
               
    *開始計算
    open_file('data.csv','output', FileHandle)
    fwrite_string(FileHandle,'Dis_pix*0.0299204,Dis_m*1000,Distance')
    fnew_line (FileHandle)
    close_file(FileHandle)
               
    *選擇一張作爲標定作爲最終標定位姿(任意一張都可以)
    index:=1
    read_image (Image,'標定20/'+index+'.png')
    dev_display (Image)
    CaltabName := '48_48mm.descr'
    create_calib_data ('calibration_object', 1, 1, CalibDataID)
    
    set_calib_data_cam_param (CalibDataID, 0, 'area_scan_telecentric_division', CamParam)
    set_calib_data_calib_object (CalibDataID, 0, CaltabName)
    find_calib_object (Image, CalibDataID, 0, 0, 1, [], [])
    get_calib_data_observ_contours (Caltab, CalibDataID, 'caltab', 0, 0, 1)
    get_calib_data_observ_points (CalibDataID, 0, 0, 1, RCoord, CCoord, Index, PoseForCalibrationPlate)
    dev_set_color ('green')
    dev_display (Caltab)
    dev_set_color ('red')
    disp_caltab (WindowHandle, CaltabName, CamParam, PoseForCalibrationPlate, 1)
    dev_set_line_width (1)
    disp_circle (WindowHandle, RCoord, CCoord, gen_tuple_const(|RCoord|,1.5))
    * caltab_points (CaltabName, X, Y, Z)
    * calibrate_cameras (CalibDataID, Error)
    * To take the thickness of the calibration plate into account, the z-value
    * of the origin given by the camera pose has to be translated by the
    * thickness of the calibration plate.
    * Deactivate the following line if you do not want to add the correction.
    set_origin_pose (PoseForCalibrationPlate, 0, 0, 0, PoseCalib)
    * disp_continue_message (WindowHandle, 'black', 'true')
    * stop ()
               
    *像素距離
    distance_pp(RCoord[0],CCoord[0],RCoord[48],CCoord[48], Dis_pix)
    *像素直接轉換mm然後計算
    pix2mm(RCoord, CCoord,CamParam[2],CamParam[3],newCol,newRow)
    distance_pp(newRow[0],newCol[0],newRow[48],newCol[48], Dis_m)
    *用同一個世界座標系來計算
    image_points_to_world_plane(CamParam, PoseCalib,[RCoord[0],RCoord[48]], [CCoord[0],CCoord[48]], 'mm', X1, Y1)
    distance_pp(Y1[0],X1[0],Y1[1],X1[1],Distance)
               
    *輸出計算結果比較
    open_file('data.csv','append', FileHandle)
    fwrite_string(FileHandle, Dis_pix*0.0299+','+Dis_m*1000+','+Distance+'\n')
    close_file(FileHandle)    
               
    Message:= '計算完畢'
    disp_message (WindowHandle, Message, 'window', 12, 12, 'red', 'false')
    stop()
    

    此文檔由http://www.ihalcon.com/read-7598.html分享整理得到。

  • 博主簡介:
  • 工業自動化上位機軟件工程師、機器視覺算法工程師、運動控制算法工程師。目前從業於智能製造自動化行業。 博主郵箱:[email protected]
  • 幫忙點個贊吧。哈哈。
  • 發表評論
    所有評論
    還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
    相關文章