因为二维码本身含有信息,因此可以作为产品的信息载体,如:产品特征。在工业领域常用在产品入库、分拣和包装上。但常常会因为二维码图像污点、光照不均匀以及二维码图像倾斜等原因,使得二维码的识别正确率低,针对这些问题,通过学习贾老师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对于英文、数字等识别效果很好,但是识别中文会出现乱码现象,查阅博客发现是编码和解码格式问题,下次解决。

OpenCV 二维码定位与识别相关推荐

  1. opencv 二维码定位

    最近师兄跟我提到我二维码定位,参考了许多大佬的程序,写了这个小程序 目的: 用opencv的库实现QRcode定位 环境: Windows 10 VS2015 opencv3.4.0 基本原理 下图为 ...

  2. python3实现二维码定位及识别

    一.功能需求 通过opencv及pyzbar库将图片中的二维码边界定位出来,然后再通过pyzbar识别二维码的信息 参考文章 参考代码 import cv2 as cv from pyzbar imp ...

  3. python opencv 二维码定位识别

    # --coding:utf-8-- from Camera.sdk.Camera import Camerafrom math import sin,cos,radians,fabs import ...

  4. Opencv的使用小教程3——利用轮廓检测实现二维码定位

    Opencv的使用小教程3--利用轮廓检测实现二维码定位 二维码具有什么特征 实现效果 识别二维码的流程 1.预处理图像 2.寻找轮廓 3.通过寻找到的轮廓确定"回"的位置 4.创 ...

  5. opencv4.0.1 qr二维码定位识别源码详解(一)

    一.概述 opencv4.0版本以后,加入了二维码定位解码的功能,其主要功能基于quirc开源库,下载地址GitHub.约1200行代码,识别与定位占了约800行,解码部分不作赘述,直接调用quric ...

  6. python3 + opencv +pyzbar实时检测二维码 / 定位二维码,并绘制出二维码的框和提取二维码内容

    python3 + opencv +pyzbar实时检测二维码 / 定位二维码,并绘制出二维码的框和提取二维码内容 1 pyzbar二维码检测模块 1.1. pyzbar模块介绍 1.2 pyzbar ...

  7. OpenCV+Zbar二维码及条形码识别

    OpenCV搭配Zbar进行二维码及条形码识别 先上代码 #include<Windows.h> #include <iostream> #include<zbar.h& ...

  8. java二维码定位获取坐标并替换原来二维码

    有段时间没有写博客了,不知道是因为工作的原因还是懒了... 程序员还得以写代码为生,so~进入主题吧 公司是做广告服务的,运转模式一句话就是:在车内设备上播放广告主投放的广告,并获取收益,现在有个需求 ...

  9. 【二维码识别】基于matlab GUI灰度+二值化+校正二维码生成与识别【含Matlab源码 635期】

    ⛄一.二维码生成与识别简介 如今,移动互联网技术日新月异,随着5G时代的来临,广泛应用于数据处理过程中的二维码信息安全日益成为人们越来越关注的问题.以QR码为代表的二维码,以其在信息存储.传输和识别技 ...

最新文章

  1. EM: 生而为菌,自强不息-嗜酸杆菌在重金属污染土壤中的生态适应性机制
  2. 浅谈Java throw, throws, try catch异常处理
  3. iframe,window,滚动栏的一些问题
  4. python下载网页歌词_使用Python下载歌词并嵌入歌曲文件中的实现代码
  5. 03-cmake语法-变量,字符串
  6. leetCode刷题第一天--求两数之和
  7. java中的equals()空对象的出错
  8. mysql数据库备份到oss_备份MySQL数据库并上传到阿里云OSS存储
  9. LeetCode力扣(27. 移除元素)----Java/JavaScript/C
  10. ubuntu ssh 登录日志_全球第一开源ERP Odoo操作手册 安装ssh服务和ssh客户端
  11. Python网络编程基础【底层网络】
  12. ci框架 乱码 mysql_CodeIgniter(CI)发邮件标题中文乱码解决方案
  13. 联想 m73 黑苹果 软路由 esxi AIO
  14. 去哪儿网前端架构师司徒正美:如何挑选适合的前端框架?
  15. Linux常用命令100个用法
  16. EC风扇电机如何工作?
  17. 《微微一笑很倾城》中肖奈大神说的平方根倒数速算法是什么鬼?三十分钟理解!...
  18. jenkins使用python plugin编写代码构建时报错:Caused: java.io.IOException: Cannot run program “python“
  19. 数据分析案例-气象数据分析
  20. 802.11有线等效加密WEP

热门文章

  1. 学会了GDB,就像山顶洞人学会了钻木取火
  2. 怎样在一只股票上做T+0?
  3. 自编程实现朴素贝叶斯算法,Navie Bayes程序(python),并对鸢尾花数据进行分类。
  4. 猴博士、高数叔资源分享
  5. 5种很牛的两位数乘法速算方法
  6. msp432上运行linux,MSP432实现printf 输出
  7. php中的点号,PHP中逗号与点号有什么区别
  8. html5 webp,JS判断浏览器是否支持webp
  9. SpringBoot application.properties 详解
  10. 《历史的教训》读书笔记(转载)