diff --git a/modules/objdetect/src/aruco/aruco_board.cpp b/modules/objdetect/src/aruco/aruco_board.cpp index f8d3d3c108..f5f274ec0c 100644 --- a/modules/objdetect/src/aruco/aruco_board.cpp +++ b/modules/objdetect/src/aruco/aruco_board.cpp @@ -99,21 +99,6 @@ void Board::Impl::generateImage(Size outSize, OutputArray img, int marginSize, i float sizeX = maxX - minX; float sizeY = maxY - minY; - // proportion transformations - float xReduction = sizeX / float(out.cols); - float yReduction = sizeY / float(out.rows); - - // determine the zone where the markers are placed - if(xReduction > yReduction) { - int nRows = int(sizeY / xReduction); - int rowsMargins = (out.rows - nRows) / 2; - out.adjustROI(-rowsMargins, -rowsMargins, 0, 0); - } else { - int nCols = int(sizeX / yReduction); - int colsMargins = (out.cols - nCols) / 2; - out.adjustROI(0, 0, -colsMargins, -colsMargins); - } - // now paint each marker Mat marker; Point2f outCorners[3]; diff --git a/modules/objdetect/test/test_charucodetection.cpp b/modules/objdetect/test/test_charucodetection.cpp index 47166fa78e..c0f6c93d50 100644 --- a/modules/objdetect/test/test_charucodetection.cpp +++ b/modules/objdetect/test/test_charucodetection.cpp @@ -81,6 +81,18 @@ static Mat projectCharucoBoard(aruco::CharucoBoard& board, Mat cameraMatrix, dou return img; } +static bool borderPixelsHaveSameColor(const Mat& image, uint8_t color) { + for (int j = 0; j < image.cols; j++) { + if (image.at(0, j) != color || image.at(image.rows-1, j) != color) + return false; + } + for (int i = 0; i < image.rows; i++) { + if (image.at(i, 0) != color || image.at(i, image.cols-1) != color) + return false; + } + return true; +} + /** * @brief Check Charuco detection */ @@ -769,17 +781,24 @@ TEST_P(CharucoBoard, testWrongSizeDetection) ASSERT_TRUE(detectedCharucoIds.empty()); } -TEST(CharucoBoardGenerate, issue_24806) + +typedef testing::TestWithParam> CharucoBoardGenerate; +INSTANTIATE_TEST_CASE_P(/**/, CharucoBoardGenerate, testing::Values(make_tuple(Size(7, 4), 13.f, Size(400, 300), 24), + make_tuple(Size(12, 2), 13.f, Size(200, 150), 1), + make_tuple(Size(12, 2), 13.1f, Size(400, 300), 1))); +TEST_P(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); + auto params = GetParam(); + const Size boardSize = std::get<0>(params); + const float squareLength = std::get<1>(params), markerLength = 10.f; + Size imgSize = std::get<2>(params); const aruco::CharucoBoard board(boardSize, squareLength, markerLength, dict); - const int marginSize = 24; + const int marginSize = std::get<3>(params); Mat boardImg; // generate chessboard image - board.generateImage(Size(400, 300), boardImg, marginSize); + board.generateImage(imgSize, 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); @@ -817,7 +836,54 @@ TEST(CharucoBoardGenerate, issue_24806) 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 + + // 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*(boardSize.width-1)+pixInMarginMarker+pixInMarker); + int endArucoY = cvRound(pixInSquare*(boardSize.height-1)+pixInMarginMarker+pixInMarker); + Mat arucoZone = chessboardZoneImg(Range(cvRound(pixInMarginMarker), endArucoY), Range(cvRound(pixInMarginMarker), endArucoX)); + + const auto& markerCorners = board.getObjPoints(); + float minX, maxX, minY, maxY; + minX = maxX = markerCorners[0][0].x; + minY = maxY = markerCorners[0][0].y; + for (const auto& marker : markerCorners) { + for (const Point3f& objCorner : marker) { + minX = min(minX, objCorner.x); + maxX = max(maxX, objCorner.x); + minY = min(minY, objCorner.y); + maxY = max(maxY, objCorner.y); + } + } + + Point2f outCorners[3]; + for (const auto& marker : markerCorners) { + for (int i = 0; i < 3; i++) { + outCorners[i] = Point2f(marker[i].x, marker[i].y) - Point2f(minX, minY); + outCorners[i].x = outCorners[i].x / (maxX - minX) * float(arucoZone.cols); + outCorners[i].y = outCorners[i].y / (maxY - minY) * float(arucoZone.rows); + } + Size dst_sz(outCorners[2] - outCorners[0]); // assuming CCW order + dst_sz.width = dst_sz.height = std::min(dst_sz.width, dst_sz.height); + Rect borderRect = Rect(outCorners[0], dst_sz); + + //The test checks the inner and outer borders of the Aruco markers. + //In the inner border of Aruco marker, all pixels should be black. + //In the outer border of Aruco marker, all pixels should be white. + + Mat markerImg = arucoZone(borderRect); + bool markerBorderIsBlack = borderPixelsHaveSameColor(markerImg, 0); + ASSERT_EQ(markerBorderIsBlack, true); + + Mat markerOuterBorder = markerImg; + markerOuterBorder.adjustROI(1, 1, 1, 1); + bool markerOuterBorderIsWhite = borderPixelsHaveSameColor(markerOuterBorder, 255); + ASSERT_EQ(markerOuterBorderIsWhite, true); + } } TEST(Charuco, testSeveralBoardsWithCustomIds)