OpenCV4二维码检测测试

opencv4集成了二维码检测功能测试一下

代码很简单:

#include 
#include

using namespace cv;
int main()

{
	//读取本地的一张图片便显示出来
	cv::Mat img = imread("45.jpg");
	cv::QRCodeDetector QRdetecter;
	std::vector list;
	cv::Mat  res;
	QRdetecter.detectAndDecode(img, list, res);

	for (int i = 0; i < list.size(); i++)
	{

		if (i == 3)
			line(img, list[i], list[0], Scalar(0, 255, 0), 2);
		else
			line(img, list[i], list[i + 1], Scalar(0, 255, 0), 2);

	}

	imshow("测试窗口", img);

	waitKey(0);
	return 0;
}

效果:

OpenCV4二维码检测测试_第1张图片

之前的二维码都是自己实现的功能,opencv4的简直又快又好。

自己实现:


#include 
#include 
#include 

using namespace cv;
using namespace std;
using namespace zbar;


Mat  GammaTransform(cv::Mat &image)
{

	Mat imageGamma;
	Mat dist;
	//灰度归一化
	image.convertTo(imageGamma, CV_64F, 1.0 / 255, 0);

	//伽马变换
	double gamma = 1.5;

	pow(imageGamma, gamma, dist);//dist 要与imageGamma有相同的数据类型

	dist.convertTo(dist, CV_8U, 255, 0);
	return dist;
}


