二维码识别的原理 您所在的位置:网站首页 扫码器是什么技术做的 二维码识别的原理

二维码识别的原理

2024-06-04 21:42| 来源: 网络整理| 查看: 265

二维码的特征定位和信息识别 背景介绍

视觉的方法可以用来估计位置和姿态。最容易想到的是在目标上布置多个容易识别的特征,这样使用opencv相机标定和、相机畸变矫正、轮廓提取、solvepnp来获取目标相对于相机的位姿。在实际使用中只要相机和目标一方是估计的,那就可以得到全局坐标。如果相机和靶标都在移动,那只能获取到相对坐标。但是受限于相机视角和景深,这样多个特征的识别虽然精度可以很高,但是范围却很小。

对于如何扩大范围,使用二维码是一个很好的思路。首先,二维码本身具有多个特征,单个二维码可以用来实现上述方法的功能。其次,二维码本身带有信息,如果二维码的布置事先已知,那么位置和姿态估计的范围将只受限于二维码的数量。

本文主要是二维码的特征识别和信息识别。

二维码的的生成

二维码是在一个网站上生成的,经过手机的测试,生成的二维码没有问题。http://www.liantu.com/,该网站是免费的,生成的图片及二维码各种参数可以自定义。 本文的测试图片有20张,是数字1到5,每个数字隔90度旋转各一张。

在这里插入图片描述

二维码的特征识别

二维码特征识别的思路是:第一步,寻找二维码的三个角的定位角点,需要对图片进行平滑滤波,二值化,寻找轮廓,筛选轮廓中有两个子轮廓的特征,从筛选后的轮廓中找到面积最接近的3个即是二维码的定位角点。第二步:判断3个角点处于什么位置,主要用来对图片进行透视校正(相机拍到的图片)或者仿射校正(对网站上生成的图片进行缩放拉伸旋转等操作后得到的图片)。需要判断三个角点围成的三角形的最大的角就是二维码左上角的点。然后根据这个角的两个边的角度差确定另外两个角点的左下和右上位置。第三步,根据这些特征识别二维码的范围。

具体的代码:

Mat src = imread( "pic\\456.jpg", 1 ); if(src.empty()) { fprintf(stderr, "Can not load image!\n"); return 0; } Mat src_all=src.clone(); //彩色图转灰度图 Mat src_gray; cvtColor( src, src_gray, CV_BGR2GRAY ); //对图像进行平滑处理 blur( src_gray, src_gray, Size(3,3) ); //使灰度图象直方图均衡化 equalizeHist( src_gray, src_gray ); namedWindow("src_gray"); imshow("src_gray",src_gray); //灰度图 //指定112阀值进行二值化 Mat threshold_output; threshold( src_gray, threshold_output, 112, 255, THRESH_BINARY );

#ifdef DEBUG namedWindow(“二值化后输出”); imshow(“二值化后输出”,threshold_output); //二值化后输出 #endif

