diff --git a/modules/objdetect/misc/python/test/test_objdetect_aruco.py b/modules/objdetect/misc/python/test/test_objdetect_aruco.py index dda58b6460..8dd407d32f 100644 --- a/modules/objdetect/misc/python/test/test_objdetect_aruco.py +++ b/modules/objdetect/misc/python/test/test_objdetect_aruco.py @@ -394,5 +394,69 @@ class aruco_objdetect_test(NewOpenCVTests): self.assertEqual(2, img_points.shape[2]) np.testing.assert_array_equal(chessboard_corners, obj_points[:, :, :2].reshape(-1, 2)) + def test_draw_detected_markers(self): + detected_points = [[[10, 10], [50, 10], [50, 50], [10, 50]]] + img = np.zeros((60, 60), dtype=np.uint8) + + # add extra dimension in Python to create Nx4 Mat with 2 channels + points1 = np.array(detected_points).reshape(-1, 4, 1, 2) + img = cv.aruco.drawDetectedMarkers(img, points1, borderColor=255) + + # check that the marker borders are painted + contours, _ = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) + self.assertEqual(len(contours), 1) + self.assertEqual(img[10, 10], 255) + self.assertEqual(img[50, 10], 255) + self.assertEqual(img[50, 50], 255) + self.assertEqual(img[10, 50], 255) + + # must throw Exception without extra dimension + points2 = np.array(detected_points) + with self.assertRaises(Exception): + img = cv.aruco.drawDetectedMarkers(img, points2, borderColor=255) + + def test_draw_detected_charuco(self): + detected_points = [[[10, 10], [50, 10], [50, 50], [10, 50]]] + img = np.zeros((60, 60), dtype=np.uint8) + + # add extra dimension in Python to create Nx1 Mat with 2 channels + points = np.array(detected_points).reshape(-1, 1, 2) + img = cv.aruco.drawDetectedCornersCharuco(img, points, cornerColor=255) + + # check that the 4 charuco corners are painted + contours, _ = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) + self.assertEqual(len(contours), 4) + for contour in contours: + center_x = round(np.average(contour[:, 0, 0])) + center_y = round(np.average(contour[:, 0, 1])) + center = [center_x, center_y] + self.assertTrue(center in detected_points[0]) + + # must throw Exception without extra dimension + points2 = np.array(detected_points) + with self.assertRaises(Exception): + img = cv.aruco.drawDetectedCornersCharuco(img, points2, borderColor=255) + + def test_draw_detected_diamonds(self): + detected_points = [[[10, 10], [50, 10], [50, 50], [10, 50]]] + img = np.zeros((60, 60), dtype=np.uint8) + + # add extra dimension in Python to create Nx4 Mat with 2 channels + points = np.array(detected_points).reshape(-1, 4, 1, 2) + img = cv.aruco.drawDetectedDiamonds(img, points, borderColor=255) + + # check that the diamonds borders are painted + contours, _ = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) + self.assertEqual(len(contours), 1) + self.assertEqual(img[10, 10], 255) + self.assertEqual(img[50, 10], 255) + self.assertEqual(img[50, 50], 255) + self.assertEqual(img[10, 50], 255) + + # must throw Exception without extra dimension + points2 = np.array(detected_points) + with self.assertRaises(Exception): + img = cv.aruco.drawDetectedDiamonds(img, points2, borderColor=255) + if __name__ == '__main__': NewOpenCVTests.bootstrap() diff --git a/modules/objdetect/src/aruco/aruco_detector.cpp b/modules/objdetect/src/aruco/aruco_detector.cpp index 84ccc6e323..b18ddd98ba 100644 --- a/modules/objdetect/src/aruco/aruco_detector.cpp +++ b/modules/objdetect/src/aruco/aruco_detector.cpp @@ -1315,24 +1315,26 @@ void drawDetectedMarkers(InputOutputArray _image, InputArrayOfArrays _corners, int nMarkers = (int)_corners.total(); for(int i = 0; i < nMarkers; i++) { Mat currentMarker = _corners.getMat(i); - CV_Assert(currentMarker.total() == 4 && currentMarker.type() == CV_32FC2); + CV_Assert(currentMarker.total() == 4 && currentMarker.channels() == 2); + if (currentMarker.type() != CV_32SC2) + currentMarker.convertTo(currentMarker, CV_32SC2); // draw marker sides for(int j = 0; j < 4; j++) { - Point2f p0, p1; - p0 = currentMarker.ptr(0)[j]; - p1 = currentMarker.ptr(0)[(j + 1) % 4]; + Point p0, p1; + p0 = currentMarker.ptr(0)[j]; + p1 = currentMarker.ptr(0)[(j + 1) % 4]; line(_image, p0, p1, borderColor, 1); } // draw first corner mark - rectangle(_image, currentMarker.ptr(0)[0] - Point2f(3, 3), - currentMarker.ptr(0)[0] + Point2f(3, 3), cornerColor, 1, LINE_AA); + rectangle(_image, currentMarker.ptr(0)[0] - Point(3, 3), + currentMarker.ptr(0)[0] + Point(3, 3), cornerColor, 1, LINE_AA); // draw ID if(_ids.total() != 0) { - Point2f cent(0, 0); + Point cent(0, 0); for(int p = 0; p < 4; p++) - cent += currentMarker.ptr(0)[p]; + cent += currentMarker.ptr(0)[p]; cent = cent / 4.; stringstream s; s << "id=" << _ids.getMat().ptr(0)[i]; diff --git a/modules/objdetect/src/aruco/charuco_detector.cpp b/modules/objdetect/src/aruco/charuco_detector.cpp index 55a7f8d888..4605de19c5 100644 --- a/modules/objdetect/src/aruco/charuco_detector.cpp +++ b/modules/objdetect/src/aruco/charuco_detector.cpp @@ -507,20 +507,27 @@ void drawDetectedCornersCharuco(InputOutputArray _image, InputArray _charucoCorn InputArray _charucoIds, Scalar cornerColor) { CV_Assert(!_image.getMat().empty() && (_image.getMat().channels() == 1 || _image.getMat().channels() == 3)); - CV_Assert((_charucoCorners.getMat().total() == _charucoIds.getMat().total()) || - _charucoIds.getMat().total() == 0); - - size_t nCorners = _charucoCorners.getMat().total(); + CV_Assert((_charucoCorners.total() == _charucoIds.total()) || + _charucoIds.total() == 0); + CV_Assert(_charucoCorners.channels() == 2); + + Mat charucoCorners = _charucoCorners.getMat(); + if (charucoCorners.type() != CV_32SC2) + charucoCorners.convertTo(charucoCorners, CV_32SC2); + Mat charucoIds; + if (!_charucoIds.empty()) + charucoIds = _charucoIds.getMat(); + size_t nCorners = charucoCorners.total(); for(size_t i = 0; i < nCorners; i++) { - Point2f corner = _charucoCorners.getMat().at((int)i); + Point corner = charucoCorners.at((int)i); // draw first corner mark - rectangle(_image, corner - Point2f(3, 3), corner + Point2f(3, 3), cornerColor, 1, LINE_AA); + rectangle(_image, corner - Point(3, 3), corner + Point(3, 3), cornerColor, 1, LINE_AA); // draw ID if(!_charucoIds.empty()) { - int id = _charucoIds.getMat().at((int)i); + int id = charucoIds.at((int)i); stringstream s; s << "id=" << id; - putText(_image, s.str(), corner + Point2f(5, -5), FONT_HERSHEY_SIMPLEX, 0.5, + putText(_image, s.str(), corner + Point(5, -5), FONT_HERSHEY_SIMPLEX, 0.5, cornerColor, 2); } } @@ -540,25 +547,27 @@ void drawDetectedDiamonds(InputOutputArray _image, InputArrayOfArrays _corners, int nMarkers = (int)_corners.total(); for(int i = 0; i < nMarkers; i++) { Mat currentMarker = _corners.getMat(i); - CV_Assert(currentMarker.total() == 4 && currentMarker.type() == CV_32FC2); + CV_Assert(currentMarker.total() == 4 && currentMarker.channels() == 2); + if (currentMarker.type() != CV_32SC2) + currentMarker.convertTo(currentMarker, CV_32SC2); // draw marker sides for(int j = 0; j < 4; j++) { - Point2f p0, p1; - p0 = currentMarker.at< Point2f >(j); - p1 = currentMarker.at< Point2f >((j + 1) % 4); + Point p0, p1; + p0 = currentMarker.at(j); + p1 = currentMarker.at((j + 1) % 4); line(_image, p0, p1, borderColor, 1); } // draw first corner mark - rectangle(_image, currentMarker.at< Point2f >(0) - Point2f(3, 3), - currentMarker.at< Point2f >(0) + Point2f(3, 3), cornerColor, 1, LINE_AA); + rectangle(_image, currentMarker.at(0) - Point(3, 3), + currentMarker.at(0) + Point(3, 3), cornerColor, 1, LINE_AA); // draw id composed by four numbers if(_ids.total() != 0) { - Point2f cent(0, 0); + Point cent(0, 0); for(int p = 0; p < 4; p++) - cent += currentMarker.at< Point2f >(p); + cent += currentMarker.at(p); cent = cent / 4.; stringstream s; s << "id=" << _ids.getMat().at< Vec4i >(i); diff --git a/modules/objdetect/test/test_charucodetection.cpp b/modules/objdetect/test/test_charucodetection.cpp index 9e561bc40a..418826d947 100644 --- a/modules/objdetect/test/test_charucodetection.cpp +++ b/modules/objdetect/test/test_charucodetection.cpp @@ -689,6 +689,58 @@ TEST(Charuco, testmatchImagePoints) } } +typedef testing::TestWithParam CharucoDraw; +INSTANTIATE_TEST_CASE_P(/**/, CharucoDraw, testing::Values(CV_8UC2, CV_8SC2, CV_16UC2, CV_16SC2, CV_32SC2, CV_32FC2, CV_64FC2)); +TEST_P(CharucoDraw, testDrawDetected) { + vector> detected_golds = {{Point(20, 20), Point(80, 20), Point(80, 80), Point2f(20, 80)}}; + Point center_gold = (detected_golds[0][0] + detected_golds[0][1] + detected_golds[0][2] + detected_golds[0][3]) / 4; + int type = GetParam(); + vector detected(detected_golds[0].size(), Mat(4, 1, type)); + // copy detected_golds to detected with any 2 channels type + for (size_t i = 0ull; i < detected_golds[0].size(); i++) { + detected[0].row((int)i) = Scalar(detected_golds[0][i].x, detected_golds[0][i].y); + } + vector> contours; + Point detectedCenter; + Moments m; + Mat img; + + // check drawDetectedMarkers + img = Mat::zeros(100, 100, CV_8UC1); + ASSERT_NO_THROW(aruco::drawDetectedMarkers(img, detected, noArray(), Scalar(255, 255, 255))); + // check that the marker borders are painted + findContours(img, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); + ASSERT_EQ(contours.size(), 1ull); + m = moments(contours[0]); + detectedCenter = Point(cvRound(m.m10/m.m00), cvRound(m.m01/m.m00)); + ASSERT_EQ(detectedCenter, center_gold); + + + // check drawDetectedCornersCharuco + img = Mat::zeros(100, 100, CV_8UC1); + ASSERT_NO_THROW(aruco::drawDetectedCornersCharuco(img, detected[0], noArray(), Scalar(255, 255, 255))); + // check that the 4 charuco corners are painted + findContours(img, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); + ASSERT_EQ(contours.size(), 4ull); + for (size_t i = 0ull; i < 4ull; i++) { + m = moments(contours[i]); + detectedCenter = Point(cvRound(m.m10/m.m00), cvRound(m.m01/m.m00)); + // detectedCenter must be in detected_golds + ASSERT_TRUE(find(detected_golds[0].begin(), detected_golds[0].end(), detectedCenter) != detected_golds[0].end()); + } + + + // check drawDetectedDiamonds + img = Mat::zeros(100, 100, CV_8UC1); + ASSERT_NO_THROW(aruco::drawDetectedDiamonds(img, detected, noArray(), Scalar(255, 255, 255))); + // check that the diamonds borders are painted + findContours(img, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); + ASSERT_EQ(contours.size(), 1ull); + m = moments(contours[0]); + detectedCenter = Point(cvRound(m.m10/m.m00), cvRound(m.m01/m.m00)); + ASSERT_EQ(detectedCenter, center_gold); +} + typedef testing::TestWithParam CharucoBoard; INSTANTIATE_TEST_CASE_P(/**/, CharucoBoard, testing::Values(Size(3, 2), Size(3, 2), Size(6, 2), Size(2, 6), Size(3, 4), Size(4, 3), Size(7, 3), Size(3, 7)));