上一教程: 菱形标记的检测
下一教程: Aruco模块常见问题
ArUco模块也可用于标定相机。相机标定包括获取相机内参和畸变系数。除非修改相机光学器件,否则这些参数保持不变,因此相机标定只需进行一次。
相机标定通常使用OpenCV的cv::calibrateCamera()
函数。此函数需要一些环境点与其在不同视角相机图像中的投影之间的对应关系。通常,这些对应关系是从棋盘格图案的角点获得的。有关详细信息,请参阅cv::calibrateCamera()
函数文档或OpenCV标定教程。
使用ArUco模块,可以基于ArUco标记角点或ChArUco角点进行标定。使用ArUco进行标定比使用传统的棋盘格图案更通用,因为它允许遮挡或部分视图。
如上所述,标定可以使用标记角点或ChArUco角点进行。但是,强烈建议使用ChArUco角点方法,因为与标记角点相比,提供的角点精度更高。只有在由于某种限制无法使用ChArUco棋盘的情况下,才应使用标准棋盘进行标定。
使用ChArUco棋盘进行标定
要使用ChArUco棋盘进行标定,需要从不同的视角检测棋盘,这与标准标定使用传统棋盘格图案的方式相同。但是,由于使用ChArUco的优势,允许遮挡和部分视图,并且并非所有角点都需要在所有视角中可见。
ChArUco标定视角
使用cv::calibrateCamera()
的示例,用于cv::aruco::CharucoBoard
vector<Mat> allCharucoCorners, allCharucoIds;
vector<vector<Point2f>> allImagePoints;
vector<vector<Point3f>> allObjectPoints;
vector<Mat> allImages;
while(inputVideo.
grab()) {
vector<int> markerIds;
vector<vector<Point2f>> markerCorners;
Mat currentCharucoCorners, currentCharucoIds;
vector<Point3f> currentObjectPoints;
vector<Point2f> currentImagePoints;
detector.detectBoard(image, currentCharucoCorners, currentCharucoIds);
if(key ==
'c' && currentCharucoCorners.
total() > 3) {
board.matchImagePoints(currentCharucoCorners, currentCharucoIds, currentObjectPoints, currentImagePoints);
if(currentImagePoints.empty() || currentObjectPoints.empty()) {
cout << "点匹配失败,请重试。" << endl;
continue;;
}
cout << "帧已捕获" << endl;
allCharucoCorners.push_back(currentCharucoCorners);
allCharucoIds.push_back(currentCharucoIds);
allImagePoints.push_back(currentImagePoints);
allObjectPoints.push_back(currentObjectPoints);
allImages.push_back(image);
imageSize = image.
size();
}
}
Mat cameraMatrix, distCoeffs;
if(calibrationFlags & CALIB_FIX_ASPECT_RATIO) {
cameraMatrix = Mat::eye(3, 3,
CV_64F);
cameraMatrix.
at<
double>(0, 0) = aspectRatio;
}
double repError =
calibrateCamera(allObjectPoints, allImagePoints, imageSize, cameraMatrix, distCoeffs,
每个视角捕获的ChArUco角点和ChArUco标识符存储在向量allCharucoCorners
和allCharucoIds
中,每个视角一个元素。
calibrateCamera()
函数将使用相机标定参数填充cameraMatrix
和distCoeffs
数组。它将返回从标定中获得的重投影误差。rvecs
和tvecs
中的元素将填充每个视角中估计的相机姿态(相对于ChArUco棋盘)。
最后,calibrationFlags
参数确定标定的一些选项。
完整的可运行示例包含在samples/cpp/tutorial_code/objectDetection
文件夹中的calibrate_camera_charuco.cpp
中。
这些示例现在通过cv::CommandLineParser
从命令行接收输入。对于此文件,示例参数将如下所示:
"camera_calib.txt" -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10
-v=path/img_%02d.jpg
来自opencv/samples/cpp/tutorial_code/objectDetection/tutorial_camera_charuco.yml
的相机标定参数是通过从这个文件夹放置的img_00.jpg-img_03.jpg
获得的。
使用ArUco棋盘进行标定
如前所述,建议使用ChAruco棋盘而不是ArUco棋盘进行相机标定,因为ChArUco角点比标记角点更准确。但是,在某些特殊情况下,可能需要使用基于ArUco棋盘的标定。与之前的情况一样,它需要从不同的视角检测ArUco棋盘。
ArUco标定视角
使用cv::calibrateCamera()
的示例,用于cv::aruco::GridBoard
aruco::GridBoard gridboard(
Size(markersX, markersY), markerLength, markerSeparation, dictionary);
aruco::ArucoDetector detector(dictionary, detectorParams);
vector<vector<vector<Point2f>>> allMarkerCorners;
vector<vector<int>> allMarkerIds;
while(inputVideo.
grab()) {
vector<int> markerIds;
vector<vector<Point2f>> markerCorners, rejectedMarkers;
detector.detectMarkers(image, markerCorners, markerIds, rejectedMarkers);
if(refindStrategy) {
detector.refineDetectedMarkers(image, gridboard, markerCorners, markerIds, rejectedMarkers);
}
if(key == 'c' && !markerIds.empty()) {
cout << "帧已捕获" << endl;
allMarkerCorners.push_back(markerCorners);
allMarkerIds.push_back(markerIds);
imageSize = image.
size();
}
}
Mat cameraMatrix, distCoeffs;
if(calibrationFlags & CALIB_FIX_ASPECT_RATIO) {
cameraMatrix = Mat::eye(3, 3,
CV_64F);
cameraMatrix.
at<
double>(0, 0) = aspectRatio;
}
vector<Point3f> objectPoints;
vector<Point2f> imagePoints;
vector<Mat> processedObjectPoints, processedImagePoints;
size_t nFrames = allMarkerCorners.size();
for(size_t frame = 0; frame < nFrames; frame++) {
Mat currentImgPoints, currentObjPoints;
gridboard.matchImagePoints(allMarkerCorners[frame], allMarkerIds[frame], currentObjPoints, currentImgPoints);
if(currentImgPoints.total() > 0 && currentObjPoints.total() > 0) {
processedImagePoints.push_back(currentImgPoints);
processedObjectPoints.push_back(currentObjPoints);
}
}
double repError = calibrateCamera(processedObjectPoints, processedImagePoints, imageSize, cameraMatrix, distCoeffs,
完整的示例代码位于 `samples/cpp/tutorial_code/objectDetection` 文件夹中的 `calibrate_camera.cpp` 文件中。
这些示例现在通过cv::CommandLineParser
从命令行接收输入。对于此文件,示例参数将如下所示:
"camera_calib.txt" -w=5 -h=7 -l=100 -s=10 -d=10 -v=path/aruco_videos_or_images