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
2023-10-16 21:25:56 +03:00
221 changed files with 3584 additions and 2215 deletions
@@ -721,19 +721,21 @@ public:
ECI_UTF8 = 26
};
/** @brief QR code encoder parameters.
@param version The optional version of QR code (by default - maximum possible depending on
the length of the string).
@param correction_level The optional level of error correction (by default - the lowest).
@param mode The optional encoding mode - Numeric, Alphanumeric, Byte, Kanji, ECI or Structured Append.
@param structure_number The optional number of QR codes to generate in Structured Append mode.
*/
/** @brief QR code encoder parameters. */
struct CV_EXPORTS_W_SIMPLE Params
{
CV_WRAP Params();
//! The optional version of QR code (by default - maximum possible depending on the length of the string).
CV_PROP_RW int version;
//! The optional level of error correction (by default - the lowest).
CV_PROP_RW CorrectionLevel correction_level;
//! The optional encoding mode - Numeric, Alphanumeric, Byte, Kanji, ECI or Structured Append.
CV_PROP_RW EncodeMode mode;
//! The optional number of QR codes to generate in Structured Append mode.
CV_PROP_RW int structure_number;
};
@@ -36,6 +36,7 @@ struct CV_EXPORTS_W_SIMPLE DetectorParameters {
minMarkerDistanceRate = 0.05;
cornerRefinementMethod = (int)CORNER_REFINE_NONE;
cornerRefinementWinSize = 5;
relativeCornerRefinmentWinSize = 0.3f;
cornerRefinementMaxIterations = 30;
cornerRefinementMinAccuracy = 0.1;
markerBorderBits = 1;
@@ -56,7 +57,7 @@ struct CV_EXPORTS_W_SIMPLE DetectorParameters {
useAruco3Detection = false;
minSideLengthCanonicalImg = 32;
minMarkerLengthRatioOriginalImg = 0.0;
};
}
/** @brief Read a new set of DetectorParameters from FileNode (use FileStorage.root()).
*/
@@ -108,9 +109,27 @@ struct CV_EXPORTS_W_SIMPLE DetectorParameters {
/** @brief default value CORNER_REFINE_NONE */
CV_PROP_RW int cornerRefinementMethod;
/// window size for the corner refinement process (in pixels) (default 5).
/** @brief maximum window size for the corner refinement process (in pixels) (default 5).
*
* The window size may decrease if the ArUco marker is too small, check relativeCornerRefinmentWinSize.
* The final window size is calculated as:
* min(cornerRefinementWinSize, averageArucoModuleSize*relativeCornerRefinmentWinSize),
* where averageArucoModuleSize is average module size of ArUco marker in pixels.
* (ArUco marker is composed of black and white modules)
*/
CV_PROP_RW int cornerRefinementWinSize;
/** @brief Dynamic window size for corner refinement relative to Aruco module size (default 0.3).
*
* The final window size is calculated as:
* min(cornerRefinementWinSize, averageArucoModuleSize*relativeCornerRefinmentWinSize),
* where averageArucoModuleSize is average module size of ArUco marker in pixels.
* (ArUco marker is composed of black and white modules)
* In the case of markers located far from each other, it may be useful to increase the value of the parameter to 0.4-0.5.
* In the case of markers located close to each other, it may be useful to decrease the parameter value to 0.1-0.2.
*/
CV_PROP_RW float relativeCornerRefinmentWinSize;
/// maximum number of iterations for stop criteria of the corner refinement process (default 30).
CV_PROP_RW int cornerRefinementMaxIterations;
@@ -192,7 +192,7 @@ class CV_EXPORTS DetectionBasedTracker
{
lastPositions.push_back(rect);
id=getNextId();
};
}
static int getNextId()
{
@@ -20,7 +20,7 @@ model download link: https://github.com/opencv/opencv_zoo/tree/master/models/fac
class CV_EXPORTS_W FaceDetectorYN
{
public:
virtual ~FaceDetectorYN() {};
virtual ~FaceDetectorYN() {}
/** @brief Set the size for the network input, which overwrites the input size of creating model. Call this method when the size of input image does not match the input size when creating model
*
@@ -99,7 +99,7 @@ model download link: https://github.com/opencv/opencv_zoo/tree/master/models/fac
class CV_EXPORTS_W FaceRecognizerSF
{
public:
virtual ~FaceRecognizerSF() {};
virtual ~FaceRecognizerSF() {}
/** @brief Definition of distance used for calculating the distance between two face features
*/
+12 -2
View File
@@ -3,6 +3,7 @@
// of this distribution and at http://opencv.org/license.html
#include "../precomp.hpp"
#include <opencv2/core/utils/logger.hpp>
#include "opencv2/objdetect/aruco_board.hpp"
#include <opencv2/objdetect/aruco_dictionary.hpp>
@@ -250,7 +251,11 @@ GridBoard::GridBoard() {}
GridBoard::GridBoard(const Size& size, float markerLength, float markerSeparation,
const Dictionary &dictionary, InputArray ids):
Board(new GridBoardImpl(dictionary, size, markerLength, markerSeparation)) {
float onePin = markerLength / ((float)(dictionary.markerSize+2));
if (markerSeparation < onePin*.7f) {
CV_LOG_WARNING(NULL, "Marker border " << markerSeparation << " is less than 70% of ArUco pin size "
<< onePin << ". Please increase markerSeparation or decrease markerLength for stable board detection");
}
size_t totalMarkers = (size_t) size.width*size.height;
CV_Assert(ids.empty() || totalMarkers == ids.total());
vector<vector<Point3f> > objPoints;
@@ -541,7 +546,12 @@ CharucoBoard::CharucoBoard(const Size& size, float squareLength, float markerLen
Board(new CharucoBoardImpl(dictionary, size, squareLength, markerLength)) {
CV_Assert(size.width > 1 && size.height > 1 && markerLength > 0 && squareLength > markerLength);
float onePin = markerLength / ((float)(dictionary.markerSize+2));
float markerSeparation = (squareLength - markerLength)/2.f;
if (markerSeparation < onePin*.7f) {
CV_LOG_WARNING(NULL, "Marker border " << markerSeparation << " is less than 70% of ArUco pin size "
<< onePin <<". Please increase markerSeparation or decrease markerLength for stable board detection");
}
ids.copyTo(impl->ids);
static_pointer_cast<CharucoBoardImpl>(impl)->createCharucoBoard();
+30 -13
View File
@@ -35,6 +35,8 @@ static inline bool readWrite(DetectorParameters &params, const FileNode* readNod
check |= readWriteParameter("minMarkerDistanceRate", params.minMarkerDistanceRate, readNode, writeStorage);
check |= readWriteParameter("cornerRefinementMethod", params.cornerRefinementMethod, readNode, writeStorage);
check |= readWriteParameter("cornerRefinementWinSize", params.cornerRefinementWinSize, readNode, writeStorage);
check |= readWriteParameter("relativeCornerRefinmentWinSize", params.relativeCornerRefinmentWinSize, readNode,
writeStorage);
check |= readWriteParameter("cornerRefinementMaxIterations", params.cornerRefinementMaxIterations,
readNode, writeStorage);
check |= readWriteParameter("cornerRefinementMinAccuracy", params.cornerRefinementMinAccuracy,
@@ -692,7 +694,7 @@ static void _identifyCandidates(InputArray grey,
/**
* Line fitting A * B = C :: Called from function refineCandidateLines
* @param nContours, contour-container
* @param nContours contour-container
*/
static Point3f _interpolate2Dline(const vector<Point2f>& nContours){
CV_Assert(nContours.size() >= 2);
@@ -748,10 +750,8 @@ static Point2f _getCrossPoint(Point3f nLine1, Point3f nLine2){
/**
* Refine Corners using the contour vector :: Called from function detectMarkers
* @param nContours, contour-container
* @param nCorners, candidate Corners
* @param camMatrix, cameraMatrix input 3x3 floating-point camera matrix
* @param distCoeff, distCoeffs vector of distortion coefficient
* @param nContours contour-container
* @param nCorners candidate Corners
*/
static void _refineCandidateLines(vector<Point>& nContours, vector<Point2f>& nCorners){
vector<Point2f> contour2f(nContours.begin(), nContours.end());
@@ -847,6 +847,16 @@ struct ArucoDetector::ArucoDetectorImpl {
const RefineParameters& _refineParams): dictionary(_dictionary),
detectorParams(_detectorParams), refineParams(_refineParams) {}
float getAverageArucoPinSize(vector<Point2f> markerCorners) {
float averageArucoModuleSize = 0.f;
int numPins = dictionary.markerSize + detectorParams.markerBorderBits * 2;
for (size_t i = 0ull; i < markerCorners.size(); i++) {
averageArucoModuleSize += sqrt(normL2Sqr<float>(Point2f(markerCorners[i] - markerCorners[(i+1ull)%markerCorners.size()])));
}
averageArucoModuleSize /= ((float)markerCorners.size()*numPins);
return averageArucoModuleSize;
}
};
ArucoDetector::ArucoDetector(const Dictionary &_dictionary,
@@ -951,13 +961,15 @@ void ArucoDetector::detectMarkers(InputArray _image, OutputArrayOfArrays _corner
const float scale_init = (float) grey_pyramid[closest_pyr_image_idx].cols / grey.cols;
findCornerInPyrImage(scale_init, closest_pyr_image_idx, grey_pyramid, Mat(candidates[i]), detectorParams);
}
else
cornerSubPix(grey, Mat(candidates[i]),
Size(detectorParams.cornerRefinementWinSize, detectorParams.cornerRefinementWinSize),
Size(-1, -1),
TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS,
detectorParams.cornerRefinementMaxIterations,
detectorParams.cornerRefinementMinAccuracy));
else {
int cornerRefinementWinSize = std::max(1, cvRound(detectorParams.relativeCornerRefinmentWinSize*
arucoDetectorImpl->getAverageArucoPinSize(candidates[i])));
cornerRefinementWinSize = min(cornerRefinementWinSize, detectorParams.cornerRefinementWinSize);
cornerSubPix(grey, Mat(candidates[i]), Size(cornerRefinementWinSize, cornerRefinementWinSize), Size(-1, -1),
TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS,
detectorParams.cornerRefinementMaxIterations,
detectorParams.cornerRefinementMinAccuracy));
}
}
});
}
@@ -1223,8 +1235,13 @@ void ArucoDetector::refineDetectedMarkers(InputArray _image, const Board& _board
CV_Assert(detectorParams.cornerRefinementWinSize > 0 &&
detectorParams.cornerRefinementMaxIterations > 0 &&
detectorParams.cornerRefinementMinAccuracy > 0);
std::vector<Point2f> marker(closestRotatedMarker.begin<Point2f>(), closestRotatedMarker.end<Point2f>());
int cornerRefinementWinSize = std::max(1, cvRound(detectorParams.relativeCornerRefinmentWinSize*
arucoDetectorImpl->getAverageArucoPinSize(marker)));
cornerRefinementWinSize = min(cornerRefinementWinSize, detectorParams.cornerRefinementWinSize);
cornerSubPix(grey, closestRotatedMarker,
Size(detectorParams.cornerRefinementWinSize, detectorParams.cornerRefinementWinSize),
Size(cornerRefinementWinSize, cornerRefinementWinSize),
Size(-1, -1), TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS,
detectorParams.cornerRefinementMaxIterations,
detectorParams.cornerRefinementMinAccuracy));
@@ -27,13 +27,12 @@ struct CharucoDetector::CharucoDetectorImpl {
bool checkBoard(InputArrayOfArrays markerCorners, InputArray markerIds, InputArray charucoCorners, InputArray charucoIds) {
vector<Mat> mCorners;
markerCorners.getMatVector(mCorners);
const Mat& mIds = markerIds.getMat();
const Mat& chCorners = charucoCorners.getMat();
const Mat& chIds = charucoIds.getMat();
const Mat mIds = markerIds.getMat();
const Mat chCorners = charucoCorners.getMat();
const Mat chIds = charucoIds.getMat();
const vector<int>& boardIds = board.getIds();
const vector<vector<int> >& nearestMarkerIdx = board.getNearestMarkerIdx();
const vector<vector<int> > nearestMarkerIdx = board.getNearestMarkerIdx();
vector<Point2f> distance(board.getNearestMarkerIdx().size(), Point2f(0.f, std::numeric_limits<float>::max()));
// distance[i].x: max distance from the i-th charuco corner to charuco corner-forming markers.
// The two charuco corner-forming markers of i-th charuco corner are defined in getNearestMarkerIdx()[i]
+4 -4
View File
@@ -25,7 +25,7 @@ public:
net.setPreferableBackend(backend_id);
net.setPreferableTarget(target_id);
};
}
void alignCrop(InputArray _src_img, InputArray _face_mat, OutputArray _aligned_img) const override
{
Mat face_mat = _face_mat.getMat();
@@ -39,13 +39,13 @@ public:
}
Mat warp_mat = getSimilarityTransformMatrix(src_point);
warpAffine(_src_img, _aligned_img, warp_mat, Size(112, 112), INTER_LINEAR);
};
}
void feature(InputArray _aligned_img, OutputArray _face_feature) override
{
Mat inputBolb = dnn::blobFromImage(_aligned_img, 1, Size(112, 112), Scalar(0, 0, 0), true, false);
net.setInput(inputBolb);
net.forward(_face_feature);
};
}
double match(InputArray _face_feature1, InputArray _face_feature2, int dis_type) const override
{
Mat face_feature1 = _face_feature1.getMat(), face_feature2 = _face_feature2.getMat();
@@ -60,7 +60,7 @@ public:
throw std::invalid_argument("invalid parameter " + std::to_string(dis_type));
}
};
}
private:
Mat getSimilarityTransformMatrix(float src[5][2]) const {
+102 -3
View File
@@ -2728,6 +2728,58 @@ bool QRDecode::samplingForVersion()
return true;
}
static bool checkASCIIcompatible(const uint8_t* str, const size_t size) {
for (size_t i = 0; i < size; ++i) {
uint8_t byte = str[i];
if (byte >= 0x80)
return false;
}
return true;
}
static bool checkUTF8(const uint8_t* str, const size_t size) {
for (size_t i = 0; i < size; ++i) {
uint8_t byte = str[i];
if (byte >= 0x80) {
// Check that symbol is encoded correctly.
// Count number of bytes per symbol as a number of leading non-zero bits
uint8_t numBytesPerSymbol;
if ((byte & 0xe0) == 0xc0)
numBytesPerSymbol = 2;
else if ((byte & 0xf0) == 0xe0)
numBytesPerSymbol = 3;
else if ((byte & 0xf8) == 0xf0)
numBytesPerSymbol = 4;
else
return false;
for (size_t j = 1; j < numBytesPerSymbol; ++j) {
if (i + j >= size || (str[i + j] & 0xc0) != 0x80) {
return false;
}
}
i += numBytesPerSymbol - 1;
}
}
return true;
}
static std::string encodeUTF8_bytesarray(const uint8_t* str, const size_t size) {
std::ostringstream res;
for (size_t i = 0; i < size; ++i) {
uint8_t byte = str[i];
if (byte >= 0x80) {
res << (char)(0xc0 | (byte >> 6));
res << (char)(0x80 | (byte & 0x3f));
} else {
res << (char)byte;
}
}
return res.str();
}
bool QRDecode::decodingProcess()
{
#ifdef HAVE_QUIRC
@@ -2757,11 +2809,58 @@ bool QRDecode::decodingProcess()
if (errorCode != 0) { return false; }
for (int i = 0; i < qr_code_data.payload_len; i++)
CV_LOG_INFO(NULL, "QR: decoded with .version=" << qr_code_data.version << " .data_type=" << qr_code_data.data_type << " .eci=" << qr_code_data.eci << " .payload_len=" << qr_code_data.payload_len)
switch (qr_code_data.data_type)
{
result_info += qr_code_data.payload[i];
case QUIRC_DATA_TYPE_NUMERIC:
if (!checkASCIIcompatible(qr_code_data.payload, qr_code_data.payload_len)) {
CV_LOG_INFO(NULL, "QR: DATA_TYPE_NUMERIC payload must be ACSII compatible string");
return false;
}
result_info.assign((const char*)qr_code_data.payload, qr_code_data.payload_len);
return true;
case QUIRC_DATA_TYPE_ALPHA:
if (!checkASCIIcompatible(qr_code_data.payload, qr_code_data.payload_len)) {
CV_LOG_INFO(NULL, "QR: DATA_TYPE_ALPHA payload must be ASCII compatible string");
return false;
}
result_info.assign((const char*)qr_code_data.payload, qr_code_data.payload_len);
return true;
case QUIRC_DATA_TYPE_BYTE:
// https://en.wikipedia.org/wiki/Extended_Channel_Interpretation
if (qr_code_data.eci == QUIRC_ECI_UTF_8) {
CV_LOG_INFO(NULL, "QR: payload ECI is UTF-8");
if (!checkUTF8(qr_code_data.payload, qr_code_data.payload_len)) {
CV_LOG_INFO(NULL, "QUIRC_DATA_TYPE_BYTE with UTF-8 ECI must be UTF-8 compatible string");
return false;
}
result_info.assign((const char*)qr_code_data.payload, qr_code_data.payload_len);
} else if (qr_code_data.eci == 25/*ECI_UTF_16BE*/) {
CV_LOG_INFO(NULL, "QR: UTF-16BE ECI is not supported");
return false;
} else if (checkASCIIcompatible(qr_code_data.payload, qr_code_data.payload_len)) {
CV_LOG_INFO(NULL, "QR: payload is ASCII compatible (special handling for symbols encoding is not needed)");
result_info.assign((const char*)qr_code_data.payload, qr_code_data.payload_len);
} else {
if (checkUTF8(qr_code_data.payload, qr_code_data.payload_len)) {
CV_LOG_INFO(NULL, "QR: payload QUIRC_DATA_TYPE_BYTE is UTF-8 compatible, return as-is");
result_info.assign((const char*)qr_code_data.payload, qr_code_data.payload_len);
} else {
CV_LOG_INFO(NULL, "QR: assume 1-byte per symbol encoding");
result_info = encodeUTF8_bytesarray(qr_code_data.payload, qr_code_data.payload_len);
}
}
return true;
case QUIRC_DATA_TYPE_KANJI:
// FIXIT BUG: we must return UTF-8 compatible string
CV_LOG_WARNING(NULL, "QR: Kanji is not supported properly");
result_info.assign((const char*)qr_code_data.payload, qr_code_data.payload_len);
return true;
}
return true;
CV_LOG_WARNING(NULL, "QR: unsupported QR data type");
return false;
#else
return false;
#endif
+1 -1
View File
@@ -703,7 +703,7 @@ bool QRCodeEncoderImpl::stringToBits(const std::string& input_info)
default:
return encodeAuto(input_info, payload);
}
};
}
void QRCodeEncoderImpl::eccGenerate(vector<vector<uint8_t> > &data_blocks, vector<vector<uint8_t> > &ecc_blocks)
{
+21
View File
@@ -637,4 +637,25 @@ TEST_P(Objdetect_QRCode_detectAndDecodeMulti, decode_9_qrcodes_version7)
#endif // UPDATE_QRCODE_TEST_DATA
TEST(Objdetect_QRCode_detectAndDecode, utf8_output)
{
#ifndef HAVE_QUIRC
throw SkipTestException("Quirc is required for decoding");
#else
const std::string name_current_image = "umlaut.png";
const std::string root = "qrcode/";
std::string image_path = findDataFile(root + name_current_image);
Mat src = imread(image_path);
ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path;
QRCodeDetector qrcode;
std::vector<Point> corners;
Mat straight;
std::string decoded_info = qrcode.detectAndDecode(src, corners, straight);
EXPECT_FALSE(decoded_info.empty());
EXPECT_NE(decoded_info.find("M\xc3\xbcllheimstrasse"), std::string::npos);
#endif // HAVE_QUIRC
}
}} // namespace