参考牧野大仙的实现过程,自己在其基础上进行了相关改进。
二维码的检测过程一般要用到矫正过程,而矫正需要得到相关透视变换的变换矩阵H;变换矩阵H则是由特征角点得到。具体如下:
#include<opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char*argv[]){
Mat imageSource = imread("123.PNG", 0);
Mat image;
imageSource.copyTo(image);
GaussianBlur(image, image, Size(3, 3), 0); //滤波
threshold(image, image, 100, 255, CV_THRESH_BINARY); //二值化
imshow("二值化", image);
Mat element = getStructuringElement(2, Size(7, 7)); //膨胀腐蚀核
//morphologyEx(image,image,MORPH_OPEN,element);
for (int i = 0;i<10;i++){
erode(image, image, element);
i++;
}
imshow("腐蚀s", image);
Mat image1;
erode(image, image1, element);
image1 = image - image1;
imshow("边界", image1);
//寻找直线 边界定位也可以用findContours实现
vector<Vec2f>lines;
HoughLines(image1, lines, 1, CV_PI / 150, 250, 0, 0);
Mat DrawLine = Mat::zeros(image1.size(), CV_8UC1);
for (int i = 0;i<lines.size();i++)
{
float rho = lines[i][0];
float theta = lines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000 * (-b));
pt1.y = cvRound(y0 + 1000 * a);
pt2.x = cvRound(x0 - 1000 * (-b));
pt2.y = cvRound(y0 - 1000 * a);
line(DrawLine, pt1, pt2, Scalar(255), 1, CV_AA);
}
imshow("直线", DrawLine);
Point2f P1[4];
Point2f P2[4];
vector<Point2f>corners;
goodFeaturesToTrack(DrawLine, corners, 4, 0.1, 10, Mat()); //角点检测
for (int i = 0;i<corners.size();i++)
{
circle(DrawLine, corners[i], 3, Scalar(255), 3);
P1[i] = corners[i];
}
imshow("交点", DrawLine);
int width = P1[1].x - P1[0].x;
int hight = P1[2].y - P1[0].y;
P2[0] = P1[0];
P2[1] = Point2f(P2[0].x + width, P2[0].y);
P2[2] = Point2f(P2[0].x, P2[1].y + hight);
P2[3] = Point2f(P2[1].x, P2[2].y);
Mat elementTransf;
elementTransf = getAffineTransform(P1, P2);
warpAffine(imageSource, imageSource, elementTransf, imageSource.size(), 1, 0, Scalar(255));
imshow("校正", imageSource);
namedWindow("Source Window", 0);
imshow("Source Window", imageSource);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// 阈值化检测边界
/// 寻找轮廓
bitwise_not(imageSource, imageSource);
Point2f p[4];
findContours(imageSource, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
vector<RotatedRect>minrect(contours.size());
Mat drawing = Mat::zeros(imageSource.size(), imageSource.type());
for (int i = 0;i < contours.size();i++) {
RotatedRect rec = minAreaRect(Mat(contours[i]));
rec.points(p);
for (int j = 0; j < 4; j++) {
line(imageSource, p[j],p[(j + 1) % 4], Scalar(255,244,55), 1, 8);
cout << p[j].x << " " <<p[j].y << endl;
}
}
imshow("drawing", imageSource);
waitKey();
return 0;
}
这里我们采用RotatedRect函数对查找的轮廓进行覆盖,这里主要对父轮廓进行了查找;
原图:
矫正图:
效果图:查找