// // 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