-
我們發現左上、左下、右上三個位置探測圖形,在二維碼的解碼過程中,其實是分幾個步驟的,首先就是要定位這個二維碼確認其位置,然后才能取出里面的數據,而這個定位的點就是這三個。在距離二維碼較遠時,可能無法解析出完整的數據,但是卻能定位這個二維碼,通過定位點的信息,我們可以進行放大的操作,從而獲取到更加精確的圖像數據,也更有利於我們解析。
二維碼結構
/** * 沒有查詢到二維碼結果,但是能基本能定位到二維碼,根據返回的數據集,檢驗是否要放大 * * @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
