OpenCV を使用したマーカーの正確な検出に問題があります。
その問題を紹介するビデオを録画しました: http://youtu.be/IeSSW4MdyfU
ご覧のとおり、私が検出しているマーカーは、いくつかのカメラ アングルでわずかに移動しています。これはカメラのキャリブレーションの問題である可能性があることを Web で読んだので、カメラのキャリブレーション方法を説明します。何が間違っているのか教えていただけるでしょうか?
最初に、さまざまな画像からデータを収集し、キャリブレーションコーナーを_imagePoints
このようなベクトルに保存しています
std::vector<cv::Point2f> corners;
_imageSize = cvSize(image->size().width, image->size().height);
bool found = cv::findChessboardCorners(*image, _patternSize, corners);
if (found) {
cv::Mat *gray_image = new cv::Mat(image->size().height, image->size().width, CV_8UC1);
cv::cvtColor(*image, *gray_image, CV_RGB2GRAY);
cv::cornerSubPix(*gray_image, corners, cvSize(11, 11), cvSize(-1, -1), cvTermCriteria(CV_TERMCRIT_EPS+ CV_TERMCRIT_ITER, 30, 0.1));
cv::drawChessboardCorners(*image, _patternSize, corners, found);
}
_imagePoints->push_back(_corners);
それよりも、十分なデータを収集した後、次のコードでカメラの行列と係数を計算しています:
std::vector< std::vector<cv::Point3f> > *objectPoints = new std::vector< std::vector< cv::Point3f> >();
for (unsigned long i = 0; i < _imagePoints->size(); i++) {
std::vector<cv::Point2f> currentImagePoints = _imagePoints->at(i);
std::vector<cv::Point3f> currentObjectPoints;
for (int j = 0; j < currentImagePoints.size(); j++) {
cv::Point3f newPoint = cv::Point3f(j % _patternSize.width, j / _patternSize.width, 0);
currentObjectPoints.push_back(newPoint);
}
objectPoints->push_back(currentObjectPoints);
}
std::vector<cv::Mat> rvecs, tvecs;
static CGSize size = CGSizeMake(_imageSize.width, _imageSize.height);
cv::Mat cameraMatrix = [_userDefaultsManager cameraMatrixwithCurrentResolution:size]; // previously detected matrix
cv::Mat coeffs = _userDefaultsManager.distCoeffs; // previously detected coeffs
cv::calibrateCamera(*objectPoints, *_imagePoints, _imageSize, cameraMatrix, coeffs, rvecs, tvecs);
結果はビデオで見た通りです。
私は何を間違っていますか?それはコードの問題ですか?キャリブレーションを実行するために使用する画像の量 (現在、キャリブレーションが終了する前に 20 ~ 30 枚の画像を取得しようとしています)。
次のように、誤って検出されたチェス盤の角を含む画像を使用する必要があります。
または、次のような適切に検出されたチェス盤のみを使用する必要があります。
チェス盤の代わりにサークル グリッドを試してみましたが、結果は今よりずっと悪いものでした。
マーカーを検出する方法について質問がある場合:solvepnp
関数を使用しています:
solvePnP(modelPoints, imagePoints, [_arEngine currentCameraMatrix], _userDefaultsManager.distCoeffs, rvec, tvec);
modelPoints を次のように指定します。
markerPoints3D.push_back(cv::Point3d(-kMarkerRealSize / 2.0f, -kMarkerRealSize / 2.0f, 0));
markerPoints3D.push_back(cv::Point3d(kMarkerRealSize / 2.0f, -kMarkerRealSize / 2.0f, 0));
markerPoints3D.push_back(cv::Point3d(kMarkerRealSize / 2.0f, kMarkerRealSize / 2.0f, 0));
markerPoints3D.push_back(cv::Point3d(-kMarkerRealSize / 2.0f, kMarkerRealSize / 2.0f, 0));
処理画像のマーカーコーナーのimagePoints
座標です(私はそれを行うためにカスタムアルゴリズムを使用しています)