3D座標系でオブジェクトを見つけるタスクがあります。ほぼ正確なXおよびY座標を取得する必要があるため、この写真のオレンジ色のボールのように、移動するオブジェクトの上部に配置される既知のZ座標を持つ1つのカラーマーカーを追跡することにしました。
最初に、カメラキャリブレーションを行って固有のパラメーターを取得し、その後、次のコードのようにcv :: solvePnPを使用して回転ベクトルと平行移動ベクトルを取得しました。
std::vector<cv::Point2f> imagePoints;
std::vector<cv::Point3f> objectPoints;
//img points are green dots in the picture
imagePoints.Push_back(cv::Point2f(271.,109.));
imagePoints.Push_back(cv::Point2f(65.,208.));
imagePoints.Push_back(cv::Point2f(334.,459.));
imagePoints.Push_back(cv::Point2f(600.,225.));
//object points are measured in millimeters because calibration is done in mm also
objectPoints.Push_back(cv::Point3f(0., 0., 0.));
objectPoints.Push_back(cv::Point3f(-511.,2181.,0.));
objectPoints.Push_back(cv::Point3f(-3574.,2354.,0.));
objectPoints.Push_back(cv::Point3f(-3400.,0.,0.));
cv::Mat rvec(1,3,cv::DataType<double>::type);
cv::Mat tvec(1,3,cv::DataType<double>::type);
cv::Mat rotationMatrix(3,3,cv::DataType<double>::type);
cv::solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec);
cv::Rodrigues(rvec,rotationMatrix);
すべてのマトリックスを取得した後、この方程式は、イメージポイントをワールド座標に変換するのに役立ちます。
ここで、MはcameraMatrix、R-rotationMatrix、t-tvec、sは不明です。 Zconstは、オレンジ色のボールがある高さを表します。この例では、285 mmです。したがって、最初に「s」を取得するために前の方程式を解く必要があり、イメージポイントを選択してX座標とY座標を見つけることができます。
これを解決するには、Zconstが既知であるため、行列の最後の行を使用して変数 "s"を見つけることができます。そのためのコードは次のとおりです。
cv::Mat uvPoint = (cv::Mat_<double>(3,1) << 363, 222, 1); // u = 363, v = 222, got this point using mouse callback
cv::Mat leftSideMat = rotationMatrix.inv() * cameraMatrix.inv() * uvPoint;
cv::Mat rightSideMat = rotationMatrix.inv() * tvec;
double s = (285 + rightSideMat.at<double>(2,0))/leftSideMat.at<double>(2,0));
//285 represents the height Zconst
std::cout << "P = " << rotationMatrix.inv() * (s * cameraMatrix.inv() * uvPoint - tvec) << std::endl;
この後、私は結果を得ました:P = [-2629.5、1272.6、285。]
そして、それを測定と比較すると、次のとおりです。Preal = [-2629.6、1269.5、285。]
エラーは非常に小さく、これは非常に良好ですが、このボックスをこの部屋の端に移動すると、エラーは20〜40mmになる可能性があり、それを改善したいと思います。誰でも私を助けることができますか、何か提案がありますか?
構成を考えると、エッジでの20〜40mmのエラーは平均です。あなたはすべてをうまくやったようです。
カメラ/システム構成を変更しないと、より良い結果を得るのは難しいでしょう。カメラのキャリブレーションをやり直してより良い結果を期待することはできますが、これによりそれらが改善されることはありません(そして、最終的に悪い結果になる可能性があるので、実際の内部パラメータを消去しないでください)
Count0で述べたように、より高い精度が必要な場合は、複数の測定を行う必要があります。
歪んだ画像または歪んでいない画像から緑色のドット(imagePoints)を取得していますか?関数solvePnPは既にimagePointsを歪ませていないため(歪み係数を渡さないか、nullとして渡さない限り)。歪みのない画像からそれらを取得している場合、それらのimagePointsを2回歪ませていない可能性があり、これによりコーナーでエラーが増加します。
https://github.com/Itseez/opencv/blob/master/modules/calib3d/src/solvepnp.cpp