1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 23:33:05 +04:00

Merge pull request #24126 from AleksandrPanov:fix_charuco_checkBoard

fix charuco checkBoard
This commit is contained in:
Alexander Smorkalov
2023-09-20 14:38:14 +03:00
committed by GitHub
4 changed files with 74 additions and 10 deletions
@@ -166,11 +166,11 @@ public:
*/
CV_WRAP std::vector<Point3f> getChessboardCorners() const;
/** @brief get CharucoBoard::nearestMarkerIdx
/** @brief get CharucoBoard::nearestMarkerIdx, for each charuco corner, nearest marker index in ids array
*/
CV_PROP std::vector<std::vector<int> > getNearestMarkerIdx() const;
/** @brief get CharucoBoard::nearestMarkerCorners
/** @brief get CharucoBoard::nearestMarkerCorners, for each charuco corner, nearest marker corner id of each marker
*/
CV_PROP std::vector<std::vector<int> > getNearestMarkerCorners() const;
+2 -1
View File
@@ -319,8 +319,9 @@ struct CharucoBoardImpl : Board::Impl {
// vector of chessboard 3D corners precalculated
std::vector<Point3f> chessboardCorners;
// for each charuco corner, nearest marker id and nearest marker corner id of each marker
// for each charuco corner, nearest marker index in ids array
std::vector<std::vector<int> > nearestMarkerIdx;
// for each charuco corner, nearest marker corner id of each marker
std::vector<std::vector<int> > nearestMarkerCorners;
void createCharucoBoard();
@@ -5,6 +5,7 @@
#include "../precomp.hpp"
#include <opencv2/calib3d.hpp>
#include <opencv2/core/utils/logger.hpp>
#include "opencv2/objdetect/charuco_detector.hpp"
#include "aruco_utils.hpp"
@@ -26,12 +27,13 @@ struct CharucoDetector::CharucoDetectorImpl {
bool checkBoard(InputArrayOfArrays markerCorners, InputArray markerIds, InputArray charucoCorners, InputArray charucoIds) {
vector<Mat> mCorners;
markerCorners.getMatVector(mCorners);
Mat mIds = markerIds.getMat();
const Mat& mIds = markerIds.getMat();
Mat chCorners = charucoCorners.getMat();
Mat chIds = charucoIds.getMat();
const Mat& chCorners = charucoCorners.getMat();
const Mat& chIds = charucoIds.getMat();
const vector<int>& boardIds = board.getIds();
vector<vector<int> > nearestMarkerIdx = board.getNearestMarkerIdx();
const vector<vector<int> >& nearestMarkerIdx = board.getNearestMarkerIdx();
vector<Point2f> distance(board.getNearestMarkerIdx().size(), Point2f(0.f, std::numeric_limits<float>::max()));
// distance[i].x: max distance from the i-th charuco corner to charuco corner-forming markers.
// The two charuco corner-forming markers of i-th charuco corner are defined in getNearestMarkerIdx()[i]
@@ -41,13 +43,19 @@ struct CharucoDetector::CharucoDetectorImpl {
Point2f charucoCorner(chCorners.ptr<Point2f>(0)[i]);
for (size_t j = 0ull; j < mIds.total(); j++) {
int idMaker = mIds.ptr<int>(0)[j];
// skip the check if the marker is not in the current board.
if (find(boardIds.begin(), boardIds.end(), idMaker) == boardIds.end())
continue;
Point2f centerMarker((mCorners[j].ptr<Point2f>(0)[0] + mCorners[j].ptr<Point2f>(0)[1] +
mCorners[j].ptr<Point2f>(0)[2] + mCorners[j].ptr<Point2f>(0)[3]) / 4.f);
float dist = sqrt(normL2Sqr<float>(centerMarker - charucoCorner));
// check distance from the charuco corner to charuco corner-forming markers
if (nearestMarkerIdx[chId][0] == idMaker || nearestMarkerIdx[chId][1] == idMaker) {
int nearestCornerId = nearestMarkerIdx[chId][0] == idMaker ? board.getNearestMarkerCorners()[chId][0] : board.getNearestMarkerCorners()[chId][1];
// nearestMarkerIdx contains for each charuco corner, nearest marker index in ids array
const int nearestMarkerId1 = boardIds[nearestMarkerIdx[chId][0]];
const int nearestMarkerId2 = boardIds[nearestMarkerIdx[chId][1]];
if (nearestMarkerId1 == idMaker || nearestMarkerId2 == idMaker) {
int nearestCornerId = nearestMarkerId1 == idMaker ? board.getNearestMarkerCorners()[chId][0] : board.getNearestMarkerCorners()[chId][1];
Point2f nearestCorner = mCorners[j].ptr<Point2f>(0)[nearestCornerId];
// distToNearest: distance from the charuco corner to charuco corner-forming markers
float distToNearest = sqrt(normL2Sqr<float>(nearestCorner - charucoCorner));
distance[chId].x = max(distance[chId].x, distToNearest);
// check that nearestCorner is nearest point
@@ -363,6 +371,7 @@ void CharucoDetector::detectBoard(InputArray image, OutputArray charucoCorners,
InputOutputArrayOfArrays markerCorners, InputOutputArray markerIds) const {
charucoDetectorImpl->detectBoard(image, charucoCorners, charucoIds, markerCorners, markerIds);
if (charucoDetectorImpl->checkBoard(markerCorners, markerIds, charucoCorners, charucoIds) == false) {
CV_LOG_DEBUG(NULL, "ChArUco board is built incorrectly");
charucoCorners.release();
charucoIds.release();
}
@@ -769,4 +769,58 @@ TEST_P(CharucoBoard, testWrongSizeDetection)
ASSERT_TRUE(detectedCharucoIds.empty());
}
TEST(Charuco, testSeveralBoardsWithCustomIds)
{
Size res{500, 500};
Mat K = (Mat_<double>(3,3) <<
0.5*res.width, 0, 0.5*res.width,
0, 0.5*res.height, 0.5*res.height,
0, 0, 1);
Mat expected_corners = (Mat_<float>(9,2) <<
200, 200,
250, 200,
300, 200,
200, 250,
250, 250,
300, 250,
200, 300,
250, 300,
300, 300
);
aruco::Dictionary dict = cv::aruco::getPredefinedDictionary(aruco::DICT_4X4_50);
vector<int> ids1 = {0, 1, 33, 3, 4, 5, 6, 8}, ids2 = {7, 9, 44, 11, 12, 13, 14, 15};
aruco::CharucoBoard board1(Size(4, 4), 1.f, .8f, dict, ids1), board2(Size(4, 4), 1.f, .8f, dict, ids2);
// generate ChArUco board
Mat gray;
{
Mat gray1, gray2;
board1.generateImage(Size(res.width, res.height), gray1, 150);
board2.generateImage(Size(res.width, res.height), gray2, 150);
hconcat(gray1, gray2, gray);
}
aruco::CharucoParameters charucoParameters;
charucoParameters.cameraMatrix = K;
aruco::CharucoDetector detector1(board1, charucoParameters), detector2(board2, charucoParameters);
vector<int> ids;
vector<Mat> corners;
Mat c_ids1, c_ids2, c_corners1, c_corners2;
detector1.detectBoard(gray, c_corners1, c_ids1, corners, ids);
detector2.detectBoard(gray, c_corners2, c_ids2, corners, ids);
ASSERT_EQ(ids.size(), size_t(16));
ASSERT_EQ(c_corners1.rows, expected_corners.rows);
EXPECT_NEAR(0, cvtest::norm(expected_corners, c_corners1.reshape(1), NORM_INF), 3e-1);
ASSERT_EQ(c_corners2.rows, expected_corners.rows);
expected_corners.col(0) += 500;
EXPECT_NEAR(0, cvtest::norm(expected_corners, c_corners2.reshape(1), NORM_INF), 3e-1);
}
}} // namespace