轉(zhuǎn)載自:雙目測距系列(二)魚眼鏡頭雙目標(biāo)定及測距
作者:ltshan139
前言
這幾天把基于opencv C++ api將魚眼鏡頭的雙目標(biāo)定以及測距功能實現(xiàn)完畢,效果還可以,至少對齊得非常棒。 這里把其流程及其關(guān)鍵函數(shù)在這里總結(jié)一下。
對于雙目標(biāo)定而言,opencv一共支持兩種模型:普通針孔相機模型和魚眼相機模型fisheye。后者是opencv3.0后才開始支持的。從使用角度講,它倆主要差別就在于畸變系數(shù)不一樣。
雙目測距流程一共分為四大步:標(biāo)定,對齊,匹配以及測距。這點對于普通攝像頭模型和魚眼模型都適用。下面就基于魚眼攝像頭模型來講解各個步驟具體內(nèi)容。
標(biāo)定
標(biāo)定Calibration包括單目標(biāo)定和雙目標(biāo)定,前者的輸出結(jié)果主要是內(nèi)參(3x3矩陣,包括fx,fy以及cx和cy)和畸變系數(shù)(1x4矩陣 K1,K2,K3,K4);后者輸出的主要是是外參,即右攝像頭基于左攝像頭的姿態(tài),包括R和T兩個矩陣。
標(biāo)定一個主要工作就是對著標(biāo)定板拍圖,標(biāo)定板最好遍布整個圖像區(qū)域,一般20~30張就足夠了。 opencv目前可以對三種pattern的標(biāo)定板:棋盤格,圓以及非對稱圓來找角點,其API如下所示:
case Settings::CHESSBOARD:
found = findChessboardCorners( view, s.boardSize, pointBuf, chessBoardFlags);
break;
case Settings::CIRCLES_GRID:
found = findCirclesGrid( view, s.boardSize, pointBuf );
break;
case Settings::ASYMMETRIC_CIRCLES_GRID:
found = findCirclesGrid( view, s.boardSize, pointBuf, CALIB_CB_ASYMMETRIC_GRID );
角點正確找到后,就可以開始單目標(biāo)定,其對應(yīng)API為:
CV_EXPORTS_W double calibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, const Size& image_size,
InputOutputArray K, InputOutputArray D, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, int flags = 0,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, DBL_EPSILON));
單目標(biāo)定結(jié)束后,接下來就是雙目標(biāo)定:
CV_EXPORTS_W double stereoCalibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2,
InputOutputArray K1, InputOutputArray D1, InputOutputArray K2, InputOutputArray D2, Size imageSize,
OutputArray R, OutputArray T, int flags = fisheye::CALIB_FIX_INTRINSIC,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, DBL_EPSILON));
這里需要注意的是,雙目標(biāo)定可以基于前面單目標(biāo)定出來的內(nèi)參來直接算R和T,也可以將單目內(nèi)參作為一個初始值來重新迭代計算出新的內(nèi)參和R以及T。
對齊
攝像頭內(nèi)參和外參都有了之后,就可以開始調(diào)用下面的API來分別獲得左、右攝像頭新的旋轉(zhuǎn)矩陣R和內(nèi)參投影矩陣P。
CV_EXPORTS_W void stereoRectify(InputArray K1, InputArray D1, InputArray K2, InputArray D2, const Size &imageSize, InputArray R, InputArray tvec,
OutputArray R1, OutputArray R2, OutputArray P1, OutputArray P2, OutputArray Q, int flags, const Size &newImageSize = Size(),
double balance = 0.0, double fov_scale = 1.0);
緊接著是基于新的矩陣來生成左右攝像頭的映射表left_mapx, left_mapy, right_mapx以及right_mapy。
CV_EXPORTS_W void initUndistortRectifyMap(InputArray K, InputArray D, InputArray R, InputArray P,
const cv::Size& size, int m1type, OutputArray map1, OutputArray map2);
有了映射表mapx和mapy,在后面測距的時候就可以調(diào)用remap()來對新的測試圖片進行校正。
匹配
匹配是相對最耗時的步驟,即使前面左右圖像對齊后,只需要在行上來匹配。常用的匹配算法有SGBM,BM等等。相對來講,SGBM兼顧了速度和準(zhǔn)確度,因而用的比較多。
Ptr sgbm = StereoSGBM::create(0, 16, 3);
sgbm->setPreFilterCap(63);
sgbm->setBlockSize(pParas->sgbmWindowSize);
int channel_cnt = left_rectify_img.channels();
sgbm->setP1(8 * channel_cnt * pParas->sgbmWindowSize * pParas->sgbmWindowSize);
sgbm->setP2(32 * channel_cnt * pParas->sgbmWindowSize * pParas->sgbmWindowSize);
sgbm->setMinDisparity(0);
sgbm->setNumDisparities(pParas->NumDisparities);
sgbm->setUniquenessRatio(pParas->UniquenessRatio);
sgbm->setSpeckleWindowSize(101);
sgbm->setSpeckleRange(10);
sgbm->setDisp12MaxDiff(-1);
sgbm->setMode(StereoSGBM::MODE_SGBM);
opencv已經(jīng)將匹配算法 封裝的很好了,唯一需要注意的就是參數(shù)值得調(diào)節(jié)會帶來不一樣得匹配效果。常見的需要調(diào)節(jié)的參數(shù)有:
paras.sgbmWindowSize = 7;
paras.NumDisparities = 16 * 20;
paras.UniquenessRatio = 12;
測距
匹配完成就能得到視差圖disparity map。 有了視差圖,每個點的Z方向上深度值獲取就變得簡單了。通過下面公式:
Z = B * fx / d
B是兩個攝像頭之間的距離,其值等于外參平移矩陣X方向上的絕對值,即abs(T.at(0,0))。
fx則為左攝像頭內(nèi)參矩陣的第一個值m_fisheye_intrinsicsL.val[0]
d則為每個像素在左右攝像頭像素坐標(biāo)系上X方向的差,由前面匹配步驟所得。
推薦閱讀
- 雙目測距系列(一)標(biāo)定工具的開發(fā)
- 《SSD和MobilenetSSD模型的訓(xùn)練,量化以及在海思芯片上的部署》視頻課程的介紹
- 《華為海思35xx開發(fā)板的SDK環(huán)境搭建》視頻課程的介紹
- 《基于海思35xx nnie引擎進行經(jīng)典目標(biāo)檢測算法模型推理》視頻課程介紹
更多海思AI芯片方案學(xué)習(xí)筆記歡迎關(guān)注海思AI芯片方案學(xué)習(xí)。
審核編輯:符乾江
-
AI
+關(guān)注
關(guān)注
87文章
29850瀏覽量
268148 -
深度學(xué)習(xí)
+關(guān)注
文章
5471瀏覽量
120903
發(fā)布評論請先 登錄
相關(guān)推薦
評論