前のチュートリアル: Diamondマーカーの検出
次のチュートリアル: Arucoモジュール FAQ
ArUcoモジュールはカメラのキャリブレーションにも使用できる。カメラキャリブレーションは、カメラの内部パラメータと歪み係数を取得することからなる。これらのパラメータはカメラの光学系が変更されない限り固定されたままであるため、カメラキャリブレーションは一度だけ行えばよい。
カメラキャリブレーションは通常、OpenCVの cv::calibrateCamera() 関数を使用して実行される。この関数は、異なる視点からの環境点とそのカメラ画像への投影との間の対応関係を必要とする。一般に、これらの対応関係はチェスボードパターンのコーナーから得られる。より詳細な情報は cv::calibrateCamera() 関数のドキュメントまたはOpenCVキャリブレーションチュートリアルを参照。
ArUcoモジュールを使用すると、ArUcoマーカーのコーナーまたはChArUcoコーナーに基づいてキャリブレーションを行える。ArUcoを使ったキャリブレーションは、オクルージョンや部分的な視界を許容するため、従来のチェスボードパターンを使うよりもはるかに柔軟である。
述べたとおり、キャリブレーションはマーカーのコーナーとChArUcoコーナーのどちらを使っても行える。ただし、提供されるコーナーがマーカーのコーナーに比べてはるかに正確であるため、ChArUcoコーナーを用いる手法を強く推奨する。標準のボードを使ったキャリブレーションは、何らかの制約によりChArUcoボードを使用できない状況においてのみ用いるべきである。
ChArUco ボードによるキャリブレーション
ChArUcoボードを使ってキャリブレーションするには、標準キャリブレーションが従来のチェスボードパターンで行うのと同じように、異なる視点からボードを検出する必要がある。ただし、ChArUcoを使う利点により、オクルージョンや部分的な視界が許容され、すべての視点ですべてのコーナーが見えている必要はない。
ChArUco calibration viewpoints
cv::aruco::CharucoBoard に対して cv::calibrateCamera() を使用する例:
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 << "Point matching failed, try again." << endl;
continue;
}
cout << "Frame captured" << 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 に、視点ごとに1要素として格納される。
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 calibration viewpoints
cv::aruco::GridBoard に対して cv::calibrateCamera() を使用する例:
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 << "Frame captured" << 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