OpenCV中检测ChArUco的角点(2)
論文閱讀模塊將分享點云處理,SLAM,三維視覺,高精地圖相關(guān)的文章。公眾號致力于理解三維視覺領(lǐng)域相關(guān)內(nèi)容的干貨分享,歡迎各位加入我,我們一起每天一篇文章閱讀,開啟分享之旅,有興趣的可聯(lián)系微信dianyunpcl@163.com。
opencv中ArUco模塊實踐(1)
ArUco的生成與檢測
ArUco與AprilTag簡介
ChAruco標定板
ArUCo標記板是非常有用的,因為他們的快速檢測和多功能性。然而,ArUco標記的一個問題是,即使在應(yīng)用亞像素細化后,其角點位置的精度也不太高。相反,棋盤圖案的角點可以更精確地細化,因為每個角點被兩個黑色正方形包圍。然而,尋找棋盤圖案并不像尋找aruco棋盤那樣通用:它必須是完全可見的,并且不允許遮擋。
ChAruco標記板試圖結(jié)合這兩種方法的優(yōu)點:
ArUco部分用于內(nèi)插棋盤轉(zhuǎn)角的位置,因此它具有標記板的多功能性,因為它允許遮擋或局部視圖。此外,由于插值的角點屬于棋盤,因此它們在亞像素精度方面非常精確。
當對角點加測的要求是高精度且必要的,如在相機校準,Charuco板是一個比標準aruco板更好的選擇。
ChArUco標記板的創(chuàng)建
aruco模塊提供cv::aruco::CharucoBoard類,該類表示Charuco板,并從Board類繼承。
該類與ChArUco的其他功能一樣,定義如下:
#include <opencv2/aruco/charuco.hpp>
要定義Charuco標記板,必須:
X方向的棋盤格數(shù)。
Y方向棋盤格數(shù)。
正方形邊的長度。
標記側(cè)的長度。
標記詞典。
所有標記的ID。
對于GridBoard對象,aruco模塊提供了一個創(chuàng)建CharucoBoards的函數(shù)。
cv::aruco::CharucoBoard::create():
cv::aruco::CharucoBoard board = cv::aruco::CharucoBoard::create(5, 7, 0.04, 0.02, dictionary);
第一和第二參數(shù)分別是X和Y方向上的平方數(shù)。
第三和第四個參數(shù)分別是正方形和標記的長度。它們可以以任何單位提供,記住該標記板的估計姿勢將以相同單位測量(通常使用米)。?
最后給出了標記的字典。
默認情況下,每個標記的ID都是從0開始按升序分配的,就像在GridBoard::create()中一樣。這可以通過board.ids訪問ids向量來輕松定制,就像在board父類中一樣。
一旦我們有了CharucoBoard對象,我們就可以創(chuàng)建一個圖像來打印它。這可以通過
cv::aruco::CharucoBoard board = cv::aruco::CharucoBoard::create(5, 7, 0.04, 0.02, dictionary);cv::Mat boardImage;board.draw( cv::Size(600, 500), boardImage, 10, 1 );
第一個參數(shù)是以像素為單位的輸出圖像的大小。在本例中為600x500像素。如果這與電路板尺寸不成比例,它將以圖像為中心。
boardImage:根據(jù)標定板輸出的圖像。
第三個參數(shù)是(可選)以像素為單位的邊距,因此沒有任何標記接觸圖像邊界。在這種情況下,邊距是10。
最后,標記邊框的大小,類似于drawMarker()函數(shù)。默認值為1。
ChArUco標定板檢測
當你檢測到一個ChArUco棋盤時,實際檢測到的是棋盤的每個棋盤格角點。
ChArUco板上的每個角落都分配了一個唯一標識符(id)。這些ID從0到板中的角總數(shù)。
因此,檢測到的ChArUco板包括:
vector<Point2f>charucoCorners:檢測到的角點的圖像位置列表。
vector<int>charucoIds:charucoCorners中每個檢測到的角點的ID。
ChArUco角點的檢測基于先前檢測到的標記。因此,首先檢測標記,然后從標記中插值ChArUco角點。檢測ChArUco角點的函數(shù)是
cv::aruco::interpolateCornersCharuco()
這個例子展示了整個過程。首先,檢測標記,然后從這些標記中插值ChArUco角點。
cv::Mat inputImage;
cv::Mat cameraMatrix, distCoeffs;
// camera parameters are read from somewhere
readCameraParameters(cameraMatrix, distCoeffs);cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);cv::aruco::CharucoBoard board = cv::aruco::CharucoBoard::create(5, 7, 0.04, 0.02, dictionary);
...vector< int > markerIds;
vector< vector<Point2f> > markerCorners;cv::aruco::detectMarkers(inputImage, board.dictionary, markerCorners, markerIds);
// if at least one marker detected
if(markerIds.size() > 0) {
std::vector<cv::Point2f> charucoCorners;std::vector<int> charucoIds;cv::aruco::interpolateCornersCharuco(markerCorners, markerIds, inputImage, board, charucoCorners, charucoIds, cameraMatrix, distCoeffs);}
interpolateCornersCharuco()函數(shù)的參數(shù)為:
markerCorners和markerIds:從detectMarkers()函數(shù)中檢測到的標記物。
inputimage:檢測到標記的原始圖像。圖像是必要的執(zhí)行亞像素細化在Aruco角點。
board:CharucoBoard對象
charucockerners和charucoIds:輸出插值Charuco角點
cameraMatrix和distcoefs:可選的攝像機校準參數(shù)
函數(shù)返回插值的Charuco角點的數(shù)目。
在這種情況下,我們調(diào)用interpolateCornersCharuco()來提供相機校準參數(shù)。但是,這些參數(shù)是可選的。沒有這些參數(shù)的類似示例如下:
cv::Mat inputImage;
cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);cv::aruco::CharucoBoard board = cv::aruco::CharucoBoard::create(5, 7, 0.04, 0.02, dictionary);...
vector< int > markerIds;vector< vector<Point2f> > markerCorners;DetectorParameters params;params.doCornerRefinement = false;cv::aruco::detectMarkers(inputImage,?board.dictionary,?markerCorners,?markerIds,?params);// if at least one marker detectedif(markerIds.size() > 0) {std::vector<cv::Point2f> charucoCorners;std::vector<int> charucoIds;cv::aruco::interpolateCornersCharuco(markerCorners, markerIds, inputImage, board, charucoCorners, charucoIds);}
如果提供了校準參數(shù),ChArUco角點插值方法是,首先從ArUco標記估計一個粗略姿態(tài),然后將ChArUco角點重新投影回圖像。另一方面,如果不提供校準參數(shù),則通過計算ChArUco平面和ChArUco圖像投影之間的對應(yīng)單應(yīng)來插值ChArUco角點。
使用單應(yīng)的主要問題是插值對圖像失真更敏感。實際上,單應(yīng)僅使用每個ChArUco角點的最近標記位來執(zhí)行,以減少失真的影響。
在檢測ChArUco板的標記時,特別是在使用單應(yīng)性時,建議禁用標記的角點細化。其原因是,由于棋盤方塊的接近性,亞像素過程會在角點位置產(chǎn)生重要的偏差,這些偏差會傳播到ChArUco角點插值,產(chǎn)生較差的結(jié)果。
此外,僅返回其兩個周圍標記已找到的角點。如果沒有檢測到周圍的兩個標記中的任何一個,這通常意味著該區(qū)域存在某種遮擋或圖像質(zhì)量不好。在任何情況下,最好不要考慮該角點,因為我們想要的是確保插值的ChArUco角點非常精確。
在對ChArUco角點進行插值之后,執(zhí)行亞像素細化。
一旦我們內(nèi)插了ChArUco角點,我們可能會想畫出來看看他們的檢測是否正確。使用drawDetectedCornersCharuco()函數(shù)可以輕松完成此操作:
cv::aruco::drawDetectedCornersCharuco(image, charucoCorners, charucoIds, color);
image是繪制角點的圖像(通常與檢測角點的圖像相同)。
outputImage將是inputImage的克隆,并繪制了角點。
charucoCorners和charucoIds是從interpolateCornersCharuco()函數(shù)中檢測到的Charuco角點。
最后,最后一個參數(shù)是要繪制角點的(可選)顏色,類型為cv::Scalar。
最后,這是ChArUco檢測的完整示例(不使用校準參數(shù))
cv::VideoCapture inputVideo;inputVideo.open(0);cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);cv::aruco::CharucoBoard board = cv::aruco::CharucoBoard::create(5, 7, 0.04, 0.02, dictionary);DetectorParameters params;params.doCornerRefinement = false;while (inputVideo.grab()) {cv::Mat image, imageCopy;inputVideo.retrieve(image);image.copyTo(imageCopy);std::vector<int> ids;std::vector<std::vector<cv::Point2f> > corners;cv::aruco::detectMarkers(image,?dictionary,?corners,?ids,?params);// if at least one marker detectedif (ids.size() > 0) {cv::aruco::drawDetectedMarkers(imageCopy, corners, ids);std::vector<cv::Point2f> charucoCorners;std::vector<int> charucoIds;cv::aruco::interpolateCornersCharuco(corners, ids, image, board, charucoCorners, charucoIds);// if at least one charuco corner detectedif(charucoIds.size() > 0)cv::aruco::drawDetectedCornersCharuco(imageCopy, charucoCorners, charucoIds, cv::Scalar(255, 0, 0));}cv::imshow("out", imageCopy);char key = (char) cv::waitKey(waitTime);if (key == 27)break;}
ChArUco姿態(tài)估計
ChArUco板的最終目標是非常精確地找到角點,以便進行高精度校準或姿態(tài)估計。
aruco模塊提供了一個簡單的ChArUco姿態(tài)估計功能。與在GridBoard中一樣,CharucoBoard的坐標系放置在板平面中,Z軸指向外,并居中于板的左下角。
姿態(tài)估計的函數(shù)是estimatePosecharocboard():
cv::aruco::EstimatePoseCharocboard(charucoCorners、charucoIds、board、cameraMatrix、Distceffs、rvec、tvec);
charucoCorners和charucoIds參數(shù)是從interpolateCornersCharuco()函數(shù)中檢測到的charuco角點。
第三個參數(shù)是CharucoBoard對象。
cameraMatrix和distcoefs是姿態(tài)估計所必需的攝像機標定參數(shù)。
最后,rvec和tvec參數(shù)是Charuco板的輸出姿態(tài)。
如果正確估計了姿勢,則函數(shù)返回true,否則返回false。失敗的主要原因是沒有足夠的角點進行姿態(tài)估計或它們在同一條直線上。可以使用drawAxis()繪制軸,以檢查姿勢是否正確估計。結(jié)果是:(X:紅色,Y:綠色,Z:藍色)
完整的的位姿估計的代碼
cv::VideoCapture inputVideo;
inputVideo.open(0);cv::Mat cameraMatrix, distCoeffs;// camera parameters are read from somewherereadCameraParameters(cameraMatrix, distCoeffs);cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);cv::aruco::CharucoBoard board = cv::aruco::CharucoBoard::create(5, 7, 0.04, 0.02, dictionary);while (inputVideo.grab()) {cv::Mat image, imageCopy;inputVideo.retrieve(image);image.copyTo(imageCopy);std::vector<int> ids;std::vector<std::vector<cv::Point2f> > corners;cv::aruco::detectMarkers(image, dictionary, corners, ids);// if at least one marker detectedif (ids.size() > 0) {std::vector<cv::Point2f> charucoCorners;std::vector<int> charucoIds;cv::aruco::interpolateCornersCharuco(corners, ids, image, board, charucoCorners, charucoIds, cameraMatrix, distCoeffs);// if at least one charuco corner detectedif(charucoIds.size() > 0) {cv::aruco::drawDetectedCornersCharuco(imageCopy, charucoCorners, charucoIds, cv::Scalar(255, 0, 0));cv::Vec3d rvec, tvec;bool valid = cv::aruco::estimatePoseCharucoBoard(charucoCorners, charucoIds, board, cameraMatrix, distCoeffs, rvec, tvec);// if charuco pose is validif(valid)cv::aruco::drawAxis(imageCopy, cameraMatrix, distCoeffs, rvec, tvec, 0.1);}}cv::imshow("out", imageCopy);char key = (char) cv::waitKey(waitTime);if (key == 27)break;}
資源
三維點云論文及相關(guān)應(yīng)用分享
【點云論文速讀】基于激光雷達的里程計及3D點云地圖中的定位方法
3D目標檢測:MV3D-Net
三維點云分割綜述(上)
3D-MiniNet: 從點云中學習2D表示以實現(xiàn)快速有效的3D LIDAR語義分割(2020)
win下使用QT添加VTK插件實現(xiàn)點云可視化GUI
JSNet:3D點云的聯(lián)合實例和語義分割
大場景三維點云的語義分割綜述
PCL中outofcore模塊---基于核外八叉樹的大規(guī)模點云的顯示
基于局部凹凸性進行目標分割
基于三維卷積神經(jīng)網(wǎng)絡(luò)的點云標記
點云的超體素(SuperVoxel)
基于超點圖的大規(guī)模點云分割
更多文章可查看:點云學習歷史文章大匯總
SLAM及AR相關(guān)分享
【開源方案共享】ORB-SLAM3開源啦!
【論文速讀】AVP-SLAM:自動泊車系統(tǒng)中的語義SLAM
【點云論文速讀】StructSLAM:結(jié)構(gòu)化線特征SLAM
SLAM和AR綜述
常用的3D深度相機
AR設(shè)備單目視覺慣導SLAM算法綜述與評價
SLAM綜述(4)激光與視覺融合SLAM
Kimera實時重建的語義SLAM系統(tǒng)
SLAM綜述(3)-視覺與慣導,視覺與深度學習SLAM
易擴展的SLAM框架-OpenVSLAM
高翔:非結(jié)構(gòu)化道路激光SLAM中的挑戰(zhàn)
SLAM綜述之Lidar SLAM
基于魚眼相機的SLAM方法介紹
如果你對本文感興趣,請點擊“原文閱讀”獲取知識星球二維碼,務(wù)必按照“姓名+學校/公司+研究方向”備注加入免費知識星球,免費下載pdf文檔,和更多熱愛分享的小伙伴一起交流吧!
以上內(nèi)容如有錯誤請留言評論,歡迎指正交流。如有侵權(quán),請聯(lián)系刪除
掃描二維碼
? ? ? ? ? ? ? ? ? ?關(guān)注我們
讓我們一起分享一起學習吧!期待有想法,樂于分享的小伙伴加入免費星球注入愛分享的新鮮活力。分享的主題包含但不限于三維視覺,點云,高精地圖,自動駕駛,以及機器人等相關(guān)的領(lǐng)域。
分享及合作:群主微信“920177957”(需要按要求備注) 聯(lián)系郵箱:dianyunpcl@163.com,歡迎企業(yè)來聯(lián)系公眾號展開合作。
點一下“在看”你會更好看耶
總結(jié)
以上是生活随笔為你收集整理的OpenCV中检测ChArUco的角点(2)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: opencv中ArUco模块实践(1)
- 下一篇: 基于自适应逆透视变换的车道线SLAM