![]() |
OpenCV 4.13.0
Open Source Computer Vision
|
前のチュートリアル: ArUcoボードの検出
次のチュートリアル: ダイヤモンドマーカーの検出
ArUcoマーカーとボードは、高速な検出と汎用性の高さから非常に有用である。しかし、ArUcoマーカーの問題の一つは、サブピクセル精緻化を適用した後でも、コーナー位置の精度がそれほど高くないことである。
これとは対照的に、チェスボードパターンのコーナーは、各コーナーが2つの黒い正方形に囲まれているため、より高精度に精緻化できる。しかし、チェスボードパターンを見つけることは、ArUcoボードを見つけるほど汎用的ではない。すなわち、全体が完全に見えている必要があり、オクルージョン(遮蔽)は許されない。
ChArUcoボードは、これら2つのアプローチの利点を組み合わせようとするものである:
ArUco部分はチェスボードのコーナー位置を補間するために使用される。これにより、オクルージョンや部分的な見え方を許容できるため、マーカーボードの汎用性を持つ。さらに、補間されたコーナーはチェスボードに属しているため、サブピクセル精度の点で非常に正確である。
カメラキャリブレーションのように高い精度が必要な場合、Charucoボードは標準的なArUcoボードよりも良い選択肢となる。
このチュートリアルでは以下を学ぶ:
このコードは samples/cpp/tutorial_code/objectDetection/detect_board_charuco.cpp にある
目的の一覧に挙げたすべての処理を実現する方法のサンプルコードを次に示す。
arucoモジュールは、Charucoボードを表す cv::aruco::CharucoBoard クラスを提供する。これは cv::aruco::Board クラスを継承している。
このクラスは、ChArUcoの他の機能と同様に、以下で定義されている:
cv::aruco::CharucoBoard を定義するには、以下が必要である:
cv::aruco::GridBoard オブジェクトの場合と同様に、arucoモジュールは cv::aruco::CharucoBoard を簡単に作成する手段を提供する。このオブジェクトは、cv::aruco::CharucoBoard コンストラクタを用いて、これらのパラメータから簡単に作成できる:
各マーカーのIDは、cv::aruco::GridBoard コンストラクタと同様に、デフォルトでは0から始まる昇順で割り当てられる。これは、cv::aruco::Board 親クラスと同様に、board.ids を通じてidsベクトルにアクセスすることで簡単にカスタマイズできる。
cv::aruco::CharucoBoard オブジェクトが得られたら、それを印刷するための画像を作成できる。これには2つの方法がある:
apps/pattern-tools/generate_pattern.py を使用する。キャリブレーションパターンの作成を参照。cv::aruco::CharucoBoard::generateImage() を使用する。関数 cv::aruco::CharucoBoard::generateImage() は cv::aruco::CharucoBoard クラスで提供されており、以下のコードを用いて呼び出すことができる:
cv::aruco::generateImageMarker() 関数と同様である。デフォルト値は1である。出力画像は次のようになる:
完全に動作する例は、samples/cpp/tutorial_code/objectDetection/ 内の create_board_charuco.cpp に含まれている。
サンプル create_board_charuco.cpp は、現在 cv::CommandLineParser を介してコマンドラインから入力を受け取る。このファイルの場合、例となるパラメータは次のようになる:
ChArUcoボードを検出するとき、実際に検出しているのは、ボードの各チェスボードコーナーである。
ChArUcoボード上の各コーナーには、一意の識別子(id)が割り当てられている。これらのidは0からボード内のコーナーの総数までである。charucoボード検出の手順は、以下のステップに分解できる:
マーカーを検出する対象となる元画像。この画像は、ChArUcoコーナーでのサブピクセル精緻化を行うために必要である。
readCameraParameters のパラメータは次のとおりである:
この関数はこれらのパラメータを入力として受け取り、カメラキャリブレーションパラメータが有効かどうかを表すブール値を返す。キャリブレーションなしでcharucoコーナーを検出する場合、このステップは不要である。
ChArUcoコーナーの検出は、先に検出されたマーカーに基づく。したがって、まずマーカーが検出され、次にそのマーカーからChArUcoコーナーが補間される。ChArUcoコーナーを検出するメソッドは cv::aruco::CharucoDetector::detectBoard() である。
detectBoard のパラメータは次のとおりである:
image - 入力画像。charucoCorners - 検出されたコーナーの画像位置の出力リスト。charucoIds - charucoCorners 内の検出された各コーナーの出力id。markerCorners - 検出されたマーカーコーナーの入出力ベクトル。markerIds - 検出されたマーカーの識別子の入出力ベクトルmarkerCorners と markerIds が空の場合、この関数はarucoマーカーとidを検出する。
キャリブレーションパラメータが与えられている場合、ChArUcoコーナーは、まずArUcoマーカーから大まかな姿勢を推定し、次にChArUcoコーナーを画像へ再投影することで補間される。
一方、キャリブレーションパラメータが与えられていない場合、ChArUcoコーナーは、ChArUco平面とChArUco画像投影との間の対応するホモグラフィを計算することで補間される。
ホモグラフィを用いる場合の主な問題は、補間が画像の歪みに対してより敏感になることである。実際には、歪みの影響を抑えるため、ホモグラフィは各ChArUcoコーナーに最も近いマーカーのみを使って計算される。
ChArUcoボードのマーカーを検出する際、特にホモグラフィを使う場合は、マーカーのコーナー精緻化を無効にすることが推奨される。その理由は、チェスボードのマス目が近接しているため、サブピクセル処理がコーナー位置に大きな偏差を生じさせ、それがChArUcoコーナーの補間に伝播して結果が悪化するためである。
さらに、周囲の2つのマーカーが両方とも見つかったコーナーのみが返される。周囲の2つのマーカーのいずれかが検出されなかった場合、通常はその領域でオクルージョンが生じているか画像品質が良くないことを意味する。いずれにせよ、補間されたChArUcoコーナーが非常に正確であることを確実にしたいので、そのコーナーは考慮しないほうが望ましい。
ChArUcoコーナーが補間された後、サブピクセル精緻化が実行される。
ChArUcoコーナーを補間したら、おそらくそれらを描画して検出が正しいかどうかを確認したくなるだろう。これは cv::aruco::drawDetectedCornersCharuco() 関数を使えば簡単に行える。
imageCopy はコーナーが描画される画像である(通常はコーナーが検出されたのと同じ画像になる)。outputImage は、コーナーが描画された inputImage のクローンになる。charucoCorners と charucoIds は、cv::aruco::CharucoDetector::detectBoard() 関数で検出されたCharucoコーナーである。cv::Scalar である。この画像に対して:
結果は次のようになる:
次の画像のようにオクルージョンが存在する場合、一部のコーナーは明らかに見えていても、オクルージョンのため周囲のマーカーがすべて検出されているわけではなく、そのため補間されない:
サンプル動画:
完全に動作する例は、samples/cpp/tutorial_code/objectDetection/ 内の detect_board_charuco.cpp に含まれている。
サンプル detect_board_charuco.cpp は、cv::CommandLineParser を介してコマンドラインから入力を受け取るようになった。このファイルの場合、例として与える引数は次のようになる:
ChArUcoボードの最終的な目的は、高精度のキャリブレーションや姿勢推定のためにコーナーを非常に正確に見つけることである。
arucoモジュールには、ChArUcoの姿勢推定を簡単に行うための関数が用意されている。cv::aruco::GridBoard の場合と同様に、cv::aruco::CharucoBoard の座標系はボード平面上に置かれ、Z軸は内向きで、ボードの左下隅を原点とする。
objPoints はZ軸が平面に対して内向きの場合に対応する。CCW順の objPoints はZ軸が平面に対して外向きの場合に対応する。PR https://github.com/opencv/opencv_contrib/pull/3174 を参照。charucoボードの姿勢推定を行うには、cv::aruco::CharucoBoard::matchImagePoints() と cv::solvePnP() を使用する:
charucoCorners と charucoIds の引数は、cv::aruco::CharucoDetector::detectBoard() 関数で検出されたcharucoコーナーである。cameraMatrix と distCoeffs は、姿勢推定に必要なカメラキャリブレーションパラメータである。rvec と tvec の引数は、Charucoボードの出力姿勢である。cv::solvePnP() は、姿勢が正しく推定された場合に true を、そうでない場合に false を返す。失敗の主な原因は、姿勢推定に十分なコーナーがないか、それらが同一直線上にあることである。姿勢が正しく推定されたことを確認するため、cv::drawFrameAxes() を使って軸を描画できる。結果は次のようになる: (X:赤, Y:緑, Z:青)
完全に動作する例は、samples/cpp/tutorial_code/objectDetection/ 内の detect_board_charuco.cpp に含まれている。
サンプル detect_board_charuco.cpp は、cv::CommandLineParser を介してコマンドラインから入力を受け取るようになった。このファイルの場合、例として与える引数は次のようになる: