mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
Merge pull request #13097 from alalek:backport_13086
This commit is contained in:
commit
57a30a1dd8
@ -670,16 +670,46 @@ public:
|
||||
void groupRectangles(std::vector<cv::Rect>& rectList, std::vector<double>& weights, int groupThreshold, double eps) const;
|
||||
};
|
||||
|
||||
class CV_EXPORTS QRCodeDetector
|
||||
class CV_EXPORTS_W QRCodeDetector
|
||||
{
|
||||
public:
|
||||
QRCodeDetector();
|
||||
CV_WRAP QRCodeDetector();
|
||||
~QRCodeDetector();
|
||||
|
||||
void setEpsX(double epsX);
|
||||
void setEpsY(double epsY);
|
||||
/** @brief sets the epsilon used during the horizontal scan of QR code stop marker detection.
|
||||
@param epsX Epsilon neighborhood, which allows you to determine the horizontal pattern
|
||||
of the scheme 1:1:3:1:1 according to QR code standard.
|
||||
*/
|
||||
CV_WRAP void setEpsX(double epsX);
|
||||
/** @brief sets the epsilon used during the vertical scan of QR code stop marker detection.
|
||||
@param epsY Epsilon neighborhood, which allows you to determine the vertical pattern
|
||||
of the scheme 1:1:3:1:1 according to QR code standard.
|
||||
*/
|
||||
CV_WRAP void setEpsY(double epsY);
|
||||
|
||||
bool detect(InputArray in, OutputArray points) const;
|
||||
/** @brief Detects QR code in image and returns the quadrangle containing the code.
|
||||
@param img grayscale or color (BGR) image containing (or not) QR code.
|
||||
@param points Output vector of vertices of the minimum-area quadrangle containing the code.
|
||||
*/
|
||||
CV_WRAP bool detect(InputArray img, OutputArray points) const;
|
||||
|
||||
/** @brief Decodes QR code in image once it's found by the detect() method.
|
||||
Returns UTF8-encoded output string or empty string if the code cannot be decoded.
|
||||
|
||||
@param img grayscale or color (BGR) image containing QR code.
|
||||
@param points Quadrangle vertices found by detect() method (or some other algorithm).
|
||||
@param straight_qrcode The optional output image containing rectified and binarized QR code
|
||||
*/
|
||||
CV_WRAP cv::String decode(InputArray img, InputArray points, OutputArray straight_qrcode = noArray());
|
||||
|
||||
/** @brief Both detects and decodes QR code
|
||||
|
||||
@param img grayscale or color (BGR) image containing QR code.
|
||||
@param points opiotnal output array of vertices of the found QR code quadrangle. Will be empty if not found.
|
||||
@param straight_qrcode The optional output image containing rectified and binarized QR code
|
||||
*/
|
||||
CV_WRAP cv::String detectAndDecode(InputArray img, OutputArray points=noArray(),
|
||||
OutputArray straight_qrcode = noArray());
|
||||
protected:
|
||||
struct Impl;
|
||||
Ptr<Impl> p;
|
||||
@ -700,8 +730,8 @@ CV_EXPORTS bool detectQRCode(InputArray in, std::vector<Point> &points, double e
|
||||
@param straight_qrcode Matrix of the type CV_8UC1 containing an binary straight QR code.
|
||||
*/
|
||||
CV_EXPORTS bool decodeQRCode(InputArray in, InputArray points, std::string &decoded_info, OutputArray straight_qrcode = noArray());
|
||||
//! @} objdetect
|
||||
|
||||
//! @} objdetect
|
||||
}
|
||||
|
||||
#include "opencv2/objdetect/detection_based_tracker.hpp"
|
||||
|
@ -21,7 +21,8 @@ PERF_TEST_P_(Perf_Objdetect_QRCode, detect)
|
||||
ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path;
|
||||
|
||||
std::vector< Point > corners;
|
||||
TEST_CYCLE() ASSERT_TRUE(detectQRCode(src, corners));
|
||||
QRCodeDetector qrcode;
|
||||
TEST_CYCLE() ASSERT_TRUE(qrcode.detect(src, corners));
|
||||
SANITY_CHECK(corners);
|
||||
}
|
||||
|
||||
@ -37,8 +38,13 @@ PERF_TEST_P_(Perf_Objdetect_QRCode, decode)
|
||||
|
||||
std::vector< Point > corners;
|
||||
std::string decoded_info;
|
||||
ASSERT_TRUE(detectQRCode(src, corners));
|
||||
TEST_CYCLE() ASSERT_TRUE(decodeQRCode(src, corners, decoded_info, straight_barcode));
|
||||
QRCodeDetector qrcode;
|
||||
ASSERT_TRUE(qrcode.detect(src, corners));
|
||||
TEST_CYCLE()
|
||||
{
|
||||
decoded_info = qrcode.decode(src, corners, straight_barcode);
|
||||
ASSERT_FALSE(decoded_info.empty());
|
||||
}
|
||||
|
||||
std::vector<uint8_t> decoded_info_uint8_t(decoded_info.begin(), decoded_info.end());
|
||||
SANITY_CHECK(decoded_info_uint8_t);
|
||||
@ -69,7 +75,8 @@ PERF_TEST_P_(Perf_Objdetect_Not_QRCode, detect)
|
||||
rng.fill(not_qr_code, RNG::UNIFORM, Scalar(0), Scalar(1));
|
||||
}
|
||||
|
||||
TEST_CYCLE() ASSERT_FALSE(detectQRCode(not_qr_code, corners));
|
||||
QRCodeDetector qrcode;
|
||||
TEST_CYCLE() ASSERT_FALSE(qrcode.detect(not_qr_code, corners));
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
@ -77,7 +84,6 @@ PERF_TEST_P_(Perf_Objdetect_Not_QRCode, detect)
|
||||
PERF_TEST_P_(Perf_Objdetect_Not_QRCode, decode)
|
||||
{
|
||||
Mat straight_barcode;
|
||||
std::string decoded_info;
|
||||
std::vector< Point > corners;
|
||||
corners.push_back(Point( 0, 0)); corners.push_back(Point( 0, 5));
|
||||
corners.push_back(Point(10, 0)); corners.push_back(Point(15, 15));
|
||||
@ -91,7 +97,8 @@ PERF_TEST_P_(Perf_Objdetect_Not_QRCode, decode)
|
||||
rng.fill(not_qr_code, RNG::UNIFORM, Scalar(0), Scalar(1));
|
||||
}
|
||||
|
||||
TEST_CYCLE() ASSERT_FALSE(decodeQRCode(not_qr_code, corners, decoded_info, straight_barcode));
|
||||
QRCodeDetector qrcode;
|
||||
TEST_CYCLE() ASSERT_TRUE(qrcode.decode(not_qr_code, corners, straight_barcode).empty());
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
#endif
|
||||
|
@ -778,7 +778,15 @@ bool QRCodeDetector::detect(InputArray in, OutputArray points) const
|
||||
{
|
||||
Mat inarr = in.getMat();
|
||||
CV_Assert(!inarr.empty());
|
||||
CV_Assert(inarr.type() == CV_8UC1);
|
||||
CV_Assert(inarr.depth() == CV_8U);
|
||||
int incn = inarr.channels();
|
||||
if( incn == 3 || incn == 4 )
|
||||
{
|
||||
Mat gray;
|
||||
cvtColor(inarr, gray, COLOR_BGR2GRAY);
|
||||
inarr = gray;
|
||||
}
|
||||
|
||||
QRDetect qrdet;
|
||||
qrdet.init(inarr, p->epsX, p->epsY);
|
||||
if (!qrdet.localization()) { return false; }
|
||||
@ -788,7 +796,7 @@ bool QRCodeDetector::detect(InputArray in, OutputArray points) const
|
||||
return true;
|
||||
}
|
||||
|
||||
CV_EXPORTS bool detectQRCode(InputArray in, vector<Point> &points, double eps_x, double eps_y)
|
||||
bool detectQRCode(InputArray in, vector<Point> &points, double eps_x, double eps_y)
|
||||
{
|
||||
QRCodeDetector qrdetector;
|
||||
qrdetector.setEpsX(eps_x);
|
||||
@ -1060,11 +1068,27 @@ bool QRDecode::fullDecodingProcess()
|
||||
#endif
|
||||
}
|
||||
|
||||
CV_EXPORTS bool decodeQRCode(InputArray in, InputArray points, std::string &decoded_info, OutputArray straight_qrcode)
|
||||
bool decodeQRCode(InputArray in, InputArray points, std::string &decoded_info, OutputArray straight_qrcode)
|
||||
{
|
||||
QRCodeDetector qrcode;
|
||||
decoded_info = qrcode.decode(in, points, straight_qrcode);
|
||||
return !decoded_info.empty();
|
||||
}
|
||||
|
||||
cv::String QRCodeDetector::decode(InputArray in, InputArray points,
|
||||
OutputArray straight_qrcode)
|
||||
{
|
||||
Mat inarr = in.getMat();
|
||||
CV_Assert(!inarr.empty());
|
||||
inarr.convertTo(inarr, CV_8UC1);
|
||||
CV_Assert(inarr.depth() == CV_8U);
|
||||
|
||||
int incn = inarr.channels();
|
||||
if( incn == 3 || incn == 4 )
|
||||
{
|
||||
Mat gray;
|
||||
cvtColor(inarr, gray, COLOR_BGR2GRAY);
|
||||
inarr = gray;
|
||||
}
|
||||
|
||||
CV_Assert(points.isVector());
|
||||
vector<Point2f> src_points;
|
||||
@ -1074,18 +1098,50 @@ CV_EXPORTS bool decodeQRCode(InputArray in, InputArray points, std::string &deco
|
||||
|
||||
QRDecode qrdec;
|
||||
qrdec.init(inarr, src_points);
|
||||
bool exit_flag = qrdec.fullDecodingProcess();
|
||||
bool ok = qrdec.fullDecodingProcess();
|
||||
|
||||
decoded_info = qrdec.getDecodeInformation();
|
||||
std::string decoded_info = qrdec.getDecodeInformation();
|
||||
|
||||
if (exit_flag && straight_qrcode.needed())
|
||||
if (ok && straight_qrcode.needed())
|
||||
{
|
||||
qrdec.getStraightBarcode().convertTo(straight_qrcode,
|
||||
straight_qrcode.fixedType() ?
|
||||
straight_qrcode.type() : CV_32FC2);
|
||||
}
|
||||
|
||||
return exit_flag;
|
||||
return ok ? decoded_info : std::string();
|
||||
}
|
||||
|
||||
cv::String QRCodeDetector::detectAndDecode(InputArray in,
|
||||
OutputArray points_,
|
||||
OutputArray straight_qrcode)
|
||||
{
|
||||
Mat inarr = in.getMat();
|
||||
CV_Assert(!inarr.empty());
|
||||
CV_Assert(inarr.depth() == CV_8U);
|
||||
|
||||
int incn = inarr.channels();
|
||||
if( incn == 3 || incn == 4 )
|
||||
{
|
||||
Mat gray;
|
||||
cvtColor(inarr, gray, COLOR_BGR2GRAY);
|
||||
inarr = gray;
|
||||
}
|
||||
|
||||
vector<Point2f> points;
|
||||
bool ok = detect(inarr, points);
|
||||
if( points_.needed() )
|
||||
{
|
||||
if( ok )
|
||||
Mat(points).copyTo(points_);
|
||||
else
|
||||
points_.release();
|
||||
}
|
||||
std::string decoded_info;
|
||||
if( ok )
|
||||
decoded_info = decode(inarr, points, straight_qrcode);
|
||||
return decoded_info;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -66,9 +66,13 @@ TEST_P(Objdetect_QRCode, regression)
|
||||
|
||||
std::vector<Point> corners;
|
||||
std::string decoded_info;
|
||||
ASSERT_TRUE(detectQRCode(src, corners));
|
||||
QRCodeDetector qrcode;
|
||||
#ifdef HAVE_QUIRC
|
||||
ASSERT_TRUE(decodeQRCode(src, corners, decoded_info, straight_barcode));
|
||||
decoded_info = qrcode.detectAndDecode(src, corners, straight_barcode);
|
||||
ASSERT_FALSE(corners.empty());
|
||||
ASSERT_FALSE(decoded_info.empty());
|
||||
#else
|
||||
ASSERT_TRUE(qrcode.detect(src, corners));
|
||||
#endif
|
||||
|
||||
const std::string dataset_config = findDataFile(root + "dataset_config.json", false);
|
||||
@ -119,10 +123,11 @@ TEST(Objdetect_QRCode_basic, not_found_qrcode)
|
||||
Mat straight_barcode;
|
||||
std::string decoded_info;
|
||||
Mat zero_image = Mat::zeros(256, 256, CV_8UC1);
|
||||
EXPECT_FALSE(detectQRCode(zero_image, corners));
|
||||
QRCodeDetector qrcode;
|
||||
EXPECT_FALSE(qrcode.detect(zero_image, corners));
|
||||
#ifdef HAVE_QUIRC
|
||||
corners = std::vector<Point>(4);
|
||||
EXPECT_ANY_THROW(decodeQRCode(zero_image, corners, decoded_info, straight_barcode));
|
||||
EXPECT_ANY_THROW(qrcode.decode(zero_image, corners, straight_barcode));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,7 @@ int liveQRCodeDetect()
|
||||
return -4;
|
||||
}
|
||||
|
||||
QRCodeDetector qrcode;
|
||||
TickMeter total;
|
||||
for(;;)
|
||||
{
|
||||
@ -97,11 +98,11 @@ int liveQRCodeDetect()
|
||||
cvtColor(frame, src, COLOR_BGR2GRAY);
|
||||
|
||||
total.start();
|
||||
bool result_detection = detectQRCode(src, transform);
|
||||
bool result_detection = qrcode.detect(src, transform);
|
||||
if (result_detection)
|
||||
{
|
||||
bool result_decode = decodeQRCode(src, transform, decode_info, straight_barcode);
|
||||
if (result_decode) { cout << decode_info << '\n'; }
|
||||
decode_info = qrcode.decode(src, transform, straight_barcode);
|
||||
if (!decode_info.empty()) { cout << decode_info << '\n'; }
|
||||
}
|
||||
total.stop();
|
||||
double fps = 1 / total.getTimeSec();
|
||||
@ -110,7 +111,7 @@ int liveQRCodeDetect()
|
||||
if (result_detection) { getMatWithQRCodeContour(frame, transform); }
|
||||
getMatWithFPS(frame, fps);
|
||||
|
||||
imshow("Live detect QR code", frame);
|
||||
imshow("Live QR code detector", frame);
|
||||
if( waitKey(30) > 0 ) { break; }
|
||||
}
|
||||
return 0;
|
||||
@ -119,33 +120,34 @@ int liveQRCodeDetect()
|
||||
int showImageQRCodeDetect(string in, string out)
|
||||
{
|
||||
Mat src = imread(in, IMREAD_GRAYSCALE), straight_barcode;
|
||||
string decode_info;
|
||||
string decoded_info;
|
||||
vector<Point> transform;
|
||||
const int count_experiments = 10;
|
||||
double transform_time = 0.0;
|
||||
bool result_detection = false, result_decode = false;
|
||||
bool result_detection = false;
|
||||
TickMeter total;
|
||||
QRCodeDetector qrcode;
|
||||
for (size_t i = 0; i < count_experiments; i++)
|
||||
{
|
||||
total.start();
|
||||
transform.clear();
|
||||
result_detection = detectQRCode(src, transform);
|
||||
result_detection = qrcode.detect(src, transform);
|
||||
total.stop();
|
||||
transform_time += total.getTimeSec();
|
||||
total.reset();
|
||||
if (!result_detection) { break; }
|
||||
|
||||
total.start();
|
||||
result_decode = decodeQRCode(src, transform, decode_info, straight_barcode);
|
||||
decoded_info = qrcode.decode(src, transform, straight_barcode);
|
||||
total.stop();
|
||||
transform_time += total.getTimeSec();
|
||||
total.reset();
|
||||
if (!result_decode) { break; }
|
||||
if (decoded_info.empty()) { break; }
|
||||
|
||||
}
|
||||
double fps = count_experiments / transform_time;
|
||||
if (!result_detection) { cout << "Not find QR-code." << '\n'; return -2; }
|
||||
if (!result_decode) { cout << "Not decode QR-code." << '\n'; return -3; }
|
||||
if (!result_detection) { cout << "QR code not found\n"; return -2; }
|
||||
if (decoded_info.empty()) { cout << "QR code cannot be decoded\n"; return -3; }
|
||||
|
||||
Mat color_src = imread(in);
|
||||
getMatWithQRCodeContour(color_src, transform);
|
||||
@ -166,7 +168,7 @@ int showImageQRCodeDetect(string in, string out)
|
||||
cout << "Output image file path: " << out << '\n';
|
||||
cout << "Size: " << color_src.size() << '\n';
|
||||
cout << "FPS: " << fps << '\n';
|
||||
cout << "Decode info: " << decode_info << '\n';
|
||||
cout << "Decoded info: " << decoded_info << '\n';
|
||||
|
||||
vector<int> compression_params;
|
||||
compression_params.push_back(IMWRITE_PNG_COMPRESSION);
|
||||
|
Loading…
Reference in New Issue
Block a user