20

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 枚の画像を取得しようとしています)。

次のように、誤って検出されたチェス盤の角を含む画像を使用する必要があります。

写真1

または、次のような適切に検出されたチェス盤のみを使用する必要があります。

写真2 写真3

チェス盤の代わりにサークル グリッドを試してみましたが、結果は今よりずっと悪いものでした。

マーカーを検出する方法について質問がある場合: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座標です(私はそれを行うためにカスタムアルゴリズムを使用しています)

4

3 に答える 3

5

問題を適切にデバッグするには、すべてのコードが必要です:-)

@kobejohnコメントで引用されているチュートリアル (キャリブレーションポーズ) で提案されているアプローチに従っていると仮定し、コードが次の手順に従うようにします。

  1. チェス盤のターゲットのさまざまな画像を収集する
  2. ポイントの画像でチェス盤の角を見つける 1)
  3. カメラを ( で)キャリブレーションし、結果として固有のカメラ パラメーター ( と呼びましょう) とレンズ歪みパラメーター ( と呼びましょう)cv::calibrateCameraを取得します。intrinsicdistortion
  4. 独自のカスタム ターゲットの画像を収集し (ターゲットはビデオの 0:57 に表示されます)、次の図に示すように、Axadiw 独自のカスタム ターゲット関連するポイントを見つけます (画像で見つけたポイントimage_custom_target_verticesworld_custom_target_vertices対応する 3D ポイントを呼び出しましょう)。 )。
  5. ポイント 4 で取得した独自のカスタム ターゲットの画像から、カメラの回転行列 ( と呼びましょうR) と平行移動ベクトル ( と呼びましょう) を推定します。tcv::solvePnPcv::solvePnP(world_custom_target_vertices,image_custom_target_vertices,intrinsic,distortion,R,t)
  6. 3D で 8 つのコーナーの立方体を指定すると (それらと呼びましょうworld_cube_vertices)、8 つの 2D イメージ ポイント (それらと呼びましょう) をlike this oneimage_cube_verticesへの呼び出しによって取得しますcv2::projectPointscv::projectPoints(world_cube_vertices,R,t,intrinsic,distortion,image_cube_vertices)
  7. draw独自の関数で立方体を描画します。

ここで、描画手順の最終結果は、以前に計算されたすべてのデータに依存するため、問題がどこにあるかを見つける必要があります。

キャリブレーション:回答で見たように、3) では、コーナーが適切に検出されていない画像を破棄する必要があります。「悪い」チェス盤のターゲット イメージを破棄するには、再投影エラーのしきい値が必要です。キャリブレーションチュートリアルからの引用:

再投影エラー

再投影誤差は、見つかったパラメーターがどれほど正確であるかを適切に推定します。これは、可能な限りゼロに近づける必要があります。固有行列、歪み行列、回転行列、平行移動行列が与えられたら、まず cv2.projectPoints() を使用してオブジェクト ポイントをイメージ ポイントに変換します。次に、変換で得られたものとコーナー検出アルゴリズムとの間の絶対ノルムを計算します。平均誤差を見つけるために、すべてのキャリブレーション画像について計算された誤差の算術平均を計算します。

通常、いくつかの実験で適切なしきい値を見つけることができます。この追加の手順により、 と の値が向上intrinsicしますdistortion

独自のカスタム ターゲットを見つける: ポイント 4) とラベル付けしたステップで、独自のカスタム ターゲットを見つける方法を説明しているようには思えません。期待どおりの結果が得られますimage_custom_target_verticesか? その結果が「悪い」画像を破棄しますか?

カメラのポーズ: 5) では 3) で見つかったものを使用していると思いますintrinsicが、その間、カメラは何も変更されていませんか? Callari のカメラ キャリブレーションの 2 番目のルールを参照します。

カメラキャリブレーションの第 2 のルール: 「キャリブレーション後はレンズに触れないでください」。特に、フォーカシングとアイリスの両方が非線形レンズの歪みに影響を与え、(レンズによってはそれほど影響はありませんが) 視野に影響を与えるため、焦点を合わせ直したり、F ストップを変更したりすることはできません。もちろん、レンズのジオメトリにはまったく影響しないため、露出時間は完全に自由に変更できます。

そして、draw機能に問題があるかもしれません。

于 2013-11-24T10:57:07.760 に答える
1

まだ興味がある方へ:これは古い質問ですが、あなたの問題は悪いキャリブレーションではないと思います. OpenCV と SceneKit を使用して iOS 用の AR アプリを開発しましたが、同じ問題が発生しました。

あなたの問題は立方体の間違ったレンダリング位置だと思います:OpenCVのsolvePnPはマーカー中心のX、Y、Z座標を返しますが、マーカーのZ軸に沿った特定の距離で、マーカーの上に立方体をレンダリングしたいです。立方体の側面のサイズのちょうど半分です。したがって、この距離のマーカー移動ベクトルの Z 座標を改善する必要があります。

実際、立方体を上から見ると、立方体は適切にレンダリングされています。問題を説明するために画像を作成しましたが、私の評判では投稿できません。

于 2015-07-24T15:51:44.400 に答える