[c++]根據二維碼矩形特征定位識別位置


  1. 我們發現左上、左下、右上三個位置探測圖形,在二維碼的解碼過程中,其實是分幾個步驟的,首先就是要定位這個二維碼確認其位置,然后才能取出里面的數據,而這個定位的點就是這三個。在距離二維碼較遠時,可能無法解析出完整的數據,但是卻能定位這個二維碼,通過定位點的信息,我們可以進行放大的操作,從而獲取到更加精確的圖像數據,也更有利於我們解析。

     
    二維碼結構 
    /** * 沒有查詢到二維碼結果,但是能基本能定位到二維碼,根據返回的數據集,檢驗是否要放大 * * @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); } 
  1. 與微信的對比
    微信的掃一掃可以說是秒級的處理,特別是在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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM