fix generate of charuco chessboard image, add test

pull/24873/head
AleksandrPanov 10 months ago
parent 853e5dfcdf
commit 37c76b815c
  1. 72
      modules/objdetect/src/aruco/aruco_board.cpp
  2. 51
      modules/objdetect/test/test_charucodetection.cpp

@ -483,39 +483,44 @@ void CharucoBoardImpl::generateImage(Size outSize, OutputArray img, int marginSi
Mat noMarginsImg =
out.colRange(marginSize, out.cols - marginSize).rowRange(marginSize, out.rows - marginSize);
double totalLengthX, totalLengthY;
totalLengthX = squareLength * size.width;
totalLengthY = squareLength * size.height;
// proportional transformation
double xReduction = totalLengthX / double(noMarginsImg.cols);
double yReduction = totalLengthY / double(noMarginsImg.rows);
// the size of the chessboard square depends on the location of the chessboard
float pixInSquare = 0.f;
// the size of the chessboard in pixels
Size pixInChessboard(noMarginsImg.cols, noMarginsImg.rows);
// determine the zone where the chessboard is placed
Mat chessboardZoneImg;
if(xReduction > yReduction) {
int nRows = int(totalLengthY / xReduction);
int rowsMargins = (noMarginsImg.rows - nRows) / 2;
chessboardZoneImg = noMarginsImg.rowRange(rowsMargins, noMarginsImg.rows - rowsMargins);
} else {
int nCols = int(totalLengthX / yReduction);
int colsMargins = (noMarginsImg.cols - nCols) / 2;
chessboardZoneImg = noMarginsImg.colRange(colsMargins, noMarginsImg.cols - colsMargins);
}
// determine the margins to draw only the markers
// take the minimum just to be sure
double squareSizePixels = min(double(chessboardZoneImg.cols) / double(size.width),
double(chessboardZoneImg.rows) / double(size.height));
double diffSquareMarkerLength = (squareLength - markerLength) / 2;
int diffSquareMarkerLengthPixels =
int(diffSquareMarkerLength * squareSizePixels / squareLength);
float pixInSquareX = (float)noMarginsImg.cols / (float)size.width;
float pixInSquareY = (float)noMarginsImg.rows / (float)size.height;
Point startChessboard(0, 0);
if (pixInSquareX <= pixInSquareY) {
// the width of "noMarginsImg" image determines the dimensions of the chessboard
pixInSquare = pixInSquareX;
pixInChessboard.height = cvRound(pixInSquare*size.height);
int rowsMargin = (noMarginsImg.rows - pixInChessboard.height) / 2;
startChessboard.y = rowsMargin;
}
else {
// the height of "noMarginsImg" image determines the dimensions of the chessboard
pixInSquare = pixInSquareY;
pixInChessboard.width = cvRound(pixInSquare*size.width);
int colsMargin = (noMarginsImg.cols - pixInChessboard.width) / 2;
startChessboard.x = colsMargin;
}
// determine the zone where the chessboard is located
Mat chessboardZoneImg = noMarginsImg(Rect(startChessboard, pixInChessboard));
// marker size in pixels
const float pixInMarker = markerLength/squareLength*pixInSquare;
// the size of the marker margin in pixels
const float pixInMarginMarker = 0.5f*(pixInSquare - pixInMarker);
// determine the zone where the aruco markers are located
int endArucoX = cvRound(pixInSquare*(size.width-1)+pixInMarginMarker+pixInMarker);
int endArucoY = cvRound(pixInSquare*(size.height-1)+pixInMarginMarker+pixInMarker);
Mat arucoZone = chessboardZoneImg(Range(cvRound(pixInMarginMarker), endArucoY), Range(cvRound(pixInMarginMarker), endArucoX));
// draw markers
Mat markersImg;
Board::Impl::generateImage(chessboardZoneImg.size(), markersImg, diffSquareMarkerLengthPixels, borderBits);
markersImg.copyTo(chessboardZoneImg);
Board::Impl::generateImage(arucoZone.size(), arucoZone, 0, borderBits);
// now draw black squares
for(int y = 0; y < size.height; y++) {
@ -527,12 +532,11 @@ void CharucoBoardImpl::generateImage(Size outSize, OutputArray img, int marginSi
if(y % 2 != x % 2) continue; // white corner, dont do anything
}
double startX, startY;
startX = squareSizePixels * double(x);
startY = squareSizePixels * double(y);
float startX = pixInSquare * float(x);
float startY = pixInSquare * float(y);
Mat squareZone = chessboardZoneImg.rowRange(int(startY), int(startY + squareSizePixels))
.colRange(int(startX), int(startX + squareSizePixels));
Mat squareZone = chessboardZoneImg(Range(cvRound(startY), cvRound(startY + pixInSquare)),
Range(cvRound(startX), cvRound(startX + pixInSquare)));
squareZone.setTo(0);
}

@ -769,6 +769,57 @@ TEST_P(CharucoBoard, testWrongSizeDetection)
ASSERT_TRUE(detectedCharucoIds.empty());
}
TEST(CharucoBoardGenerate, issue_24806)
{
aruco::Dictionary dict = aruco::getPredefinedDictionary(aruco::DICT_4X4_1000);
const float squareLength = 13.f, markerLength = 10.f;
const Size boardSize(7ull, 4ull);
const aruco::CharucoBoard board(boardSize, squareLength, markerLength, dict);
const int marginSize = 24;
Mat boardImg;
// generate chessboard image
board.generateImage(Size(400, 300), boardImg, marginSize);
// This condition checks that the width of the image determines the dimensions of the chessboard in this test
CV_Assert((float)(boardImg.cols) / (float)boardSize.width <=
(float)(boardImg.rows) / (float)boardSize.height);
// prepare data for chessboard image test
Mat noMarginsImg = boardImg(Range(marginSize, boardImg.rows - marginSize),
Range(marginSize, boardImg.cols - marginSize));
const float pixInSquare = (float)(noMarginsImg.cols) / (float)boardSize.width;
Size pixInChessboard(cvRound(pixInSquare*boardSize.width), cvRound(pixInSquare*boardSize.height));
const Point startChessboard((noMarginsImg.cols - pixInChessboard.width) / 2,
(noMarginsImg.rows - pixInChessboard.height) / 2);
Mat chessboardZoneImg = noMarginsImg(Rect(startChessboard, pixInChessboard));
// B - black pixel, W - white pixel
// chessboard corner 1:
// B W
// W B
Mat goldCorner1 = (Mat_<uint8_t>(2, 2) <<
0, 255,
255, 0);
// B - black pixel, W - white pixel
// chessboard corner 2:
// W B
// B W
Mat goldCorner2 = (Mat_<uint8_t>(2, 2) <<
255, 0,
0, 255);
// test chessboard corners in generated image
for (const Point3f& p: board.getChessboardCorners()) {
Point2f chessCorner(pixInSquare*(p.x/squareLength),
pixInSquare*(p.y/squareLength));
Mat winCorner = chessboardZoneImg(Rect(Point(cvRound(chessCorner.x) - 1, cvRound(chessCorner.y) - 1), Size(2, 2)));
bool eq = (cv::countNonZero(goldCorner1 != winCorner) == 0) | (cv::countNonZero(goldCorner2 != winCorner) == 0);
ASSERT_TRUE(eq);
}
// TODO: fix aruco generateImage and add test aruco corners for generated image
}
TEST(Charuco, testSeveralBoardsWithCustomIds)
{
Size res{500, 500};

Loading…
Cancel
Save