1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 00:03:03 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2025-03-11 16:38:05 +03:00
306 changed files with 9362 additions and 19775 deletions
@@ -6,6 +6,18 @@
#include "opencv2/objdetect/aruco_detector.hpp"
#include "opencv2/3d.hpp"
namespace cv {
namespace aruco {
bool operator==(const Dictionary& d1, const Dictionary& d2);
bool operator==(const Dictionary& d1, const Dictionary& d2) {
return d1.markerSize == d2.markerSize
&& std::equal(d1.bytesList.begin<Vec<uint8_t, 4>>(), d1.bytesList.end<Vec<uint8_t, 4>>(), d2.bytesList.begin<Vec<uint8_t, 4>>())
&& std::equal(d2.bytesList.begin<Vec<uint8_t, 4>>(), d2.bytesList.end<Vec<uint8_t, 4>>(), d1.bytesList.begin<Vec<uint8_t, 4>>())
&& d1.maxCorrectionBits == d2.maxCorrectionBits;
};
}
}
namespace opencv_test { namespace {
/**
@@ -638,6 +650,155 @@ TEST(CV_ArucoDetectMarkers, regression_contour_24220)
}
}
TEST(CV_ArucoMultiDict, setGetDictionaries)
{
vector<aruco::Dictionary> dictionaries = {aruco::getPredefinedDictionary(aruco::DICT_4X4_50), aruco::getPredefinedDictionary(aruco::DICT_5X5_100)};
aruco::ArucoDetector detector(dictionaries);
vector<aruco::Dictionary> dicts = detector.getDictionaries();
ASSERT_EQ(dicts.size(), 2ul);
EXPECT_EQ(dicts[0].markerSize, 4);
EXPECT_EQ(dicts[1].markerSize, 5);
dictionaries.clear();
dictionaries.push_back(aruco::getPredefinedDictionary(aruco::DICT_6X6_100));
dictionaries.push_back(aruco::getPredefinedDictionary(aruco::DICT_7X7_250));
dictionaries.push_back(aruco::getPredefinedDictionary(aruco::DICT_APRILTAG_25h9));
detector.setDictionaries(dictionaries);
dicts = detector.getDictionaries();
ASSERT_EQ(dicts.size(), 3ul);
EXPECT_EQ(dicts[0].markerSize, 6);
EXPECT_EQ(dicts[1].markerSize, 7);
EXPECT_EQ(dicts[2].markerSize, 5);
auto dict = detector.getDictionary();
EXPECT_EQ(dict.markerSize, 6);
detector.setDictionary(aruco::getPredefinedDictionary(aruco::DICT_APRILTAG_16h5));
dicts = detector.getDictionaries();
ASSERT_EQ(dicts.size(), 3ul);
EXPECT_EQ(dicts[0].markerSize, 4);
EXPECT_EQ(dicts[1].markerSize, 7);
EXPECT_EQ(dicts[2].markerSize, 5);
}
TEST(CV_ArucoMultiDict, noDict)
{
aruco::ArucoDetector detector;
EXPECT_THROW({
detector.setDictionaries({});
}, Exception);
}
TEST(CV_ArucoMultiDict, multiMarkerDetection)
{
const int markerSidePixels = 100;
const int imageSize = markerSidePixels * 2 + 3 * (markerSidePixels / 2);
vector<aruco::Dictionary> usedDictionaries;
// draw synthetic image
Mat img = Mat(imageSize, imageSize, CV_8UC1, Scalar::all(255));
for(int y = 0; y < 2; y++) {
for(int x = 0; x < 2; x++) {
Mat marker;
int id = y * 2 + x;
int dictId = x * 4 + y * 8;
auto dict = aruco::getPredefinedDictionary(dictId);
usedDictionaries.push_back(dict);
aruco::generateImageMarker(dict, id, markerSidePixels, marker);
Point2f firstCorner(markerSidePixels / 2.f + x * (1.5f * markerSidePixels),
markerSidePixels / 2.f + y * (1.5f * markerSidePixels));
Mat aux = img(Rect((int)firstCorner.x, (int)firstCorner.y, markerSidePixels, markerSidePixels));
marker.copyTo(aux);
}
}
img.convertTo(img, CV_8UC3);
aruco::ArucoDetector detector(usedDictionaries);
vector<vector<Point2f> > markerCorners;
vector<int> markerIds;
vector<vector<Point2f> > rejectedImgPts;
vector<int> dictIds;
detector.detectMarkersMultiDict(img, markerCorners, markerIds, rejectedImgPts, dictIds);
ASSERT_EQ(markerIds.size(), 4u);
ASSERT_EQ(dictIds.size(), 4u);
for (size_t i = 0; i < dictIds.size(); ++i) {
EXPECT_EQ(dictIds[i], (int)i);
}
}
TEST(CV_ArucoMultiDict, multiMarkerDoubleDetection)
{
const int markerSidePixels = 100;
const int imageWidth = 2 * markerSidePixels + 3 * (markerSidePixels / 2);
const int imageHeight = markerSidePixels + 2 * (markerSidePixels / 2);
vector<aruco::Dictionary> usedDictionaries = {
aruco::getPredefinedDictionary(aruco::DICT_5X5_50),
aruco::getPredefinedDictionary(aruco::DICT_5X5_100)
};
// draw synthetic image
Mat img = Mat(imageHeight, imageWidth, CV_8UC1, Scalar::all(255));
for(int y = 0; y < 2; y++) {
Mat marker;
int id = 49 + y;
auto dict = aruco::getPredefinedDictionary(aruco::DICT_5X5_100);
aruco::generateImageMarker(dict, id, markerSidePixels, marker);
Point2f firstCorner(markerSidePixels / 2.f + y * (1.5f * markerSidePixels),
markerSidePixels / 2.f);
Mat aux = img(Rect((int)firstCorner.x, (int)firstCorner.y, markerSidePixels, markerSidePixels));
marker.copyTo(aux);
}
img.convertTo(img, CV_8UC3);
aruco::ArucoDetector detector(usedDictionaries);
vector<vector<Point2f> > markerCorners;
vector<int> markerIds;
vector<vector<Point2f> > rejectedImgPts;
vector<int> dictIds;
detector.detectMarkersMultiDict(img, markerCorners, markerIds, rejectedImgPts, dictIds);
ASSERT_EQ(markerIds.size(), 3u);
ASSERT_EQ(dictIds.size(), 3u);
EXPECT_EQ(dictIds[0], 0); // 5X5_50
EXPECT_EQ(dictIds[1], 1); // 5X5_100
EXPECT_EQ(dictIds[2], 1); // 5X5_100
}
TEST(CV_ArucoMultiDict, serialization)
{
aruco::ArucoDetector detector;
{
FileStorage fs_out(".json", FileStorage::WRITE + FileStorage::MEMORY);
ASSERT_TRUE(fs_out.isOpened());
detector.write(fs_out);
std::string serialized_string = fs_out.releaseAndGetString();
FileStorage test_fs(serialized_string, FileStorage::Mode::READ + FileStorage::MEMORY);
ASSERT_TRUE(test_fs.isOpened());
aruco::ArucoDetector test_detector;
test_detector.read(test_fs.root());
// compare default constructor result
EXPECT_EQ(aruco::getPredefinedDictionary(aruco::DICT_4X4_50), test_detector.getDictionary());
}
detector.setDictionaries({aruco::getPredefinedDictionary(aruco::DICT_4X4_50), aruco::getPredefinedDictionary(aruco::DICT_5X5_100)});
{
FileStorage fs_out(".json", FileStorage::WRITE + FileStorage::MEMORY);
ASSERT_TRUE(fs_out.isOpened());
detector.write(fs_out);
std::string serialized_string = fs_out.releaseAndGetString();
FileStorage test_fs(serialized_string, FileStorage::Mode::READ + FileStorage::MEMORY);
ASSERT_TRUE(test_fs.isOpened());
aruco::ArucoDetector test_detector;
test_detector.read(test_fs.root());
// check for one additional dictionary
auto dicts = test_detector.getDictionaries();
ASSERT_EQ(2ul, dicts.size());
EXPECT_EQ(aruco::getPredefinedDictionary(aruco::DICT_4X4_50), dicts[0]);
EXPECT_EQ(aruco::getPredefinedDictionary(aruco::DICT_5X5_100), dicts[1]);
}
}
struct ArucoThreading: public testing::TestWithParam<aruco::CornerRefineMethod>
{
@@ -134,14 +134,17 @@ class CV_ArucoRefine : public cvtest::BaseTest {
public:
CV_ArucoRefine(ArucoAlgParams arucoAlgParams)
{
aruco::Dictionary dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
vector<aruco::Dictionary> dictionaries = {aruco::getPredefinedDictionary(aruco::DICT_6X6_250),
aruco::getPredefinedDictionary(aruco::DICT_5X5_250),
aruco::getPredefinedDictionary(aruco::DICT_4X4_250),
aruco::getPredefinedDictionary(aruco::DICT_7X7_250)};
aruco::DetectorParameters params;
params.minDistanceToBorder = 3;
params.cornerRefinementMethod = (int)aruco::CORNER_REFINE_SUBPIX;
if (arucoAlgParams == ArucoAlgParams::USE_ARUCO3)
params.useAruco3Detection = true;
aruco::RefineParameters refineParams(10.f, 3.f, true);
detector = aruco::ArucoDetector(dictionary, params, refineParams);
detector = aruco::ArucoDetector(dictionaries, params, refineParams);
}
protected: