#include #include #include #include "Eigen/Dense" #include using namespace cv; Mat cameraIntrinsics = (Mat_(3, 3) << 1.118687327324564e+03, 0.0, 0.0, 0, 1.135263811351046e+03, 0.0, 703.25397, 482.50630, 1.0); std::vector center(std::vector> contours) { std::vector mu(contours.size()); for (int i = 0; i < contours.size(); ++i) { mu[i] = moments(contours[i], false); } std::vector mc(contours.size()); for (int j = 0; j < contours.size(); ++j) { mc[j] = Point2f(mu[j].m10 / mu[j].m00, mu[j].m01 / mu[j].m00); } return mc; } /* * p0---p1 * / * / * / * p2---p3 * * */ void sortPointsForPerspective(std::vector &corners) { for (int i = 0; i < 4; ++i) { for (int j = i; j > 0; j--) { if (corners[j].x < corners[j - 1].x) swap(corners[j], corners[j - 1]); else break; } } if (corners[0].y > corners[1].y) { swap(corners[0], corners[1]); } if (corners[2].y > corners[3].y) { swap(corners[2], corners[3]); } swap(corners[1], corners[2]); } Mat imgPreProcessing(const Mat &img) { // Mat img1; // medianBlur(img,img1,3); Mat imgGray; cvtColor(img, imgGray, COLOR_BGR2GRAY); // 转灰度图 Mat imgBinary; double thresh = 50; threshold(imgGray, imgBinary, thresh, 255, THRESH_OTSU | THRESH_BINARY); // 转二值图 return imgBinary; } Mat imgFindQr(const Mat &imgBinary, Mat img) { std::vector hierarchy; std::vector> contours; findContours(imgBinary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE); // 轮廓 std::vector mc = center(contours); std::vector blockConfid; // 信任特征块序号 for (int i = 0; i < contours.size(); ++i) { const double minMidArea = 100; //中间块最小面积 const double maxMidArea = pow(min(img.rows, img.cols), 2) * 25 / 441;//中间块最大面积 int firstChild = hierarchy[i][2]; //子块 int parent = hierarchy[i][3]; //父块 if (firstChild < 0 || parent < 0) continue; //筛选掉无父子的轮廓 int uncle0 = hierarchy[parent][0]; int uncle1 = hierarchy[parent][1]; int grand = hierarchy[parent][3]; if ((uncle0 < 0 && uncle1 < 0) || grand < 0)continue; //筛选掉独立轮廓 double area = contourArea(contours[i]); if (area < minMidArea || maxMidArea < area) continue; //面积筛选掉面积过大过小轮廓 double ratio1 = contourArea(contours[parent]) / area, ratio2 = area / contourArea(contours[firstChild]); std::vector centroidVec{mc[i].x, mc[i].y, 1.0, mc[parent].x, mc[parent].y, 1.0, mc[firstChild].x, mc[firstChild].y, 1.0}; Eigen::Map> centroid(centroidVec.data(), 3, 3); if (34.0 / 25.0 <= ratio1 && ratio1 <= 64.0 / 25.0 //面积比例 外/中 = 49/25 && 16.0 / 9.0 <= ratio2 && ratio2 <= 34.0 / 9.0 // 面积比例 中/内 = 25/9 && abs(centroid.determinant()) <= 1) {//三中心三角形面积 < 1 blockConfid.emplace_back(firstChild, i, parent, grand); } } int outLabelTemp = -1; std::vector outLabel; for (auto &i : blockConfid) { // 挑选共同外框 int outLabelNow = i[3]; if (outLabelNow != outLabelTemp) { outLabel.push_back(outLabelNow); outLabelTemp = outLabelNow; } } int outAll[outLabel.size()][4]; for (int i = 0; i < outLabel.size(); ++i) { outAll[i][0] = outLabel[i]; } int num[outLabel.size()]; memset(num, 0, sizeof(num)); for (auto &i : blockConfid) { for (int j = 0; j < outLabel.size(); ++j) { if (i[3] == outLabel[j]) { outAll[j][num[j] + 1] = i[2]; num[j]++; break; } } } int num1 = 0; std::vector approx; std::vector> quaCorners; std::vector qrCodes; std::vector straight_qrcode; std::vector decoded_info; std::vector qrFrame(4); qrFrame[0] = Point2f(-20, -20); qrFrame[1] = Point2f(230, -20); qrFrame[2] = Point2f(-20, 230); qrFrame[3] = Point2f(230, 230); for (int i = 0; i < sizeof(outAll) / sizeof(outAll[0]); ++i) { Mat qrCode; approxPolyDP(contours[outAll[i][0]], approx, 3, true); putText(img, std::to_string(outAll[i][0]), contours[outAll[i][0]][0], FONT_HERSHEY_PLAIN, 2.0, Scalar(0, 0, 255), 2); drawContours(img, contours, outAll[i][0], Scalar(0, 0, 255), 1, 8); sortPointsForPerspective(approx); Mat perTran = getPerspectiveTransform(approx, qrFrame); std::cout << perTran << std::endl; warpPerspective(imgBinary, qrCode, perTran, Size(210, 210)); // std::string qrframe = "qrcode"; // qrframe.append(std::to_string(i + 1)); // imshow(qrframe, qrCode); quaCorners.push_back(approx); qrCodes.push_back(qrCode); } return img; } int main(int argc, char **argv) { // Mat img, res, imgBinary; // // img = imread("/home/ryoo/CLionProjects/QRcode/cameraOpen/qrcode.JPG"); // resize(img, img, Size(img.cols / 4, img.rows / 4), 0, 0, INTER_LINEAR); //// std::vector decoded_info; //// std::vector points; //// std::vector straight_qrcode; //// QRCodeDetector qrdetector =QRCodeDetector(); //// qrdetector.detectAndDecodeMulti(img,decoded_info,points,straight_qrcode); //// std::string name ="demo"; //// //// for (int i = 0; i < straight_qrcode.size(); ++i) { //// name.append(std::to_string(i+1)); //// imshow(name, straight_qrcode[i]); //// //// } //// waitKey(); // imgBinary = imgPreProcessing(img); // res = imgFindQr(imgBinary, img); // imshow("demo", img); // waitKey(); Mat image, res, imgBinary; VideoCapture cap; cap.open(1); if (!cap.isOpened()) return -1; cap.set(CAP_PROP_FRAME_WIDTH, 1280); cap.set(CAP_PROP_FRAME_HEIGHT, 720); std::cout<<"The Intrinsics of camera is "<> image;//等价于cap.read(frame) imgBinary = imgPreProcessing(image); res = imgFindQr(imgBinary, image); imshow("test", res); char c = waitKey(66); if (image.empty()) break; if (c == 27) break; } cap.release(); destroyAllWindows(); return 0; }