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:
@@ -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;
|
||||
|
||||
@@ -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]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user