1. 程式人生 > >【基於特徵點的矯正和輪廓二維碼檢測】

【基於特徵點的矯正和輪廓二維碼檢測】

參考牧野大仙的實現過程,自己在其基礎上進行了相關改進。

二維碼的檢測過程一般要用到矯正過程,而矯正需要得到相關透視變換的變換矩陣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函式對查詢的輪廓進行覆蓋,這裡主要對父輪廓進行了查詢;

原圖:

矯正圖:

效果圖:查詢

參考部落格: https://www.cnblogs.com/skyfsm/p/7324346.html