標(biāo)定與畸變矯正,解決的是同一個問題的兩端:標(biāo)定是“搞清楚相機(jī)把世界扭曲成了什么樣”,矯正是“把扭曲的圖像拉回正?!薄? alt=)
相機(jī)標(biāo)定與畸變矯正解決的是同一個問題的兩端標(biāo)定是“搞清楚相機(jī)把世界扭曲成了什么樣”矯正是“把扭曲的圖像拉回正?!?。為什么需要標(biāo)定工業(yè)視覺測量的前提是圖像中的像素坐標(biāo)和真實世界的物理坐標(biāo)之間存在確定的對應(yīng)關(guān)系。但這個關(guān)系不是簡單的線性縮放——鏡頭會引入畸變相機(jī)安裝角度會引入透視變形。標(biāo)定的目標(biāo)就是求解相機(jī)的內(nèi)參和外參內(nèi)參描述相機(jī)自身的特性焦距fx, fy、主點cx, cy、畸變系數(shù)k1, k2, p1, p2, k3。這些參數(shù)一旦標(biāo)定只要相機(jī)和鏡頭不動就保持不變。外參描述相機(jī)相對于世界坐標(biāo)系的位置和姿態(tài)旋轉(zhuǎn)矩陣 R 和平移向量 t。如果相機(jī)移動了外參需要重新標(biāo)定?;冪R頭的“先天缺陷”畸變主要分兩類徑向畸變由鏡頭形狀引起表現(xiàn)為圖像邊緣的“桶形”或“枕形”彎曲。直線拍出來變成彎的就是徑向畸變。它用 k1、k2、k3 三個系數(shù)描述越靠近邊緣越明顯。切向畸變由鏡頭和傳感器不平行引起表現(xiàn)為圖像的“剪切”變形。它用 p1、p2 兩個系數(shù)描述通常比徑向畸變小得多?;兡P偷暮诵墓绞莤_distorted x(1 k1r2 k2r? k3r?) 2p1xy p2(r2 2x2) y_distorted y(1 k1r2 k2r? k3r?) p1(r2 2y2) 2p2xy其中 r2 x2 y2。標(biāo)定的過程就是通過已知的世界坐標(biāo)和對應(yīng)的圖像坐標(biāo)反解出 k1、k2、p1、p2、k3 這些系數(shù)。標(biāo)定流程用棋盤格求解第一步制作標(biāo)定板。最常用的是棋盤格標(biāo)定板黑白方格交替每個方格的物理尺寸已知如 10mm。棋盤格的優(yōu)勢是角點檢測精度高OpenCV 和 Halcon 都有現(xiàn)成的角點檢測算子。第二步拍攝多張不同姿態(tài)的標(biāo)定板圖像。一般需要 10-20 張覆蓋圖像的各個區(qū)域中心、四角、邊緣并且標(biāo)定板要有不同的傾斜角度。只拍正對相機(jī)的圖標(biāo)定結(jié)果會不準(zhǔn)——因為畸變在邊緣最明顯必須讓標(biāo)定板出現(xiàn)在圖像邊緣。第三步檢測角點。OpenCV 用FindChessboardCorners找到棋盤格的內(nèi)角點再用CornerSubPix做亞像素精化。// OpenCV 標(biāo)定varobjectPointsnewListMat();varimagePointsnewListMat();SizeboardSizenewSize(9,6);// 內(nèi)角點數(shù)floatsquareSize10.0f;// 方格物理尺寸 mm// 對每張標(biāo)定圖MatgraynewMat();Cv2.CvtColor(image,gray,ColorConversionCodes.BGR2GRAY);varcornersnewListPoint2f();boolfoundCv2.FindChessboardCorners(gray,boardSize,corners);if(found){Cv2.CornerSubPix(gray,corners,newSize(11,11),newSize(-1,-1),newTermCriteria(CriteriaTypes.Eps|CriteriaTypes.MaxIter,30,0.001));imagePoints.Add(Mat.FromArray(corners.ToArray()));objectPoints.Add(GenerateObjectPoints(boardSize,squareSize));}// 標(biāo)定MatcameraMatrixnewMat();MatdistCoeffsnewMat();Cv2.CalibrateCamera(objectPoints,imagePoints,gray.Size(),cameraMatrix,distCoeffs,out_,out_);第四步評估標(biāo)定質(zhì)量。CalibrateCamera返回的重投影誤差reprojection error是核心指標(biāo)。它表示用標(biāo)定出的參數(shù)把世界點投影回圖像后與檢測到的角點之間的平均偏差。小于 0.5 像素算好小于 0.2 像素算優(yōu)秀。如果誤差大于 1 像素說明標(biāo)定板圖像質(zhì)量有問題或者姿態(tài)覆蓋不夠?;兂C正兩種方式方式一Undistort直接矯正。對整幅圖像做畸變矯正輸出一張“拉直”的圖。適合需要保存矯正后圖像的場景。MatundistortednewMat();Cv2.Undistort(src,undistorted,cameraMatrix,distCoeffs);方式二InitUndistortRectifyMapRemap。預(yù)先計算矯正映射表后續(xù)每幀用Remap快速應(yīng)用。高幀率場景必須用這種方式因為映射表只算一次每幀只做查表操作。Matmap1newMat(),map2newMat();Cv2.InitUndistortRectifyMap(cameraMatrix,distCoeffs,newMat(),cameraMatrix,imageSize,MatType.CV_32FC1,map1,map2);// 每幀Cv2.Remap(src,dst,map1,map2,InterpolationFlags.Linear);工業(yè)實操要點標(biāo)定板要覆蓋整個視野。畸變在圖像邊緣最嚴(yán)重如果標(biāo)定板只在中心區(qū)域拍攝邊緣的畸變系數(shù)就標(biāo)不準(zhǔn)。正確做法是讓標(biāo)定板出現(xiàn)在圖像的中心、四角、四邊每個位置都有不同傾斜角度的圖像。標(biāo)定后不要動相機(jī)和鏡頭。一旦標(biāo)定完成相機(jī)和鏡頭的相對位置、焦距、光圈都不能再變。動了任何一個標(biāo)定就失效了。工業(yè)現(xiàn)場通常把相機(jī)和鏡頭鎖死標(biāo)定一次用很久?;兂C正會損失邊緣像素。矯正后圖像邊緣可能被“拉”出視野或者出現(xiàn)黑邊。如果檢測區(qū)域靠近圖像邊緣需要預(yù)留余量。精度要求極高時用遠(yuǎn)心鏡頭。遠(yuǎn)心鏡頭的畸變極小幾乎不需要矯正而且沒有透視誤差。代價是視野小、工作距離固定、價格高。一句話總結(jié)標(biāo)定是用已知尺寸的標(biāo)定板反解出相機(jī)的內(nèi)參和畸變系數(shù)。矯正是用這些系數(shù)把畸變圖像拉直。標(biāo)定的質(zhì)量決定了測量的上限——重投影誤差小于 0.2 像素是工業(yè)級標(biāo)定的基本門檻。