charuco 교정 보드

소개



OpenCV에서 카메라 캘리브레이션을 하는 경우, 타겟으로서 체스보드 이미지 이나 원 그리드 이미지 를 사용하는 경우가 많다고 생각합니다.
캘리브레이션 조사 중 체스보드 이미지의 하얀 송어 부분에 뭔가 QR 코드 스타일의 패턴이있는 것을 볼 수있었습니다.
조사해 보면, Opencv contrib의 AR 마커 검출등의 모듈인 aruco 모듈안의 기능의 하나, charuco 모듈이라고 하는 것이었으므로, 시험에 사용해 보기로 했습니다.

참고



소스 코드 등은 OpenCV의 레퍼런스를 참고로 하고 있습니다.
htps : // / cs. 오펜 cv. rg / 4.1.2 / df / d4 아 / 쓰리 아 l_ 캬루코_에서 c 치오. HTML

보드 이미지 만들기



우선, 캘리브레이션에 사용하는 보드의 이미지를 작성할 필요가 있습니다만, 그 이미지를 작성하는 기능도 charuco 모듈에 포함되어 있습니다.
다음 코드를 사용하여 교정 이미지를 만들 수 있습니다.

main.cpp
#include <opencv2/opencv.hpp>
#include <opencv2/aruco/charuco.hpp>

int main(int argc, const char * argv[]) {
    //マーカ辞書作成 6x6マスのマーカを250種類生成
    cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);

    //charucoボード生成 10x7マスのチェスボード、グリッドのサイズ0.04f、グリッド内マーカのサイズ0.02f
    cv::Ptr<cv::aruco::CharucoBoard> board = cv::aruco::CharucoBoard::create(10, 7, 0.04f, 0.02f, dictionary);
    cv::Mat boardImage;
    board->draw(cv::Size(1920, 1080), boardImage, 10, 1);
    cv::imwrite("BoardImage.jpg", boardImage);
}

↓와 같은 이미지를 출력할 수 있습니다.


이 이미지를 용지 등에 인쇄하여 캘리브레이션용 촬영을 수행합니다.
이번에는 귀찮았기 때문에 노트북에 모니터에 찍은 상태로 촬영해 보겠습니다.

탐지



카메라는 iPhone XS 카메라를 사용했습니다.

검색 소스 코드는 다음과 같습니다.

main.cpp
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/aruco/charuco.hpp>

int detectCharucoBoard(std::string srcPath, std::string dstPath)
{
    cv::Mat image = cv::imread(srcPath);
    cv::Mat imageCopy = image.clone();

    //マーカ辞書作成 6x6マスのマーカを250種類生成
    cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);

    //charucoボード生成 10x7マスのチェスボード、グリッドのサイズ0.04f、グリッド内マーカのサイズ0.02f
    cv::Ptr<cv::aruco::CharucoBoard> board = cv::aruco::CharucoBoard::create(10, 7, 0.04f, 0.02f, dictionary);

    //マーカー検出時メソッドを指定
    cv::Ptr<cv::aruco::DetectorParameters> params = cv::aruco::DetectorParameters::create();
    params->cornerRefinementMethod = cv::aruco::CORNER_REFINE_NONE;

    //マーカー検出
    std::vector<int> markerIds;
    std::vector<std::vector<cv::Point2f> > markerCorners;
    cv::aruco::detectMarkers(image, board->dictionary, markerCorners, markerIds, params);

    if (markerIds.size() > 0) {

        //マーカー位置を描画
        cv::aruco::drawDetectedMarkers(imageCopy, markerCorners, markerIds);

        //マーカーの座標をもとに、チェスボード画像の交点を検出
        std::vector<cv::Point2f> charucoCorners;
        std::vector<int> charucoIds;
        cv::aruco::interpolateCornersCharuco(markerCorners, markerIds, image, board, charucoCorners, charucoIds);
        if (charucoIds.size() > 0)
        {
            //チェスボード交点位置を描画
            cv::aruco::drawDetectedCornersCharuco(imageCopy, charucoCorners, charucoIds, cv::Scalar(0, 0, 255));
        }
    }

    cv::imwrite(dstPath, imageCopy);

    return 0;
}


int main(int argc, const char * argv[]) {

    detectCharucoBoard("./IMG_5410.jpeg", "./IMG_5410_detect.jpg");
    detectCharucoBoard("./IMG_5411.jpeg", "./IMG_5411_detect.jpg");
    detectCharucoBoard("./IMG_5412.jpeg", "./IMG_5412_detect.jpg");

    return 0;
}


이미지를 보자.
이 이미지는 ...


이렇게 됩니다. 마커(파란색 id)도 체스보드 교차점(빨간색 id)도 모두 검출할 수 있는 것 같습니다.


이것만이라면, 별로 보통 체스 보드에서도 좋지 않다? 라는 느낌이 듭니다.

그러나 이미지를 볼 수 있듯이 charuco 모듈에서 감지되는 체스 보드의 교차점에는 각각 별도의 ID 번호가 있습니다. 아마도이 교차점 ID는 교차점에 가장 가까운 마커 ID를 기반으로 할당하는 것 같습니다. 이렇게하면 일반 체스 보드와 약간 다른 촬영을 할 수 있습니다. 그것은...


이 방법으로 전체 보드가 보이지 않더라도 체스 보드 교차점을 감지 할 수 있습니다.
일반 체스보드 교차점 감지 함수 cv::findChessboardCorners를 사용하면 지정된 매스의 체스보드 이미지 전체가 표시되지 않으면 감지할 수 없습니다. 그래서 카메라를 보드에 가까이 하거나 보드를 화각의 가장자리에서 촬영하려고 하면 보드가 화각 밖으로 튀어나와 보드를 검출할 수 없게 되는 경우가 있었습니다. 그 때문에 통상의 체스보드라면 캘리브레이션용의 촬영 자체가 상당히 번거롭거나 어려웠던 경우가 많습니다만, 이것을 사용하면 효율적으로 촬영할 수 있을 것 같고, 체스 보드의 일부라도 좋은 것 , 전체를 찍지 않아도 좋은 것을 이용해 여러가지 응용할 수 있을 것 같습니다.

덧붙여서 더 업으로 촬영해도 OK였습니다.



요약



charuco의 보드 감지를 시도했습니다.
기존의 체스보드와는 사양이 다른 검출을 할 수 있었으므로, 어떻게 응용할지 생각해 보고 싶습니다.

좋은 웹페이지 즐겨찾기