[opencv]QRcodeLocation

 

//
// Created by leoxae on 19-10-18.
//

#include "QRcodeLocation.h"
#include "../math/PlaneGeometry.h"

/**
 * 获取QRcode的mat集合
 * @param img
 * @return
 */
vector<Mat> QRcodeLocation::FindQRcode(Mat img) {

//    Mat hsv;
//    cvtColor(img, hsv, COLOR_BGR2HSV);
//    Scalar lower_white(0, 0, 0);
//    Scalar upper_white(180, 255, 180);
//    Mat mask_white;
//    inRange(hsv, lower_white, upper_white, mask_white);
//    Mat gray = mask_white;
//    threshold(gray, gray, 100, 255, THRESH_OTSU + THRESH_BINARY);
//    Scalar color(1, 1, 255);
//    Mat threshold_output;
//    threshold(gray, threshold_output, 112, 255, THRESH_BINARY);
//    imshow("threshold_output",threshold_output);
//    waitKey();

    Mat gray;
    Mat resimg;
    cvtColor(img, gray, COLOR_BGR2GRAY);
    adaptiveThreshold(gray, gray, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 9, 3);
    imshow("gray", gray);
    waitKey();

    vector<Mat> qrMatList;
    vector<Point> qrPointList;
    vector<vector<Point>> qrcontourList;
    vector<int> indexx;
    vector<vector<Point>> contours;
    vector<Vec4i> hierachy;
    findContours(gray, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE);
    if (hierachy.empty()) {
        qrMatList.emplace_back(img);
        return qrMatList;
    }

    for (int i = 0; i < hierachy.size(); i++) {
        auto child = hierachy[i][2];
        auto child_child = hierachy[child][2];
        if (child != -1 && child_child != -1) {
            if (AreaRate(contours[i], contours[child]) >= 10 && AreaRate(contours[i], contours[child]) < 40 &&
                AreaRate(contours[child], contours[child_child]) >= 10 &&
                AreaRate(contours[child], contours[child_child]) < 40 && contourArea(contours[i]) > 100) {
                Point pt1 = ContourCenter(contours[i]);
                Point pt2 = ContourCenter(contours[child]);
                Point pt3 = ContourCenter(contours[child_child]);
                if (CheckRec(pt1, pt2, pt3) && hierachy[i][1] != -1) {
                    drawContours(img, contours, i, Scalar(255, 0, 0), 1, 1);
                    cout << "indexss==>>" << i << endl;
                    imshow("drawContours", img);
                    waitKey();
                    qrPointList.emplace_back(pt1);
                    qrPointList.emplace_back(pt2);
                    qrPointList.emplace_back(pt3);
                    indexx.emplace_back(i);
                    qrcontourList.emplace_back(contours[i]);
                }
            }
        }
    }

    //去除重复元素
    qrPointList.erase(unique(qrPointList.begin(), qrPointList.end()), qrPointList.end());
    vector<vector<int>> levelList = JudgeTriangle(qrcontourList, indexx);
    if (levelList.empty()) {
        qrMatList.emplace_back(img);
        return qrMatList;
    }
    cout << "qrcontourList==>>" << qrcontourList.size() << endl;

//    for (int i = 0; i < qrPointList.size(); i++) {
//        cout << "qrpoint==>>" << qrPointList[i] << endl;
//    }
    for (int i = 0; i < levelList.size(); i++) {
        cout << "level==>" << levelList[i][0] << "," << levelList[i][1] << "," << levelList[i][2] << endl;
        vector<Point> contoursList;
        contoursList = mergeContours(contours[indexx[levelList[i][0]]], contours[indexx[levelList[i][1]]],
                                     contours[indexx[levelList[i][2]]]);
        RotatedRect rect = minAreaRect(contoursList);
        Point2f p[4];
        rect.points(p);
        circle(img, p[0], 2, Scalar(0, 0, 255), 1);
        circle(img, p[1], 2, Scalar(0, 0, 255), 1);
        circle(img, p[2], 2, Scalar(0, 0, 255), 1);
        circle(img, p[3], 2, Scalar(0, 0, 255), 1);
        imshow("circle", img);
        waitKey();

        vector<Point> real_points{p[0], p[1], p[2], p[3]};
        Rect ROI = boundingRect(real_points);
        if (ROI.width > 2 * ROI.height) {
            ROI.width = ROI.height;
        } else if (ROI.width > ROI.height) {
            ROI.height = ROI.width;
        } else if (ROI.width < ROI.height) {
            ROI.width = ROI.height;
        }
        Mat roimat = img(ROI);
        imshow("roimat", roimat);
        waitKey();
        qrMatList.emplace_back(roimat);
    }
}

void QRcodeLocation::check_center(vector<vector<Point>> contours, vector<int> &index) {
    float dmin1 = 10000;
    float dmin2 = 10000;
    for (int i = 0; i < contours.size(); i++) {
        RotatedRect rect_i = minAreaRect(contours[i]);
        for (int j = i + 1; j < contours.size(); j++) {
            RotatedRect rect_j = minAreaRect(contours[j]);
            float d = PlaneGeometry::NodeDistance(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;
                }
            }
        }
    }
}


