精华内容
下载资源
问答
  • 二维码定位

    万次阅读 2017-11-02 11:15:52
    使用opencv确定图片中二维码的位置

    使用opencv确定图片中二维码的位置

    背景

    确定二维码的位置并识别,有很多开源的例子,但是毕竟不是自己做的,还是想自己一步步学习一下,这里只做了一下工作:

    1.确定二维码在图片中的位置,输出其像素坐标。

    2.使用透视变换对识别的二维码矩形进行修正,方便之后的二维码识别(这里暂不做识别,有意的同学可以使用Zbar,zxing进行识别)。

    在opencv的学习上我还是一个小白,有些考虑不周的地方还请多多指教。

    流程图

    首先上一张二维码的示意图,这里用abcd指代小矩形,下文会用到。
    2

    下面是流程图
    img8

    实现

    对每一帧的图像的预处理详见附件,这里直接从Canny提取轮廓之后开始讲述

    1. 边缘检测–Canny
    Canny(blurImage, edgeTemp, canny_thread_min, canny_thread_max, 3);
    
    2. 提取轮廓–findContours (文末有备注)
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    //输入图像,轮廓(点向量形式),轮廓数量,轮廓检索模式,轮廓逼近 
    findContours(edgeTemp, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
    
    3. 绘制嵌套层次大于5的轮廓 (详情请点击此处了解hierarchy的含义)
    vector<int> vector_contours_filter;
    for (int k, c, i = 0; i < contours.size(); i++)
    {
    	k = i;
    	c = 0;
    	while (hierarchy[k][2] != -1)//表示不是最外面的轮廓
    	{
    		k = hierarchy[k][2];
    		c = c + 1;
    	}
    	if (c >= 5)
    	{
    		vector_contours_filter.push_back(i);
    	}
    }
    
    4. 利用abc三个小矩形的12个顶点做最小包围矩形
    //这里直接使用三个小矩形的12个顶点来绘制最小包围矩形
    Point2f point_minRect12[4];
    RotatedRect rect12 = minAreaRect(vertex_minRect4);	//vertex_minRect4 -> 装有abc三个小矩形的12个顶点的容器
    rect12.points(point_minRect12);//返回矩形的四个顶点给vertex  
    for (int j = 0; j < 4; j++)
    {
    	line(src1, point_minRect12[j], point_minRect12[(j + 1) % 4], Scalar(0, 0, 255), 3, 8);//非常巧妙的表达式
    }
    
    Point2f midPoint_rect;
    for (int j = 0; j < 4; j++)
    {
    	midPoint_rect.x += (point_minRect12[j].x / 4);
    	midPoint_rect.y += (point_minRect12[j].y / 4);
    }
    circle(src1, midPoint_rect, 10, Scalar(0, 255, 0), 3, 8);	//外接矩形的的中心
    imshow("结果图", src1);
    

    经过这次处理之后,基本上就只剩下abc三个小矩形了。一般情况下,利用这三个小矩形的各个顶点,绘制包围他们的最小矩形(约定包围整个二维码的最小矩形为矩形A),然后求得矩形A的中心点O,这样就得到了像素坐标下的二维码的位置。效果如下图所示:
    img3

    但是,偶尔会有这种特殊的情况发生
    img4img5

    ############### 这就很尴尬了。。。##################

    虽然这只是个别的情况,但也说明了只利用abc这三个小矩形来确定二维码的位置并不可靠。所以很有必要确定第四个小矩形d的位置,利用其把这个别情况下的二维码的最小包围矩形框纠正回来。

    5. 画出第四个小矩形d

    已知三个小矩形abc之后,第四个矩形d也就比较容易了。

    img6

    在第4步中的代码注释中提到vertex_minRect4是装有矩形abc总计12个顶点的容器,遍历这12个顶点,求两点之间的距离,找出距离最远的两个点,就是点a-1和c-3,然后利用求线段中点的公式,如下:

    midPoint.x = (P_1.x + P_2.x)/2;
    
    midPoint.y = (P_1.y + P_2.y)/2;
    

    来获取中点O的坐标,然后再分别求矩形b的四个点关于中点O的对称点的坐标,就是求线段中点的逆过程嘛。于是乎,矩形d的四个顶点我们就get到了。最后利用这四个矩形abcd的16个顶点,画它们的最小外接矩形,再通过矩形的四个顶点求取二维码的中点,

    到这里,二维码在图像中的位置就确定了,是像素坐标哦

    上述的那个特殊情况就不存在了Yeah!

    6. 提取二维码

    使用透视变换,将二维码投影到另一个平面,方便以后的识别

    1. 二维码的四个顶点的坐标:上一步利用abcd四个矩形的16个顶点做最小包围矩形时,可以获得矩形的四个顶点,数组vertexs_minRect_QR表示。

    2. 新的投影点的坐标:新的投影平面中,二维码的坐标可以自己定义,比如

    //lenth是二维码的变长
    Point2f vertex_warp[4];
    vertex_warp[0] = Point2f(0, float(lenth-1));
    vertex_warp[1] = Point2f(0, 0);
    vertex_warp[2] = Point2f(float(lenth-1), 0);
    vertex_warp[3] = Point2f(float(lenth-1), float(lenth));
    
    1. 求解透视变换的矩阵
      可以使用opencv库中的getPerspectiveTransform函数获得
    //! returns 3x3 perspective transformation for the corresponding 4 point pairs.
    CV_EXPORTS Mat getPerspectiveTransform( const Point2f src[], const Point2f dst[] );
    

    操作代码如下,由此获得变换矩阵transform

    Mat transform = getPerspectiveTransform(vertexs_minRect_QR, vertex_warp);
    
    1. 透视变换的实现
      奉上透视变换的函数warpPerspective
    //! warps the image using perspective transformation
    CV_EXPORTS_W void warpPerspective( InputArray src, OutputArray dst,
                                       InputArray M, Size dsize,
                                       int flags=INTER_LINEAR,
                                       int borderMode=BORDER_CONSTANT,
                                       const Scalar& borderValue=Scalar());
    

    实现

    warpPerspective(src, dst, transform, Size(lenth, lenth)); 
    

    结果图
    img7
    左是识别的效果图,右上是使用透视变换投影到另一个平面的效果,右下是二维码中心在原图中的像素坐标

    备注:关于提取轮廓findContours函数的参数说明

    函数原型如下:

    //! retrieves contours and the hierarchical information from black-n-white image.
    CV_EXPORTS_W void findContours( InputOutputArray image, OutputArrayOfArrays contours,
                                  OutputArray hierarchy, int mode,
                                  int method, Point offset=Point());
    

    其中的参数mode有以下可供选择,在识别二维码中,只能使用CV_RETR_TREE

    RETR_EXTERNAL=CV_RETR_EXTERNAL, //!< retrieve only the most external (top-level) contours
    RETR_LIST=CV_RETR_LIST, //!< retrieve all the contours without any hierarchical information
    RETR_CCOMP=CV_RETR_CCOMP, //!< retrieve the connected components (that can possibly be nested)
    RETR_TREE=CV_RETR_TREE, //!< retrieve all the contours and the whole hierarchy
    RETR_FLOODFILL=CV_RETR_FLOODFILL
    

    详情请点击此处了解
    最后附上支付宝红包二维码,欢迎客官扫一扫~
    在这里插入图片描述

    展开全文
  • opencv 二维码定位

    千次阅读 多人点赞 2018-11-24 14:11:26
    最近师兄跟我提到我二维码定位,参考了许多大佬的程序,写了这个小程序 目的: 用opencv的库实现QRcode定位 环境: Windows 10 VS2015 opencv3.4.0 基本原理 下图为二维码的其中一个黑色正方形,二维码...

    最近师兄跟我提到我二维码定位,参考了许多大佬的程序,写了这个小程序

    目的:

    用opencv的库实现QRcode定位

    环境:

    • Windows 10
    • VS2015
    • opencv3.4.0

    基本原理
    下图为二维码的其中一个黑色正方形,二维码定位主要是根据这个正方形的位置进行定位识别
    在这里插入图片描述这个正方形提供了两个特征:

    • 该正方形有三个轮廓特征,因此我们可以找到一个符合该特征的轮廓,便可以节省许多操作。如一个父轮廓内含有两个子轮廓。因此我们需要建立轮廓等级hierarchy
    • 该正方形的黑白比例为1:1:3:1:1。

    下面我介绍一下RotatedRect类的angle参数:
    在这里插入图片描述这幅图是我认为最符合RotatedRect类的angle的描述。我的程序需要将黑色正方形旋转回正,因此需要了解这个angle 、width和heigh。
    各算法输出图像
    1.滤波、直方图均值化、二值化
    在这里插入图片描述
    这张图的三个黑色框非常明显

    2.识别位置、填充、连通三个区域
    在这里插入图片描述

    3.将图片找轮廓 找出最小包围矩形,即可框出大致二维码位置
    在这里插入图片描述
    在这里插入图片描述

    代码实现

    
    #include "opencv2/opencv.hpp"
    
    using namespace cv;
    using namespace std;
    
    Mat transformCorner(Mat src, RotatedRect rect);
    bool isCorner(Mat &image);
    double Rate(Mat &count);
    int main()
    {
    	Mat src = imread("QRcode.jpg");
    	if (!src.data)
    		return -1;
    	double start = (double)getTickCount();
    	Mat srcGray, canvas;            //canvas为画布 将找到的定位特征画出来
    	Mat canvasGray;	
    	//pyrDown(src, src);  //图片过大时使用
    	canvas = Mat::zeros(src.size(), CV_8UC3);
    
    	/*灰度滤波直方图均值化 提高对比度*/
    	cvtColor(src, srcGray, COLOR_BGR2GRAY);
    	blur(srcGray, srcGray, Size(3, 3));
    	equalizeHist(srcGray, srcGray);
    
    	/*阈值根据实际情况 如视图中已找不到特征 可适量调整*/
    	threshold(srcGray, srcGray, 50, 255, THRESH_BINARY);
    	imshow("threshold", srcGray);
    
    	/*contours是第一次寻找轮廓*/
    	/*contours2是筛选出的轮廓*/
    	vector<vector<Point>> contours, contours2;
    	vector<Vec4i> hierarchy;
    	findContours(srcGray, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
    	int ic = 0;
    	int parentIdx = -1;
    
    	/*个人认为: 下面程序为寻找出有两个子轮廓的父轮廓*/
    	/*挺好用的 几乎筛选出来了*/
    	for (int i = 0; i < contours.size(); i++)
    	{
    		if (hierarchy[i][2] != -1 && ic == 0)
    		{
    			parentIdx = i;
    			ic++;
    		}
    		else if (hierarchy[i][2] != -1)
    		{
    			ic++;
    		}
    		else if (hierarchy[i][2] == -1)
    		{
    			parentIdx = -1;
    			ic = 0;
    		}
    		if (ic >= 2)
    		{
    			contours2.push_back(contours[parentIdx]);
    			//drawContours(canvas, contours, parentIdx, Scalar(0, 0, 255), 1, 8);
    			ic = 0;
    			parentIdx = -1;
    		}
    	}
    
    
    	vector<Point> center_all;  //center_all获取特性中心
    	for (int i = 0; i < contours2.size(); i++)
    	{
    		//drawContours(canvas, contours, i, Scalar(0, 255, 0), 2);
    		double area = contourArea(contours2[i]);
    		if (area < 100)
    			continue;
    		/*控制高宽比*/
    		RotatedRect rect = minAreaRect(Mat(contours2[i]));
    		double w = rect.size.width;
    		double h = rect.size.height;
    		double rate = min(w, h) / max(w, h);
    		if (rate > 0.85)   
    		{
    			Mat image = transformCorner(src, rect); //返回旋转后的图片
    			if (isCorner(image))
    			{
    				Point2f points[4];
    				rect.points(points);
    				for (int i = 0; i < 4; i++)
    					line(src, points[i], points[(i + 1) % 4], Scalar(0, 255, 0), 2);
    				drawContours(canvas, contours2, i, Scalar(0, 0, 255), -1);
    				center_all.push_back(rect.center);
    			}
    		}
    	}
    	/*连接三个黑色正方形区域,将其变成一个轮廓,即可用最小矩形框选*/
    	for (int i = 0; i < center_all.size(); i++)
    	{
    		line(canvas, center_all[i], center_all[(i+1) % center_all.size()], Scalar(255, 0, 0),3);
    	}
    	vector<vector<Point>> contours3;
    	cvtColor(canvas, canvasGray, COLOR_BGR2GRAY);
    	findContours(canvasGray, contours3, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    
    	/*原程序是没有这个设置 因此但输入图片无二维码时容易报错*/
    	for (int i = 0; i < contours3.size(); i++)
    	{
    		RotatedRect rect = minAreaRect(contours3[i]);
    		Point2f boxpoint[4];
    		rect.points(boxpoint);
    		for (int i = 0; i < 4; i++)
    			line(src, boxpoint[i], boxpoint[(i + 1) % 4], Scalar(0, 0, 255), 3);
    
    	}
    
    	imshow("src", src);
    	imshow("canvas", canvas);
    	//imshow("srcGray", srcGray);
    	double	time = ((double)getTickCount() - start) / getTickFrequency();
    	cout << "time:"<< time<< endl;
    	waitKey(0);
    	return 0;
    }
    /******************************************************************
    	该变换是假设照片是在一个平面且垂直与摄像头
    	(即二维码没有仿射或投影 仅仅是平移和旋转)
    *******************************************************************/
    Mat transformCorner(Mat src, RotatedRect rect)
    {
    	Point center = rect.center;   //旋转中心
    	//circle(src, center, 2, Scalar(0, 0, 255), 2);
    	//Size sz = Size(rect.size.width, rect.size.height);
    	Point TopLeft = Point(cvRound(center.x),cvRound(center.y)) - Point(rect.size.height/2,rect.size.width/2);  //旋转后的目标位置
    	TopLeft.x = TopLeft.x > src.cols ? src.cols : TopLeft.x;
    	TopLeft.x = TopLeft.x < 0 ? 0 : TopLeft.x;
    	TopLeft.y = TopLeft.y > src.rows ? src.rows : TopLeft.y;
    	TopLeft.y = TopLeft.y < 0 ? 0 : TopLeft.y;
    
    	//Point ButtonRight = (Point)center - Point(rect.size.width, rect.size.height);
    	Rect RoiRect = Rect(TopLeft.x, TopLeft.y, rect.size.width, rect.size.height);   //抠图必备矩形
    	double angle = rect.angle;        //旋转角度
    	Mat mask,roi,dst;                //dst是被旋转的图片 roi为输出图片 mask为掩模
    	Mat image;						 //被旋转后的图片
    	Size sz = src.size();             //旋转后的尺寸
    	mask = Mat::zeros(src.size(), CV_8U);
    
    	/************************************
    	为掩模上色 一般为白色
    	因为RotatedRect 类型的矩形不容易调取内像素 (主要是我不太懂)
    	因此我把矩形的四个顶点当成轮廓 再用drawContours填充
    	************************************/
    	vector<Point> contour;
    	Point2f points[4];
    	rect.points(points);
    	for (int i = 0; i < 4; i++)
    		contour.push_back(points[i]);
    	vector<vector<Point>> contours;
    	contours.push_back(contour);
    	drawContours(mask, contours, 0, Scalar(1), -1);
    
    	/*抠图,然后围绕中心矩阵中心旋转*/
    	src.copyTo(dst, mask);
    	//roi = dst(RoiRect);
    	Mat M = getRotationMatrix2D(center, angle, 1);
    	warpAffine(dst, image, M, sz);
    	roi = image(RoiRect);
    
    	//imshow("image", image);
    	return roi;
    }
    
    /***************判断输入图像的最底层轮廓是否有特征*********************/
    bool isCorner(Mat &image)
    {
    	/*******dstCopy作用是防止findContours修改dstGray*******/
    	/*******dstGray后面还需要抠图**************************/
    	Mat mask,dstGopy;
    	Mat dstGray;
    	mask = image.clone();
    	cvtColor(image, dstGray, COLOR_BGR2GRAY);
    	threshold(dstGray, dstGray, 100, 255, THRESH_BINARY_INV);  //阈值根据情况而定
    	dstGopy = dstGray.clone();  //备份
    	vector<vector<Point>> contours;
    	vector<Vec4i> hierarchy;
    	findContours(dstGopy, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
    	for (int i = 0; i < contours.size(); i++)
    	{
    		//cout << i << endl;
    		if (hierarchy[i][2] == -1 && hierarchy[i][3])
    		{
    			Rect rect = boundingRect(Mat(contours[i]));
    			rectangle(image, rect, Scalar(0, 0, 255), 2);
    			/******************由图可知最里面的矩形宽度占总宽的3/7***********************/
    			if (rect.width < mask.cols*2/ 7)      //2/7是为了防止一些微小的仿射
    				continue;
    			if (Rate(dstGray(rect)) > 0.75)       //0.75是我测试几张图片的经验值 可根据情况设置(测试数量并不多)
    			{
    				rectangle(mask, rect, Scalar(0, 0, 255), 2);
    				return true;
    			}
    		}
    	}
    	//imshow("dstGray", image);
    	//imshow("mask", dstGray);
    	return  false;
    }
    
    
    /********统计像素点*****/
    double Rate(Mat &count)
    {
    	int number = 0;
    	int allpixel = 0;
    	for (int row = 0; row < count.rows; row++)
    	{
    		for (int col = 0; col < count.cols; col++)
    		{
    			if (count.at<uchar>(row, col) == 255)
    			{
    				number++;
    			}
    			allpixel++;
    		}
    	}
    	cout << (double)number / allpixel  << endl;
    	return (double)number / allpixel;
    }
    

    总的来说,这份程序还是很多多余步骤,主要是功底不足,如有BUG,欢迎在评论区提出,一起讨论学习!

    参考借鉴文档
    图片参考网址和部分代码
    https://blog.csdn.net/jia20003/article/details/77348170
    轮廓判断程序最后的框选二维码程序参考网址https://blog.csdn.net/guanyonglai/article/details/59644437
    RotatedRect angle width heigh位置参考网址
    https://blog.csdn.net/u011765923/article/details/82708171
    这几篇文章给了我一些灵感,可以参考一下

    展开全文
  • # opencv二维码定位图案检测(c++) 通过二维码回字形定位图案三层轮廓1:1:3:1:1的结构,识别出其位置并用绿色方框框出。
  • 二维码定位符识别

    2016-08-15 17:34:02
    识别二维码定位符位置。可以用来标记平面运动物体,然后相机拍摄跟踪位置。抗干扰能力max,主要识别程序从zxing源码中改编过来的,在FinderPattern finderPatternFinder俩个类中。使用方法很简单,在Detector::...
  • 基于Vs2013写的整个工程, OPenCV和Zbar的配置都是用属性表实现的,再属性表里更换自己的本机路径,工程就可以正常运行。...基于Zbar实现条形码和二维码定位识别,识别率比opencv4.1.2里面的QRCodeDetector高
  • 基于微信小程序的二维码定位签到平台建设.pdf
  • 高速公路二维码定位报警系统 高速公路正朝着智能化方向发展,已经逐步形成“高速公路智慧化”的科技理念。智慧高速公路提出了互联网+的概念,针对传统高速公路系统和管理服务进行重新构造,提升高速公路运营管理水平...

    高速公路二维码定位报警系统

    高速公路正朝着智能化方向发展,已经逐步形成“高速公路智慧化”的科技理念。智慧高速公路提出了互联网+的概念,针对传统高速公路系统和管理服务进行重新构造,提升高速公路运营管理水平与出行服务质量,实现高速公路监控管理、快速响应、资源优配、出行指引等服务的信息智能化。
    源中瑞二维码定位报警系统,应用在高速公路,只需扫描二维码即可进行报警,解决传统高速报警效率低下的问题。
    传统高速公路报警存在的三大问题:
    一、报警流程环节多。
    据调查辖区高速公路发生交通事故后大约有82%报警人选择拨打110,然后110根据报警人提供的位置,通知指挥中心处报警,指挥中心再通知所属中队出警。
    二、事故发生后报警人不确定具体位置。
    在高速公路上发生事故需要报警时,司机往往不能快速地说出具体位置,往往就耽误了接警和救援的效率。从而导致交警或救护人员难以第一时间赶到现场救援。这个时候如果使用上我们二维码定位报警系统,只需要通过微信扫描护栏上的二维码,便可准确掌握自己所处位置,在报警或求助时,民警或者救护人员能够及时到达,防止二次事故的发生。
    在这里插入图片描述

    三、看不懂辅助标识
    在高速公路上有许多辅助标识,例如百里桩、G、S的标志等,在与交警电话沟通时
    ,并不理解辅助标识的意思,从而导致救援时间的耽搁。
    通过二维码定位报警系统的“一键报警”,能极大的增加报警效率,降低高速公路次生事故发生率。同时通过扫描二维码通知到交警指挥中心后台,指挥中心第一时间会根据当时的现场提供一些相关的注意事项和应急处理措施。在这里插入图片描述

    二维码定位报警系统运用大数据,物联网,互联网等技术,二维码定位报警不只是用在高速公路上,也是可以用在居民道路、娱乐会所、交通事故、交通堵塞、盗窃、诈骗、人员走失、噪音扰民、违法犯罪、移车服务、政府指引、其他报警等。源中瑞二维码定位报警系统始终以人民安全为中心,方便快捷解决民众所需,保障民众出行。在这里插入图片描述

    展开全文
  • 识别二维码定位符位置。可以用来标记平面运动物体,然后相机拍摄跟踪位置。抗干扰能力max,主要识别程序从zxing源码中改编过来的,在FinderPattern finderPatternFinder俩个类中。使用方法很简单,在Detector::...
  • OpenCV 二维码定位与识别

    千次阅读 2019-12-17 10:48:22
    但常常会因为二维码图像污点、光照不均匀以及二维码图像倾斜等原因,使得二维码的识别正确率低,针对这些问题,通过学习贾老师OpenCV课程以及其他博主的经验[作者仟人斩],实现了基于OpenCV的二维码定位与识别,但仍...

    因为二维码本身含有信息,因此可以作为产品的信息载体,如:产品特征。在工业领域常用在产品入库、分拣和包装上。但常常会因为二维码图像污点、光照不均匀以及二维码图像倾斜等原因,使得二维码的识别正确率低,针对这些问题,通过学习贾老师OpenCV课程以及其他博主的经验[作者仟人斩],实现了基于OpenCV的二维码定位与识别,但仍有一些问题需要进一步改进,如:背景复杂的情况下,应该采用“1 : 1:3 : 1:1”的特点,进一步判断三个定位角的位置。
    在这里插入图片描述
    1、步骤

    1. 通过灰度化、滤波、直方图均衡化、图像增强等操作预处理图像;
    2. 利用二维码 “ 回 ”形定位角定位二维码位置;
    3. 找到规则二维码的左上角点为透视变换的起点,和其他三个点;
    4. 构造变换后的点,透视变换,一一对应,获取规则的二维码图像;
    5. 使用Zbar工具进行二维码识别。

    2、代码实现
    使用findContours函数中的hierarchy参数获取“回”形定位角点,然后基于左上角位于直角的特点定位到该点,因为相机相对于二维码平面可能不是垂直关系,因此使用透视变换,而不是仿射变换。

    Mat imageContours = Mat::ones(img.size(), CV_8UC1); //最小外接矩形画布
    	vector<vector<Point>>contours, conts;
    	vector<Vec4i>hierarchy;
    
    	findContours(img, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE, Point());
    
    	int flag = 0, c = 0;
    	for (int i = 0; i < contours.size(); i++)
    	{
    		if (hierarchy[i][2] != -1 && flag == 0)
    		{
    			flag++;
    			c = i;
    
    		}
    
    		else if (hierarchy[i][2] == -1)
    		{
    			flag = 0;
    		}
    
    		else if (hierarchy[i][2] != -1)
    		{
    			flag++;
    		}
    
    		if (flag >= 2)
    		{
    			flag = 0;
    			conts.push_back(contours[c]);
    		}
    	}
    
    	int count = conts.size();
    	cout << count << endl;
    	vector<Point> pointthree;
    	for (int i = 0; i < count; i++) {
    		RotatedRect rect = minAreaRect(conts[i]);
    		
    		Point2f P[4];
    		rect.points(P);
    //		circle(imageContours, P[1], 6, (255), 1, 8);
    		for (int j = 0; j <= 3; j++)
    		{
    			line(imageContours, P[j], P[(j + 1) % 4], Scalar(255), 2);
    			
    		}
    		imshow("MinAreaRect", imageContours);
    
    		pointthree.push_back(rect.center);
    	}
    	//找到角度最大的点
    	double ca[2];
    	double cb[2];
    	
    
    
    
    	ca[0] = pointthree[1].x - pointthree[0].x;
    	ca[1] = pointthree[1].y - pointthree[0].y;
    	cb[0] = pointthree[2].x - pointthree[0].x;
    	cb[1] = pointthree[2].y - pointthree[0].y;
    	double angle1 = 180 / 3.1415*acos((ca[0] * cb[0] + ca[1] * cb[1]) / (sqrt(ca[0] * ca[0] + ca[1] * ca[1])*sqrt(cb[0] * cb[0] + cb[1] * cb[1])));
    	double ccw1;
    	if (ca[0] * cb[1] - ca[1] * cb[0] > 0) ccw1 = 0;
    	else ccw1 = 1;
    
    	ca[0] = pointthree[0].x - pointthree[1].x;
    	ca[1] = pointthree[0].y - pointthree[1].y;
    	cb[0] = pointthree[2].x - pointthree[1].x;
    	cb[1] = pointthree[2].y - pointthree[1].y;
    	double angle2 = 180 / 3.1415*acos((ca[0] * cb[0] + ca[1] * cb[1]) / (sqrt(ca[0] * ca[0] + ca[1] * ca[1])*sqrt(cb[0] * cb[0] + cb[1] * cb[1])));
    	cout << sqrt(ca[0] * ca[0] + ca[1] * ca[1]) << endl;
    	cout << sqrt(cb[0] * cb[0] + cb[1] * cb[1]) << endl;
    
    	double ccw2;
    	if (ca[0] * cb[1] - ca[1] * cb[0] > 0) ccw2 = 0;
    	else ccw2 = 1;
    
    	ca[0] = pointthree[1].x - pointthree[2].x;
    	ca[1] = pointthree[1].y - pointthree[2].y;
    	cb[0] = pointthree[0].x - pointthree[2].x;
    	cb[1] = pointthree[0].y - pointthree[2].y;
    	double angle3 = 180 / 3.1415*acos((ca[0] * cb[0] + ca[1] * cb[1]) / (sqrt(ca[0] * ca[0] + ca[1] * ca[1])*sqrt(cb[0] * cb[0] + cb[1] * cb[1])));
    	double ccw3;
    	if (ca[0] * cb[1] - ca[1] * cb[0] > 0) ccw3 = 0;
    	else ccw3 = 1;
    
    	vector<Point2f> poly(4);
    	if (angle3>angle2 && angle3>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;
    //		circle(img, poly[0], 6, Scalar(255, 255, 255), 1, 8);
    	}
    	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;
    //		circle(img, poly[0], 6, Scalar(255, 255, 255), 1, 8);
    	}
    	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;
    //		circle(img, poly[0], 6, Scalar(255, 255, 255), 1, 8);
    	}
    
    	vector<Point2f> trans(4);
    	int temp = 60;
    	trans[0] = Point2f(0 + temp, 0 + temp);
    	trans[1] = Point2f(0 + temp, 230 + temp);
    	trans[2] = Point2f(230 + temp, 230 + temp);
    	trans[3] = Point2f(230 + temp, 0 + temp);
    
    	//获取透视投影变换矩阵
    	
    	Mat m = getPerspectiveTransform(poly, trans);
    
    	//计算变换结果
    	Mat result;
    	warpPerspective(img,result,m,Size(350, 350),INTER_LINEAR);
    
    	rectangle(result, Rect(10, 10, 330, 330), Scalar(0, 0, 0), 1, 8);
    

    获取到规则二维码图像之后,调用Zbar工具实现二维码的识别。

    clock_t start = clock(); // 记录程序开始时间,用于计算扫描二维码耗时
    zbar::ImageScanner scanner;
    scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
    
    
    int width = result.cols;
    int height = result.rows;
    Image image(width, height, "Y800", result.data, width * height);  // 图片格式转换
    scanner.scan(image);
    Image::SymbolIterator symbol = image.symbol_begin();
    if (image.symbol_begin() == image.symbol_end())
    {
    	cout << "查询条码失败,请检查图片!" << endl;
    }
    for (; symbol != image.symbol_end(); ++symbol)
    {
    	cout << "类型:" << endl << symbol->get_type_name() << endl << endl;
    	cout << "条码:" << endl << symbol->get_data() << endl << endl;
    }
    image.set_data(nullptr, 0);
    
    clock_t finish = clock();  // 记录程序结束时间
    double time_length = (double)(finish - start) / CLOCKS_PER_SEC; //根据两个时刻的差,计算出扫描的时间  
    cout << "扫描耗时 " << time_length << " seconds." << endl;
    
    

    3、结果
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    透视变换的图像并没有获取到方正的图像,应该是变换角点坐标选取和长宽值不适合的原因,后面再改进。Zbar对于英文、数字等识别效果很好,但是识别中文会出现乱码现象,查阅博客发现是编码和解码格式问题,下次解决。

    展开全文
  • 电赛机器视觉——二维码定位

    千次阅读 2019-07-29 17:39:56
    二维码定位在无人机赛题中极有可能出现,一下为源码: # coding:utf8 # 创建时间:2019年7月29日 # 识别二维码并打印二维码的扫描结果的网址 import cv2 import pyzbar.pyzbar as pyzbar # 创建字典二维码数据...
  • java 图片中的二维码定位 使用技术:opencv 3.4.14 执行下载安装 import com.google.zxing.*; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.common.HybridBinarizer...
  • Opencv的使用小教程3——利用轮廓检测实现二维码定位二维码具有什么特征识别二维码的流程1、预处理图像2、寻找轮廓 好好学习噢! 二维码具有什么特征 二维码就是两个维度的条形码,平常我们在生活中随处可见,“QR...
  • opencv4.0版本以后,加入了二维码定位解码的功能,其主要功能基于quirc开源库,下载地址[添加链接描述](https://github.com/P-Chao/QRCode-CV4)。约1200行代码,识别与定位占了约800行,解码部分不作赘述,直接调用...
  • 采用Zbar第三方库,实现二维码定位,并识别内容,解决了Zbar中文乱码问题. 利用梯度信息进行条形码的定位,QR-code利用矩阵点信息定位
  • 压缩包文件包含:设置软件、操作文档、测试程序、接线图等
  • 一般隐写得到的二维码图片大都需要经过特殊手段还原,其中比较经典的就是二维码定位角的补全。 当看到二维码缺失三个定位角时,首先就想到将其补全,这个操作说起来简单,但实际上,还是需要一些小技巧的,要不然...
  • c++二维码定位和识别+zbar+opencv+ubuntu16.04+clion开发+相机实时扫描
  • 二维码顶点 效果 代码 # --coding:utf-8-- from Camera.sdk.Camera import Camera import time import numpy as np import cv2 def detecte(gray): '''提取所有轮廓''' # _,gray=cv2.threshold(gray,0,255,cv2....
  • c++二维码定位和识别+zbar+opencv+ubuntu16.04+clion开发+相机实时扫描二维码的定位准备安装opencv和配置好clion中的环境C++demo:图片二维码定位使用zbar读取二维码信息安装zbar和测试执行zbarC++demo:读取二维码...
  • opencv二维码定位

    千次阅读 2018-05-22 13:16:08
    putTextZH(img_dc, "二维码定位", Point(0, 20), Scalar(100, 100, 255), 30, "Arial"); putTextZH(img_dc, "缺陷:一幅图最多定位一个二维码", Point(0, 50), Scalar(100, 100, 255) ,30, "Arial"); putTextZH...
  • 二维码定位实验笔记

    2021-04-30 09:32:12
    一、 vs新建一个项目,复制cpp过来后全报错,是这个地方要改成x64。
  • 二维码定位点颜色设置

    千次阅读 2016-09-26 11:27:28
    原理其实很简单,利用zxing的写二维码功能生成二维码图片时,对相应像素点进行着色即可。关键是如何准确获取到二维码探测点在matrix里的位置。 二维码一共有40个尺寸。官方叫版本Version。Version 1是21 x 21...
  • 二维码定位问题

    2016-09-20 17:49:57
    有没有可以定位码眼位置的程序 求解答
  • 通过opencv及pyzbar库将图片中的二维码边界定位出来,然后再通过pyzbar识别二维码的信息 参考文章 参考代码 import cv2 as cv from pyzbar import pyzbar as pyzbar def decodeDisplay(image): barcodes = ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 29,272
精华内容 11,708
关键字:

二维码定位