参考了:Opencv+Zbar二维码识别(二维码校正)
之前发现OpenCV不能识别倾斜有角度的二维码,找到了这个"仿射变换"听起来好厉害的东西,这就是图形学吗,怕了怕了
试了一下,效果还行吧,角度只要不是旋转的太离谱都能给掰正回来
#include
using namespace std;
using namespace cv;
void main(int argc, char* argv[])
{
/*读取图像*/
cv::Mat imageSource = imread("test_x30.bmp");
cv::Mat image;
/*二值化*/
imageSource.copyTo(image);
GaussianBlur(image, image, Size(3, 3), 0); //滤波,然后工科狗条件反射的想到稳压镇流
threshold(image, image, 100, 255,THRESH_BINARY);//二值化
imshow("①图像二值化", image);
/*形态学变换*/
cv::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("②形态学变换", image);
/*边缘检测*/
cv::Mat image1;
Canny(image, image1, 100, 300, 3);
vector> contours;
vector hierarchy;
findContours(image1, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point());//RETR_EXTERNAL:只检测最外围轮廓/CHAIN_APPROX_NONE:保存物体边界上所有连续的轮廓点
imshow("③边缘检测", image1);
/*霍夫变换检测直线*/
vectorlines;
HoughLines(image1, lines, 1, CV_PI / 180, 100, 0, 0);
cv::Mat DrawLine = Mat::zeros(image1.size(), CV_8UC1);
imshow("④检测直线", DrawLine);
/*交点检测*/
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, 1);
}
Point2f P1[4];
Point2f P2[4];
vectorcorners;
goodFeaturesToTrack(DrawLine, corners, 4, 0.1, 10, Mat());
imshow("⑤交点定位", DrawLine);
/*仿射变换*/
for (int i = 0; i < corners.size(); i++)
{
circle(DrawLine, corners[i], 3, Scalar(255), 3);
P1[i] = corners[i];
}
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);
cv::Mat elementTransf;
elementTransf = getAffineTransform(P1, P2);
warpAffine(imageSource, imageSource, elementTransf, imageSource.size(), 1, 0, Scalar(255));
imshow("⑥变换校正", imageSource);
cv::QRCodeDetector QRdetecter;
std::vector list;
cv::Mat res;
string txt = QRdetecter.detectAndDecode(imageSource, list, res);//res:提取出的二维码;返回解码后的字符串
cout << txt << endl;
for (int i = 0; i < list.size(); i++)
{
if (i == 3)
line(imageSource, list[i], list[0], Scalar(0, 255, 0), 3);
else
line(imageSource, list[i], list[i + 1], Scalar(0, 255, 0), 3);
}
namedWindow("⑧提取二维码", 0);//可以拖动窗口大小
resizeWindow("⑧提取二维码", 500, 500);//设置窗口大小
moveWindow("⑧提取二维码", 1200, 500);//设置窗口位置
imshow("⑦二维码检测定位", imageSource);
imshow("⑧提取二维码", res);
waitKey();
}
先用一张歪了目测30度的测试
开运算应该是用来过滤去除背景的吧,不过测试图本就没有背景
霍夫变换,不明觉厉
仿射变换,牛逼啊V
OpenCV的detectAndDecode
再弄张10度的测一下
之前一张识别不出来的也能提取了
之前还想去看看C++下的什么zbar怎么用来着,结果这下只用OpneCV就实现了,啊这