[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

 

posted @ 2019-08-29 11:33  Xu_Lin  阅读(927)  评论(0编辑  收藏  举报