bool cmp_sort(int a, int b) {
    return a < b;//按照学号升序排列
}

/**
 * 判断是否有三个点可以围成等腰直角三角形
 * @param qrPointList
 * @return
 */
vector<vector<int>> QRcodeLocation::JudgeTriangle(vector<vector<Point>> qrcontourList, vector<int> indexx) {

    vector<vector<int>> levelList;
    vector<Point> pointList;
    if (qrcontourList.size() < 3) {
        return levelList;
    }
    for (int i = 0; i < qrcontourList.size(); i++) {
        Point pt = ContourCenter(qrcontourList[i]);
        pointList.emplace_back(pt);
    }
    for (int i = 0; i < indexx.size(); i++) {
        for (int j = i + 1; j < indexx.size(); j++) {
            for (int k = j + 1; k < indexx.size(); k++) {
                int distance1 = (int) PlaneGeometry::NodeDistance(pointList[i], pointList[j]);
                int distance2 = (int) PlaneGeometry::NodeDistance(pointList[i], pointList[k]);
                int distance3 = (int) PlaneGeometry::NodeDistance(pointList[j], pointList[k]);
                vector<int> distanceList{distance1, distance2, distance3};
                sort(distanceList.begin(), distanceList.end(), cmp_sort);
                int idx = abs(distanceList[1] - distanceList[0]);
//                cout << "abs(distanceList[1] - distanceList[0])==>" << abs(distanceList[1] - distanceList[0]) << endl;
                if (idx < 10) {
                    if (abs(sqrtf(pow(distanceList[0], 2) + pow(distanceList[1], 2))) - distanceList[2] < 15) {
                        cout << "distance1==" << distance1 << ",distance2==" << distance2 << ",distance3==" << distance3
                             << endl;
                        cout << "abs(distanceList[1] - distanceList[0])==>" << abs(distanceList[1] - distanceList[0])
                             << endl;
                        cout << "i,j,k==" << i << "," << j << "," << k << endl;
                        vector<int> level{i, j, k};
                        levelList.emplace_back(level);
                    }
                }
            }

        }
    }

    return levelList;
}

/**
 * 合并拼接三个矩形的轮廓
 * @param pt1
 * @param pt2
 * @param pt3
 * @return
 */
vector<Point> QRcodeLocation::mergeContours(vector<Point> &pt1, vector<Point> &pt2, vector<Point> &pt3) {

    vector<Point> contoursList;
    contoursList.insert(contoursList.end(), pt1.begin(), pt1.end());
    contoursList.insert(contoursList.end(), pt2.begin(), pt2.end());
    contoursList.insert(contoursList.end(), pt3.begin(), pt3.end());
    return contoursList;
}


/**
 * 判断三层轮廓的中心点间距是否够小
 * @param pt1
 * @param pt2
 * @param pt3
 * @return
 */
bool QRcodeLocation::CheckRec(Point pt1, Point pt2, Point pt3) {
    int distance1 = (int) PlaneGeometry::NodeDistance(pt1, pt2);
    int distance2 = (int) PlaneGeometry::NodeDistance(pt1, pt3);
    int distance3 = (int) PlaneGeometry::NodeDistance(pt2, pt3);
    int sum = (distance1 + distance2 + distance3) / 5;
    return sum < 5;
}

/**
 * 计算轮廓中心点
 * @param contour
 * @return
 */
Point QRcodeLocation::ContourCenter(vector<Point> &contour) {
    Moments mu;
    Point mc;
    mu = moments(contour, false);
    mc = Point2d(mu.m10 / mu.m00, mu.m01 / mu.m00);
    return mc;
}

/**
 * 计算面积的比值
 * @param contour1
 * @param contour2
 * @return
 */

double QRcodeLocation::AreaRate(vector<Point> &contour1, vector<Point> &contour2) {

    double area1 = contourArea(contour1, false);
    double area2 = contourArea(contour2, false);
    if (area1 == 0 || area2 == 0) {
        return 0;
    }
    double ratio = area1 * 1.0 / area2;
    ratio = int(ratio * 10);
    return ratio;
}

 

//
// Created by leoxae on 19-10-18.
//

#ifndef KEEKOAIROBOT_QRCODELOCATION_H
#define KEEKOAIROBOT_QRCODELOCATION_H
#include "../../globals.h"
using namespace std;
using namespace cv;

class QRcodeLocation{

private:
    vector<vector<int>> JudgeTriangle(vector<vector<Point>> contourpointList,vector<int> indexx);

    bool CheckRec(Point pt1, Point pt2, Point pt3);

    Point ContourCenter(vector<Point> &contour);

    double AreaRate(vector<Point> &contour1, vector<Point> &contour2);

    vector<Point> mergeContours(vector<Point> &pt1, vector <Point> &pt2, vector <Point> &pt3);

public:
    vector<Mat> FindQRcode(Mat img);

    void check_center(vector<vector<Point>> contours, vector<int> &index);
};


#endif //KEEKOAIROBOT_QRCODELOCATION_H

 

上一篇:OpenCV 学习笔记(14)为轮廓创建边界旋转框和椭圆


下一篇:OpenCV-Python开发指南(25)---矩特征