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

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2025-04-28 22:13:51 +03:00
243 changed files with 12965 additions and 3216 deletions
@@ -125,10 +125,10 @@ public:
CV_PROP_RW int version;
//! The optional level of error correction (by default - the lowest).
CV_PROP_RW CorrectionLevel correction_level;
CV_PROP_RW QRCodeEncoder::CorrectionLevel correction_level;
//! The optional encoding mode - Numeric, Alphanumeric, Byte, Kanji, ECI or Structured Append.
CV_PROP_RW EncodeMode mode;
CV_PROP_RW QRCodeEncoder::EncodeMode mode;
//! The optional number of QR codes to generate in Structured Append mode.
CV_PROP_RW int structure_number;
+26 -23
View File
@@ -130,10 +130,10 @@ static void _threshold(InputArray _in, OutputArray _out, int winSize, double con
static void _findMarkerContours(const Mat &in, vector<vector<Point2f> > &candidates,
vector<vector<Point> > &contoursOut, double minPerimeterRate,
double maxPerimeterRate, double accuracyRate,
double minCornerDistanceRate, int minDistanceToBorder, int minSize) {
double minCornerDistanceRate, int minSize) {
CV_Assert(minPerimeterRate > 0 && maxPerimeterRate > 0 && accuracyRate > 0 &&
minCornerDistanceRate >= 0 && minDistanceToBorder >= 0);
minCornerDistanceRate >= 0);
// calculate maximum and minimum sizes in pixels
unsigned int minPerimeterPixels =
@@ -171,16 +171,6 @@ static void _findMarkerContours(const Mat &in, vector<vector<Point2f> > &candida
double minCornerDistancePixels = double(contours[i].size()) * minCornerDistanceRate;
if(minDistSq < minCornerDistancePixels * minCornerDistancePixels) continue;
// check if it is too near to the image border
bool tooNearBorder = false;
for(int j = 0; j < 4; j++) {
if(approxCurve[j].x < minDistanceToBorder || approxCurve[j].y < minDistanceToBorder ||
approxCurve[j].x > in.cols - 1 - minDistanceToBorder ||
approxCurve[j].y > in.rows - 1 - minDistanceToBorder)
tooNearBorder = true;
}
if(tooNearBorder) continue;
// if it passes all the test, add to candidates vector
vector<Point2f> currentCandidate;
currentCandidate.resize(4);
@@ -305,7 +295,7 @@ static void _detectInitialCandidates(const Mat &grey, vector<vector<Point2f> > &
_findMarkerContours(thresh, candidatesArrays[i], contoursArrays[i],
params.minMarkerPerimeterRate, params.maxMarkerPerimeterRate,
params.polygonalApproxAccuracyRate, params.minCornerDistanceRate,
params.minDistanceToBorder, params.minSideLengthCanonicalImg);
params.minSideLengthCanonicalImg);
}
});
// join candidates
@@ -742,7 +732,7 @@ struct ArucoDetector::ArucoDetectorImpl {
vector<vector<Point2f>> rejectedImgPoints;
if (DictionaryMode::Single == dictMode) {
Dictionary& dictionary = dictionaries.at(0);
auto selectedCandidates = filterTooCloseCandidates(candidates, contours, dictionary.markerSize);
auto selectedCandidates = filterTooCloseCandidates(grey.size(), candidates, contours, dictionary.markerSize);
candidates.clear();
contours.clear();
@@ -765,7 +755,7 @@ struct ArucoDetector::ArucoDetectorImpl {
// copy candidates
vector<vector<Point2f>> candidatesCopy = candidates;
vector<vector<Point> > contoursCopy = contours;
candidatesTreeEntry.second = filterTooCloseCandidates(candidatesCopy, contoursCopy, candidatesTreeEntry.first);
candidatesTreeEntry.second = filterTooCloseCandidates(grey.size(), candidatesCopy, contoursCopy, candidatesTreeEntry.first);
}
candidates.clear();
contours.clear();
@@ -872,14 +862,14 @@ struct ArucoDetector::ArucoDetectorImpl {
}
/**
* @brief FILTER OUT NEAR CANDIDATE PAIRS
* @brief FILTER OUT NEAR CANDIDATES PAIRS AND TOO NEAR CANDIDATES TO IMAGE BORDER
*
* save the outter/inner border (i.e. potential candidates) to vector<MarkerCandidateTree>,
* save the outer/inner border (i.e. potential candidates) to vector<MarkerCandidateTree>,
* clear candidates and contours
*/
vector<MarkerCandidateTree>
filterTooCloseCandidates(vector<vector<Point2f> > &candidates, vector<vector<Point> > &contours, int markerSize) {
CV_Assert(detectorParams.minMarkerDistanceRate >= 0.);
filterTooCloseCandidates(const Size &imageSize, vector<vector<Point2f> > &candidates, vector<vector<Point> > &contours, int markerSize) {
CV_Assert(detectorParams.minMarkerDistanceRate >= 0. && detectorParams.minDistanceToBorder >= 0);
vector<MarkerCandidateTree> candidateTree(candidates.size());
for(size_t i = 0ull; i < candidates.size(); i++) {
candidateTree[i] = MarkerCandidateTree(std::move(candidates[i]), std::move(contours[i]));
@@ -940,6 +930,20 @@ struct ArucoDetector::ArucoDetectorImpl {
else // if detectInvertedMarker==false choose largest contours
std::stable_sort(grouped.begin(), grouped.end());
size_t currId = grouped[0];
// check if it is too near to the image border
bool tooNearBorder = false;
for (const auto& corner : candidateTree[currId].corners) {
if (corner.x < detectorParams.minDistanceToBorder ||
corner.y < detectorParams.minDistanceToBorder ||
corner.x > imageSize.width - 1 - detectorParams.minDistanceToBorder ||
corner.y > imageSize.height - 1 - detectorParams.minDistanceToBorder) {
tooNearBorder = true;
break;
}
}
if (tooNearBorder) {
continue;
}
isSelectedContours[currId] = true;
for (size_t i = 1ull; i < grouped.size(); i++) {
size_t id = grouped[i];
@@ -952,12 +956,11 @@ struct ArucoDetector::ArucoDetectorImpl {
}
}
vector<MarkerCandidateTree> selectedCandidates(groupedCandidates.size());
size_t countSelectedContours = 0ull;
vector<MarkerCandidateTree> selectedCandidates;
selectedCandidates.reserve(groupedCandidates.size());
for (size_t i = 0ull; i < candidateTree.size(); i++) {
if (isSelectedContours[i]) {
selectedCandidates[countSelectedContours] = std::move(candidateTree[i]);
countSelectedContours++;
selectedCandidates.push_back(std::move(candidateTree[i]));
}
}
+2
View File
@@ -397,7 +397,9 @@ void QRCodeEncoderImpl::generateQR(const std::string &input)
original = Mat(Size(version_size, version_size), CV_8UC1, Scalar(255));
masked_data = original.clone();
Mat qrcode = masked_data.clone();
std::swap(version_level, tmp_version_level);
generatingProcess(input_info, qrcode);
std::swap(version_level, tmp_version_level);
final_qrcodes.push_back(qrcode);
}
}
@@ -650,6 +650,40 @@ TEST(CV_ArucoDetectMarkers, regression_contour_24220)
}
}
TEST(CV_ArucoDetectMarkers, regression_26922)
{
const auto arucoDict = aruco::getPredefinedDictionary(aruco::DICT_4X4_1000);
const aruco::GridBoard gridBoard(Size(19, 10), 1, 0.25, arucoDict);
const Size imageSize(7200, 3825);
Mat boardImage;
gridBoard.generateImage(imageSize, boardImage, 75, 1);
const aruco::ArucoDetector detector(arucoDict);
vector<vector<Point2f>> corners;
vector<int> ids;
detector.detectMarkers(boardImage, corners, ids);
EXPECT_EQ(ids.size(), 190ull);
EXPECT_TRUE(find(ids.begin(), ids.end(), 76) != ids.end());
EXPECT_TRUE(find(ids.begin(), ids.end(), 172) != ids.end());
float transformMatrixData[9] = {1, -0.2f, 300, 0.4f, 1, -1000, 0, 0, 1};
const Mat transformMatrix(Size(3, 3), CV_32FC1, transformMatrixData);
Mat warpedImage;
warpPerspective(boardImage, warpedImage, transformMatrix, imageSize);
detector.detectMarkers(warpedImage, corners, ids);
EXPECT_EQ(ids.size(), 133ull);
// markers with id 76 and 172 are on border and should not be detected
EXPECT_FALSE(find(ids.begin(), ids.end(), 76) != ids.end());
EXPECT_FALSE(find(ids.begin(), ids.end(), 172) != ids.end());
}
TEST(CV_ArucoMultiDict, setGetDictionaries)
{
vector<aruco::Dictionary> dictionaries = {aruco::getPredefinedDictionary(aruco::DICT_4X4_50), aruco::getPredefinedDictionary(aruco::DICT_5X5_100)};
@@ -590,4 +590,39 @@ INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_decoding, testing::ValuesIn(std::
{"err_correct_2L.png", "Version 2 QR Code Test Image"},
}));
TEST(Objdetect_QRCode_Encode_Decode_Long_Text, regression_issue27183)
{
const int len = 135;
Ptr<QRCodeEncoder> encoder = QRCodeEncoder::create();
std::string input;
input.resize(len);
cv::randu(Mat(1, len, CV_8U, &input[0]), 'a', 'z' + 1);
Mat qrcode;
encoder->encode(input, qrcode);
std::vector<Point2f> corners(4);
corners[0] = Point2f(border_width, border_width);
corners[1] = Point2f(qrcode.cols * 1.0f - border_width, border_width);
corners[2] = Point2f(qrcode.cols * 1.0f - border_width, qrcode.rows * 1.0f - border_width);
corners[3] = Point2f(border_width, qrcode.rows * 1.0f - border_width);
Mat resized_src;
resize(qrcode, resized_src, fixed_size, 0, 0, INTER_AREA);
float width_ratio = resized_src.cols * 1.0f / qrcode.cols;
float height_ratio = resized_src.rows * 1.0f / qrcode.rows;
for(size_t j = 0; j < corners.size(); j++)
{
corners[j].x = corners[j].x * width_ratio;
corners[j].y = corners[j].y * height_ratio;
}
QRCodeDetector detector;
cv::String decoded_msg;
Mat straight_barcode;
EXPECT_NO_THROW(decoded_msg = detector.decode(resized_src, corners, straight_barcode));
ASSERT_FALSE(straight_barcode.empty());
EXPECT_EQ(input, decoded_msg);
}
}} // namespace