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:
@@ -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();
|
||||
|
||||
@@ -35,6 +35,8 @@ static inline bool readWrite(DetectorParameters ¶ms, 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]
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user