opencv前段时间已经发布了4.0.0版本,就着这个机会学习一下opencv中的实现。需说明的是,opencv二维码检测模块是基于Quirc(git://github.com/dlbeer/quirc.git)这个开源库集成开发的。
qr码检测到类为QRCodeDetector,其主要成员函数有
我们把重点放到定位detect()上,这基本上也是qr码检测成败的关键。
bool QRCodeDetector::detect(InputArray in, OutputArray points) const
{
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;
}
QRDetect qrdet;
qrdet.init(inarr, p->epsX, p->epsY);
if (!qrdet.localization()) { return false; }
if (!qrdet.computeTransformationPoints()) { return false; }
vector pnts2f = qrdet.getTransformationPoints();
Mat(pnts2f).convertTo(points, points.fixedType() ? points.type() : CV_32FC2);
return true;
}
可以看到detect函数先将图片转为灰度图,然后执行调用QRDetect这个类来进行检测,我们来分析QRDetect这个类。
class QRDetect
{
public:
void init(const Mat& src, double eps_vertical_ = 0.2, double eps_horizontal_ = 0.1);
bool localization();
bool computeTransformationPoints();
Mat getBinBarcode() { return bin_barcode; }
Mat getStraightBarcode() { return straight_barcode; }
vector getTransformationPoints() { return transformation_points; }
static Point2f intersectionLines(Point2f a1, Point2f a2, Point2f b1, Point2f b2);
protected:
vector searchHorizontalLines();
vector separateVerticalLines(const vector &list_lines);
void fixationPoints(vector &local_point);
vector getQuadrilateral(vector angle_list);
bool testBypassRoute(vector hull, int start, int finish);
inline double getCosVectors(Point2f a, Point2f b, Point2f c);
Mat barcode, bin_barcode, straight_barcode;
vector localization_points, transformation_points;
double eps_vertical, eps_horizontal, coeff_expansion;
};
QRCodeDetector detect函数中的QRDetect qrdet这个对象
对聚类完后3个点使用fixationPoints来重新修正,在其中先用余弦定理滤除掉任意角余弦值小于0.85的情况,后面进行了一 系列的修正(待补充);
最后滤除相邻点距离小于10pixel的情况。
3.在computeTransformationPoints()函数中主要有两个操作,
一个是查找对齐点,这里直接搬运别人博客上的内容(http://www.p-chao.com/2018-11-23/opencv4-0-0%E4%BA%8C%E7%BB%B4%E7%A0%81%E8%AF%86%E5%88%AB%E4%BB%A3%E7%A0%81%E7%AE%80%E6%9E%90/):
最开始会找到下图中的三个红色的特征点,这个比较容易理解,因为左上角的点到其它两个点的距离是差不多的。
然后在左下角和右上角的回字上,找离左上角红点最远的点,那么可以得到两个蓝颜色的特征点
根据红蓝点连线的交叉点,就可以得到第四各顶点,这样对齐需要的点我们就都找到了
第二个是进行透视变换,opencv中选取了5组点对,在上述找到的4个顶点外,还通过计算对角线交点算出了中心点,使用这5额点来计算Homograph,然后透视变换回去,就可以得到一个理想的正对我们的二维码了。
opencv直接调用了quirc解码,该部分不是关注重点,本文不做赘述。