fix generate of charuco chessboard image, add test

pull/24873/head
AleksandrPanov 1 year 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 = Mat noMarginsImg =
out.colRange(marginSize, out.cols - marginSize).rowRange(marginSize, out.rows - marginSize); out.colRange(marginSize, out.cols - marginSize).rowRange(marginSize, out.rows - marginSize);
double totalLengthX, totalLengthY; // the size of the chessboard square depends on the location of the chessboard
totalLengthX = squareLength * size.width; float pixInSquare = 0.f;
totalLengthY = squareLength * size.height; // the size of the chessboard in pixels
Size pixInChessboard(noMarginsImg.cols, noMarginsImg.rows);
// proportional transformation
double xReduction = totalLengthX / double(noMarginsImg.cols);
double yReduction = totalLengthY / double(noMarginsImg.rows);
// determine the zone where the chessboard is placed // determine the zone where the chessboard is placed
Mat chessboardZoneImg; float pixInSquareX = (float)noMarginsImg.cols / (float)size.width;
if(xReduction > yReduction) { float pixInSquareY = (float)noMarginsImg.rows / (float)size.height;
int nRows = int(totalLengthY / xReduction); Point startChessboard(0, 0);
int rowsMargins = (noMarginsImg.rows - nRows) / 2; if (pixInSquareX <= pixInSquareY) {
chessboardZoneImg = noMarginsImg.rowRange(rowsMargins, noMarginsImg.rows - rowsMargins); // the width of "noMarginsImg" image determines the dimensions of the chessboard
} else { pixInSquare = pixInSquareX;
int nCols = int(totalLengthX / yReduction); pixInChessboard.height = cvRound(pixInSquare*size.height);
int colsMargins = (noMarginsImg.cols - nCols) / 2; int rowsMargin = (noMarginsImg.rows - pixInChessboard.height) / 2;
chessboardZoneImg = noMarginsImg.colRange(colsMargins, noMarginsImg.cols - colsMargins); startChessboard.y = rowsMargin;
} }
else {
// determine the margins to draw only the markers // the height of "noMarginsImg" image determines the dimensions of the chessboard
// take the minimum just to be sure pixInSquare = pixInSquareY;
double squareSizePixels = min(double(chessboardZoneImg.cols) / double(size.width), pixInChessboard.width = cvRound(pixInSquare*size.width);
double(chessboardZoneImg.rows) / double(size.height)); int colsMargin = (noMarginsImg.cols - pixInChessboard.width) / 2;
startChessboard.x = colsMargin;
double diffSquareMarkerLength = (squareLength - markerLength) / 2; }
int diffSquareMarkerLengthPixels = // determine the zone where the chessboard is located
int(diffSquareMarkerLength * squareSizePixels / squareLength); 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 // draw markers
Mat markersImg; Board::Impl::generateImage(arucoZone.size(), arucoZone, 0, borderBits);
Board::Impl::generateImage(chessboardZoneImg.size(), markersImg, diffSquareMarkerLengthPixels, borderBits);
markersImg.copyTo(chessboardZoneImg);
// now draw black squares // now draw black squares
for(int y = 0; y < size.height; y++) { 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 if(y % 2 != x % 2) continue; // white corner, dont do anything
} }
double startX, startY; float startX = pixInSquare * float(x);
startX = squareSizePixels * double(x); float startY = pixInSquare * float(y);
startY = squareSizePixels * double(y);
Mat squareZone = chessboardZoneImg.rowRange(int(startY), int(startY + squareSizePixels)) Mat squareZone = chessboardZoneImg(Range(cvRound(startY), cvRound(startY + pixInSquare)),
.colRange(int(startX), int(startX + squareSizePixels)); Range(cvRound(startX), cvRound(startX + pixInSquare)));
squareZone.setTo(0); squareZone.setTo(0);
} }

@ -769,6 +769,57 @@ TEST_P(CharucoBoard, testWrongSizeDetection)
ASSERT_TRUE(detectedCharucoIds.empty()); 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) TEST(Charuco, testSeveralBoardsWithCustomIds)
{ {
Size res{500, 500}; Size res{500, 500};

Loading…
Cancel
Save