refined QRCodeDetector API for OpenCV 4.0 (#13086)
* refined QRCodeDetector API for OpenCV 4.0 * expanded and tested QRCodeDetector::detectAndDecode()
This commit is contained in:
@@ -667,36 +667,51 @@ 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 std::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 std::string detectAndDecode(InputArray img, OutputArray points=noArray(),
|
||||
OutputArray straight_qrcode = noArray());
|
||||
protected:
|
||||
struct Impl;
|
||||
Ptr<Impl> p;
|
||||
};
|
||||
|
||||
/** @brief Detect QR code in image and return minimum area of quadrangle that describes QR code.
|
||||
@param in Matrix of the type CV_8U containing an image where QR code are detected.
|
||||
@param points Output vector of vertices of a quadrangle of minimal area that describes QR code.
|
||||
@param eps_x Epsilon neighborhood, which allows you to determine the horizontal pattern of the scheme 1:1:3:1:1 according to QR code standard.
|
||||
@param eps_y Epsilon neighborhood, which allows you to determine the vertical pattern of the scheme 1:1:3:1:1 according to QR code standard.
|
||||
*/
|
||||
CV_EXPORTS bool detectQRCode(InputArray in, std::vector<Point> &points, double eps_x = 0.2, double eps_y = 0.1);
|
||||
|
||||
/** @brief Decode QR code in image and return text that is encrypted in QR code.
|
||||
@param in Matrix of the type CV_8UC1 containing an image where QR code are detected.
|
||||
@param points Input vector of vertices of a quadrangle of minimal area that describes QR code.
|
||||
@param decoded_info String information that is encrypted in QR code.
|
||||
@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
|
||||
|
||||
}
|
||||
|
||||
@@ -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,15 +796,6 @@ 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)
|
||||
{
|
||||
QRCodeDetector qrdetector;
|
||||
qrdetector.setEpsX(eps_x);
|
||||
qrdetector.setEpsY(eps_y);
|
||||
|
||||
return qrdetector.detect(in, points);
|
||||
}
|
||||
|
||||
class QRDecode
|
||||
{
|
||||
public:
|
||||
@@ -1060,11 +1059,20 @@ bool QRDecode::fullDecodingProcess()
|
||||
#endif
|
||||
}
|
||||
|
||||
CV_EXPORTS bool decodeQRCode(InputArray in, InputArray points, std::string &decoded_info, OutputArray straight_qrcode)
|
||||
CV_EXPORTS std::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 +1082,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_EXPORTS std::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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user