[c++]根据二维码矩形特征定位识别位置
-
我们发现左上、左下、右上三个位置探测图形,在二维码的解码过程中,其实是分几个步骤的,首先就是要定位这个二维码确认其位置,然后才能取出里面的数据,而这个定位的点就是这三个。在距离二维码较远时,可能无法解析出完整的数据,但是却能定位这个二维码,通过定位点的信息,我们可以进行放大的操作,从而获取到更加精确的图像数据,也更有利于我们解析。
/**
* 没有查询到二维码结果,但是能基本能定位到二维码,根据返回的数据集,检验是否要放大
*
* @param result 二维码定位信息
*/
void tryZoom(BarcodeReader.Result result) {
int len = 0;
float[] points = result.getPoints();
if (points.length > 3) {
float point1X = points[0];
float point1Y = points[1];
float point2X = points[2];
float point2Y = points[3];
float xLen = Math.abs(point1X - point2X);
float yLen = Math.abs(point1Y - point2Y);
len = (int) Math.sqrt(xLen * xLen + yLen * yLen);
}
handleAutoZoom(len);
}
- 与微信的对比
微信的扫一扫可以说是秒级的处理,特别是在iOS的设备上,更不可思议的是它好像没有距离的限制。经过我们的优化之后,我们的二维码可以在50cm内解析出来,但是与微信相差的还是太远,我们需要更好的处理图像数据,来定位二维码。
6. OpenCV
源文件.cpp
// // Created by leoxae on 19-8-28. // #include "checkQrcode.h" float checkQrcode::getDistance(Point pointO, Point pointA) { float distance; distance = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2); distance = sqrtf(distance); return distance; } void checkQrcode::check_center(vector<vector<Point> > c, vector<int> &index) { float dmin1 = 10000; float dmin2 = 10000; for (int i = 0; i < c.size(); ++i) { RotatedRect rect_i = minAreaRect(c[i]); for (int j = i + 1; j < c.size(); ++j) { RotatedRect rect_j = minAreaRect(c[j]); float d = getDistance(rect_i.center, rect_j.center); if (d < dmin2 && d > 10) { if (d < dmin1 && d > 10) { dmin2 = dmin1; dmin1 = d; index[2] = index[0]; index[3] = index[1]; index[0] = i; index[1] = j; } else { dmin2 = d; index[2] = i; index[3] = j; } } } } } Rect checkQrcode::processData(const Mat gray, Rect resultRect) { Rect RoiRect; // Mat gray(h, w, CV_8UC4, data); // imwrite("/storage/emulated/0/scan/src.jpg", gray); // Mat filter; // bilateralFilter(gray, filter, 15, 150, 15, 4); // imwrite("/storage/emulated/0/scan/filter.jpg", filter); int w = gray.cols; int h = gray.rows; // 进行canny化,变成黑白线条构成的图片 Mat binary; Canny(gray, binary, 100, 255, 3); // imwrite("/storage/emulated/0/scan/src_canny.jpg", binary); // detect rectangle now vector<vector<Point>> contours; vector<Vec4i> hierarchy; vector<int> found; vector<vector<Point>> found_contours; findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); // Mat result = Mat::zeros(gray.size(), CV_8UC4); for (int t = 0; t < contours.size(); ++t) { double area = contourArea(contours[t]); if (area < 150) continue; RotatedRect rect = minAreaRect(contours[t]); // 根据矩形特征进行几何分析 float rect_w = rect.size.width; float rect_h = rect.size.height; float rate = min(rect_w, rect_h) / max(rect_w, rect_h); if (rate > 0.65 && rect_w < (gray.cols >> 2) && rect_h < (gray.rows >> 2)) { int k = t; int c = 0; while (hierarchy[k][2] != -1) { k = hierarchy[k][2]; c = c + 1; } if (c >= 1) { found.push_back(t); found_contours.push_back(contours[t]); // drawContours(result, contours, static_cast<int>(t), Scalar(255, 0, 0), 2, 8); } } } // imwrite("/storage/emulated/0/scan/src_patter_1.jpg", result); if (found.size() >= 3) { vector<int> indexs(4, -1); check_center(found_contours, indexs); vector<Point> final; for (int i = 0; i < 4; ++i) { if (indexs[i] == -1) { continue; } RotatedRect part_rect = minAreaRect(found_contours[indexs[i]]); Point2f p[4]; part_rect.points(p); for (auto &j : p) { final.push_back(j); } } //region of qr Rect ROI = boundingRect(final); // if (ROI.empty()) { // return; // } int space = 0; if (ROI.width < ROI.height) { space = ROI.height - ROI.width; ROI = ROI + Size(space, 0); } else if (ROI.width > ROI.height) { space = ROI.width - ROI.height; ROI = ROI + Size(0, space); } Point left_top = ROI.tl(); Point right_down = ROI.br(); if (left_top.x >= 20 || left_top.y >= 20 || right_down.x <= w - 20 || right_down.y <= h - 20) { ROI = ROI + Point(-20, -20) + Size(40, 40); } if (ROI.tl().x > 0 && ROI.tl().y > 0 && ROI.br().x < w && ROI.br().y < h) { // rectangle(result, ROI.tl(), ROI.br(), Scalar(0, 0, 255)); // imwrite("/storage/emulated/0/scan/src_patter_2.jpg", result); RoiRect = ROI; } } return RoiRect; }
头文件.h
// // Created by leoxae on 19-8-28. // #ifndef KEEKOAIROBOT_CHECKQRCODE_H #define KEEKOAIROBOT_CHECKQRCODE_H #include "../../globals.h" using namespace std; using namespace cv; class checkQrcode{ public: static float getDistance(Point pointO, Point pointA); static void check_center(vector<vector<Point> > c, vector<int> &index); static Rect processData(const Mat gray, Rect resultRect); }; #endif //KEEKOAIROBOT_CHECKQRCODE_H
Talk is cheap. Show me the code