int main(int argc, char* argv[])
{
	char fileNameString[100];
	char windowNameString[50];
	char resultFileNameSring[100];
	Mat srcImage, grayImage, blurImage, thresholdImage, gradientXImage, gradientYImage, gradientImage, morphImage;
	for (int fileCount = 1; fileCount < 8; fileCount++)
	{
		//读取图像
		srcImage = imread("67.jpg");
		if (srcImage.empty())
		{
			cout << "image file read error" << endl;

			return -1;
		}
		namedWindow("原图", WINDOW_NORMAL);
		imshow("原图", srcImage);

		srcImage = GammaTransform(srcImage);
		namedWindow("伽马", WINDOW_NORMAL);
		imshow("伽马", srcImage);
		//图像转换为灰度图像
		if (srcImage.channels() == 3)
		{
			cvtColor(srcImage, grayImage, COLOR_RGB2GRAY);
			namedWindow("灰度化", WINDOW_NORMAL);
			imshow("灰度化", grayImage);
		}
		else
		{
			grayImage = srcImage.clone();
		}
		blur(grayImage, blurImage, Size(5, 5));
		//模糊化以后进行阈值化,得到到对应的黑白二值化图像,二值化的阈值可以根据实际情况调整
		threshold(blurImage, thresholdImage, 210, 255, 8);
		bitwise_not(thresholdImage, thresholdImage);
		namedWindow("大津二值化", WINDOW_NORMAL);
		imshow("大津二值化", thresholdImage);
		//看看二值化图像
		//imshow(windowNameString,thresholdImage);
		//二值化以后的图像,条形码之间的黑白没有连接起来,就要进行形态学运算,消除缝隙,相当于小型的黑洞,选择闭运算
		//因为是长条之间的缝隙,所以需要选择宽度大于长度
		Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 3));
		morphologyEx(thresholdImage, morphImage, MORPH_CLOSE, kernel);
		//看看形态学操作以后的图像
		//imshow(windowNameString,morphImage);
		//现在要让条形码区域连接在一起,所以选择膨胀腐蚀,而且为了保持图形大小基本不变,应该使用相同次数的膨胀腐蚀
		//先腐蚀,让其他区域的亮的地方变少最好是消除,然后膨胀回来,消除干扰,迭代次数根据实际情况选择
		
		dilate(morphImage, morphImage, getStructuringElement(MORPH_RECT, Size(5, 5)), Point(-1, -1), 3);
		erode(morphImage, morphImage, getStructuringElement(MORPH_RECT, Size(3, 3)), Point(-1, -1), 4);
		namedWindow("形态学", WINDOW_NORMAL);
		imshow("形态学", morphImage);
		//看看形态学操作以后的图像
		//imshow(windowNameString,morphImage);
		vector>contours;
		vectorcontourArea;
		//接下来对目标轮廓进行查找,目标是为了计算图像面积
		findContours(morphImage, contours, RETR_CCOMP, CHAIN_APPROX_NONE);
		//计算轮廓的面积并且存放
		for (int i = 0; i < contours.size(); i++)
		{
			contourArea.push_back(cv::contourArea(contours[i]));
		}
		////找出面积最大的轮廓
		//double maxValue; Point maxLoc;
		//minMaxLoc(contourArea, NULL, &maxValue, NULL, &maxLoc);
		////计算面积最大的轮廓的最小的外包矩形
		//RotatedRect minRect = minAreaRect(contours[maxLoc.x]);

		int index = 0;
		if (!contours.empty())
		{

			for (std::vector >::iterator it = contours.begin(); it != contours.end();)
			{
				if (fabs(cv::contourArea(Mat(*it))) < morphImage.cols * morphImage.rows / 15 || fabs(cv::contourArea(Mat(*it))) > morphImage.cols * morphImage.rows *0.8)
				{
					it = contours.erase(it);
				}
				else
				{
					it++;
				}
			}
			for (std::vector >::iterator it = contours.begin(); it != contours.end();)
			{
				RotatedRect rr = minAreaRect(*it);
				float w = rr.size.width;
				float h = rr.size.height;
				//根据长宽比删选
				if (w >= h)
				{
					w = rr.size.height;
					h = rr.size.width;
				}
				if (w/h>1.2 || w/h <0.86)
				{
					it = contours.erase(it);
				}
				else
				{
					it++;
				}
			}
		
			if (!contours.empty())
			{
				Mat draw = Mat::zeros(morphImage.size(), CV_8UC3);
				Mat draw2 = Mat::zeros(morphImage.size(), CV_8UC1);
			
				drawContours(draw, contours,
					-1, // draw all contours
					Scalar(255, 0, 0), // in white
					-1, 8); // with a thickness of 2
				namedWindow("Contours 筛选", WINDOW_NORMAL);
				imshow("Contours 筛选", draw);
				drawContours(draw2, contours,
					-1, // draw all contours
					Scalar(255, 255, 255), // in white
					-1, 8); // with a thickness of 2
				namedWindow("Contours ", WINDOW_NORMAL);
				imshow("Contours", draw2);
				//https://blog.csdn.net/kakiebu/article/details/79114964
				//https://blog.csdn.net/mangobar/article/details/79711335
				//放射变换
				RotatedRect mr = minAreaRect(Mat(contours[0]));
				Mat DrawImg(draw2.size(), draw2.type(), Scalar(0));
				Point2f vectpoint[4];
				mr.points(vectpoint);
				for (int i = 0; i<4; i++)
				{
					line(DrawImg, vectpoint[i], vectpoint[(i + 1) % 4], Scalar(255, 0, 0), 2);
				}

				imshow("drawimg", DrawImg);
				//waitKey();
				float angle = 0.0;
				Size si = mr.size;
				if (mr.size.width <= mr.size.height)
				{
					angle = mr.angle + 90;
					int tm = si.width;
					si.width = si.height;
					si.height = tm;
					//swap(si.width, si.height);
				}
				else
				{
					angle = mr.angle;
				}
				Mat rotmat = getRotationMatrix2D(mr.center, angle, 1);
				Mat deal_img;
				warpAffine(srcImage, srcImage, rotmat, draw2.size(), INTER_CUBIC);
				warpAffine(draw2, deal_img, rotmat, draw2.size(), INTER_CUBIC);
				imshow("旋转矫正0", srcImage);
				imshow("旋转矫正", deal_img);

				if(deal_img.channels()==3)
					cvtColor(deal_img, deal_img, COLOR_BGR2GRAY);
				vector>contours2;
				//接下来对目标轮廓进行查找,目标是为了计算图像面积
				findContours(deal_img, contours2, RETR_EXTERNAL, CHAIN_APPROX_NONE);
				//计算轮廓的面积并且存放
				if (!contours2.empty())
				{
					Mat roi;
					for (std::vector >::iterator it = contours.begin(); it != contours.end();it++)
					{
						Rect rec = boundingRect(Mat(*it));
						roi = srcImage(rec);
						imshow("roi", roi);
					}

					ImageScanner scanner;
					scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);	
					Mat imageGray;
					cvtColor(roi, imageGray, COLOR_RGB2GRAY);
					int width = imageGray.cols;
					int height = imageGray.rows;
					uchar *raw = (uchar *)imageGray.data;
					Image imageZbar(width, height, "Y800", raw, width * height);
					scanner.scan(imageZbar); //扫描条码    
					Image::SymbolIterator symbol = imageZbar.symbol_begin();
					if (imageZbar.symbol_begin() == imageZbar.symbol_end())
					{
						cout << "查询条码失败,请检查图片!" << endl;
					}
					for (; symbol != imageZbar.symbol_end(); ++symbol)
					{
						cout << "类型:" << endl << symbol->get_type_name() << endl << endl;
						cout << "条码:" << endl << symbol->get_data() << endl << endl;
					}
					//imshow("Source Image", resultImage);
					waitKey();



				}
			
			}
		}

	}
	
	
	waitKey(0);
	getchar();
	return 1;
}

OpenCV4二维码检测测试_第2张图片

推荐一个自己实现的,可供学习:https://www.cnblogs.com/yuanchenhui/p/opencv_qr.html

你可能感兴趣的:(opencv)