//需要的变量定义 Scalar color = Scalar(1,1,255 ); vector contours,contours2; vector hierarchy; Mat drawing = Mat::zeros( src.size(), CV_8UC3 ); //Mat drawing2 = Mat::zeros( src.size(), CV_8UC3 ); Mat drawingAllContours = Mat::zeros( src.size(), CV_8UC3 ); //利用二值化输出寻找轮廓 findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CHAIN_APPROX_NONE, Point(0, 0) ); //寻找轮廓的方法 int tempindex1 = 0; int tempindex2 = 0; for(int i = 0;ia1]; vector out2Contours = contours[it->a2]; double lenth1 = arcLength(out1Contours,1); double lenth2 = arcLength(out2Contours,1); if(abs(lenth1/lenth2-2)>1) { it = vin.erase(it); } else { drawContours( drawing, contours, it->a1, CV_RGB(255,255,255) , CV_FILLED, 8); it++; } } //获取三个定位角的中心坐标 Point point[3]; int i = 0; vector pointthree; for(it = vin.begin(),i = 0;it != vin.end();i++,it++) { point[i] = Center_cal( contours, it->a1 ); pointthree.push_back(point[i]); } if(pointthree.size() angle1) { if(ccw3) { poly[1] = pointthree[1]; poly[3] = pointthree[0]; } else { poly[1] = pointthree[0]; poly[3] = pointthree[1]; } poly[0] = pointthree[2]; Point temp(pointthree[0].x + pointthree[1].x - pointthree[2].x , pointthree[0].y + pointthree[1].y - pointthree[2].y ); poly[2] = temp; } else if(angle2>angle1 && angle2>angle3) { if(ccw2) { poly[1] = pointthree[0]; poly[3] = pointthree[2]; } else { poly[1] = pointthree[2]; poly[3] = pointthree[0]; } poly[0] = pointthree[1]; Point temp(pointthree[0].x + pointthree[2].x - pointthree[1].x , pointthree[0].y + pointthree[2].y - pointthree[1].y ); poly[2] = temp; } else if(angle1>angle2 && angle1 > angle3) { if(ccw1) { poly[1] = pointthree[1]; poly[3] = pointthree[2]; } else { poly[1] = pointthree[2]; poly[3] = pointthree[1]; } poly[0] = pointthree[0]; Point temp(pointthree[1].x + pointthree[2].x - pointthree[0].x , pointthree[1].y + pointthree[2].y - pointthree[0].y ); poly[2] = temp; } CvPoint2D32f trans[4]; int temp = 50; trans[0] = Point2f(0+temp,0+temp); trans[1] = Point2f(0+temp,100+temp); trans[2] = Point2f(100+temp,100+temp); trans[3] = Point2f(100+temp,0+temp); //获取透视投影变换矩阵 CvMat *warp_mat = cvCreateMat(3, 3, CV_32FC1); cvGetPerspectiveTransform(poly, trans, warp_mat); //计算变换结果 IplImage ipl_img(src_all); IplImage *dst = cvCreateImage(cvSize(1000, 1000), 8, 3); cvWarpPerspective(&ipl_img,dst,warp_mat); //=========================================

#ifdef DEBUG namedWindow(“透视变换后的图”); cvShowImage(“透视变换后的图”,dst); //透视变换后的图

drawContours( drawingAllContours, contours, -1, CV_RGB(255,255,255) , 1, 8); namedWindow("DrawingAllContours"); imshow( "DrawingAllContours", drawingAllContours ); namedWindow(pathtemp); imshow(pathtemp , drawing ); //3个角点填充

#endif

//接下来要框出这整个二维码 Mat gray_all,threshold_output_all; vector contours_all; vector hierarchy_all; cvtColor( drawing, gray_all, CV_BGR2GRAY ); threshold( gray_all, threshold_output_all, 45, 255, THRESH_BINARY ); findContours( threshold_output_all, contours_all, hierarchy_all, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point(0, 0) );//RETR_EXTERNAL表示只寻找最外层轮廓 Point2f fourPoint2f[4]; //求最小包围矩形 RotatedRect rectPoint = minAreaRect(contours_all[0]); //将rectPoint变量中存储的坐标值放到 fourPoint的数组中 rectPoint.points(fourPoint2f); for (int i = 0; i < 4; i++) { line(src_all, fourPoint2f[i%4], fourPoint2f[(i + 1)%4], Scalar(20,21,237), 3); } namedWindow(pathtemp); imshow(pathtemp , src_all ); //截取二维码区域 CvSize size= cvSize(200,200);//区域大小 cvSetImageROI(dst,cvRect(0,0,size.width, size.height));//设置源图像ROI IplImage* pDest = cvCreateImage(size,dst->depth,dst->nChannels);//创建目标图像 cvCopy(dst,pDest); //复制图像 cvSaveImage("Roi.jpg",pDest);//保存目标图像 二维码的信息识别

二维码的信息识别使用的是zbar,一个开源的二维码识别库,经过测试,对图像进行平滑,灰度等处理后识别效率还是很高的。zbar的算法流程简介:http://blog.csdn.net/u013738531/article/details/54574262。

//对截取后的区域进行解码 Mat imageSource = cv::Mat(pDest); cvResetImageROI(pDest);//源图像用完后,清空ROI cvtColor( imageSource, imageSource, CV_BGR2GRAY ); //zbar需要输入灰度图像才能很好的识别 //Zbar二维码识别 ImageScanner scanner; scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1); int width1 = imageSource.cols; int height1 = imageSource.rows; uchar *raw = (uchar *)imageSource.data; Image imageZbar(width1, height1, "Y800", raw, width1 * height1); scanner.scan(imageZbar); //扫描条码 Image::SymbolIterator symbol = imageZbar.symbol_begin(); if(imageZbar.symbol_begin()==imageZbar.symbol_end()) { cout


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有