OpenCV 检测二维码并定位

2022-05-07 09:15:53 浏览数 (1)

注意:该程序功能是检测二维码,不是识别,只是在图中定出二维码的位置即可

原图是这样:如果出现这张图片时,程序需要找到二维码

其余图片是这样:

程序步骤: 1.图片缩小 2.灰度化,直方图均衡化,对比度增强,滤波 3.otsu阈值分割 4.五次膨胀 5.轮廓查找,如果轮廓满足一下条件,认为可能为二维码区域,像素面积大于60,长短轴之比小于1.3 6.对疑似区域做判断,因为本实验二维码贴在大概中心位置,找到疑似轮廓的质心,判断质心是不是在图片长宽的三分之一到三分之二之间,如果是认为是二维码区域 7.对二维码区域画成蓝色

代码语言:javascript复制
#include <stdio.h>  
#include <opencv/highgui.h>  
#include <time.h>  
#include <opencv2/opencv.hpp>  
#include <opencv/cv.h>  
#include <iostream> 

using namespace std;  
using namespace cv; 

int main(int argc,char *argv[])  
{
	
	Mat srcImage;
	Mat resizeImage;
	Mat grayImage;
	Mat equalizeHistImage;
	Mat contrastandbrightImage;
	Mat sobelImage;
	Mat thresholdImage;
	Mat dilateImage;
	Mat areaImage;
	Mat ellipseImage;
	srcImage = imread("3.jpg");
	Size dsize = Size(srcImage.cols*0.3,srcImage.rows*0.3);
	resize(srcImage, resizeImage,dsize);
	cvtColor(resizeImage,grayImage,CV_BGR2GRAY);
	equalizeHist(grayImage,equalizeHistImage);
	亮度、对比度增强
	contrastandbrightImage= Mat::zeros( equalizeHistImage.size(), equalizeHistImage.type() ); 
	for(int y = 0; y < equalizeHistImage.rows; y   )  
	{  
		for(int x = 0; x <equalizeHistImage.cols; x   )  
		{  
			contrastandbrightImage.at<uchar>(y,x)= saturate_cast<uchar>(6*(equalizeHistImage.at<uchar>(y,x) ));  	
		} 
	} 
	blur(contrastandbrightImage,contrastandbrightImage,Size(3,3));  
	//Sobel(contrastandbrightImage, sobelImage, CV_8U, 0,1 ,1, 1, 0, BORDER_DEFAULT);
	threshold(contrastandbrightImage,thresholdImage, 0, 255, CV_THRESH_OTSU CV_THRESH_BINARY_INV);  
	Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));  
	//进行膨胀操作  
	dilate(thresholdImage, dilateImage, element);  
	dilate(dilateImage, dilateImage, element);
	dilate(dilateImage, dilateImage, element);  
	dilate(dilateImage, dilateImage, element);  
	dilate(dilateImage, dilateImage, element);  

	//dilateImage.copyTo(areaImage);
	//vector< vector< Point> > contours;  
	//findContours(areaImage,contours,CV_RETR_TREE,  CV_CHAIN_APPROX_NONE); 
	//vector<vector<Point> >::iterator itc= contours.begin();  
	//while (itc!=contours.end()) 
	//{  
	//	if( itc->size()<100)
	//	{  
	//		itc= contours.erase(itc);  
	//	}
	//   else
	//   {
	//	     itc;  
	//	}
	//}  
	//drawContours(areaImage, contours, -1, Scalar(255), CV_FILLED);

	//找轮廓 两步判断  一个是大小  一个是长短轴比比  认为面积比60大,长短轴比比1.3小的区域是二维码区域  再做下一步判断
	dilateImage.copyTo(ellipseImage);
	vector<vector<Point> > twocontours;
	vector<Vec4i>twohierarchy;
	findContours(ellipseImage,twocontours,twohierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE);  
	vector<Moments> mu(twocontours.size() );      
    vector<Point2f> mc( twocontours.size() );
	for(int k = 0; k < (int)twocontours.size(); k  )    //查找轮廓
	{
		if (int(twocontours.at(k).size()) <=60)//轮廓面积小于60的不处理
		{
			drawContours(ellipseImage, twocontours, k, Scalar(0), CV_FILLED);
		}
		else
		{
			RotatedRect rRect = fitEllipse(twocontours.at(k)); 
			double majorAxis = rRect.size.height > rRect.size.width ? rRect.size.height : rRect.size.width;
			double minorAxis = rRect.size.height > rRect.size.width ? rRect.size.width : rRect.size.height;
			float rate = majorAxis/minorAxis;
			if (rate<1.3)   //长短轴之比小于1.4的轮廓
			{
				//可能为二维码的区域,判断是否为二维码区域
				printf("%fn",rate);
				//求区域的质心
				mu[k] = moments( twocontours[k], false );   
				mc[k] = Point2d( mu[k].m10/mu[k].m00 , mu[k].m01/mu[k].m00 ); 
				//打印质心
				printf("x=%f,y=%fn",mc[k].x,mc[k].y);
				//打印图像的长宽
				printf("图像的长%d,图像的宽%dn",resizeImage.cols,resizeImage.rows);
				//画出质心
				Point center = Point(mc[k].x,mc[k].y);  
				int r = 10;    
				circle(resizeImage,center,r,Scalar(255,0,0));  
				//判断质心是不是在图像中间   三分之一 < 质心 < 三分之二
				if ((int)mc[k].x<(int)2*(resizeImage.cols/3)&&(int)mc[k].x>(int)(resizeImage.cols/3))
				{
					if ((int)mc[k].y<(int)2*(resizeImage.rows/3)&&(int)mc[k].y>(int)(resizeImage.rows/3))
					{
							drawContours(resizeImage, twocontours, k, Scalar(255,0,0), CV_FILLED);//把轮廓涂成蓝色
							printf("蓝色是二维码区域n");
					}
				}
			}
			else  //长短轴之比大于1.4的轮廓  不是二维码区域
			{
				drawContours(resizeImage, twocontours, k, Scalar(0,0,255), CV_FILLED);//把轮廓涂成红色
			}
		}
	}		
	imshow("缩小图",resizeImage);
	imshow("灰度图",grayImage);
	imshow("对比度和亮度增强",contrastandbrightImage);
	//imshow("soble检测",sobelImage);
	imshow("二值化结果",thresholdImage);
	imshow("膨胀",dilateImage);
	//imshow("删除小面积",areaImage);
	imshow("长短轴",ellipseImage);
	waitKey(0);
}

部分结果图:

无二维码图片的结果图:

0 人点赞