OpenCV 二维码定位与识别

2023-11-16

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenCV 二维码定位与识别 的相关文章

  • OpenCV 2.4.3 中的阴影去除

    我正在使用 OpenCV 2 4 3 最新版本 使用内置的视频流检测前景GMG http docs opencv org modules gpu doc video html highlight gmg gpu 3a 3aGMG GPU算法
  • 如何使用 Python 裁剪图像中的矩形

    谁能给我关于如何裁剪两个矩形框并保存它的建议 我已经尝试过这段代码 但效果不佳 import cv2 import numpy as np Run the code with the image name keep pressing spa
  • uri 警告中缺少端口:使用 Python OpenCV cv2.VideoCapture() 打开文件时出错

    当我尝试流式传输 ipcam 时 出现了如下所示的错误 tcp 000000000048c640 uri 中缺少端口 警告 打开文件时出错 build opencv modules videoio src cap ffmpeg impl h
  • 2d 图像点和 3d 网格之间的交点

    Given 网格 源相机 我有内在和外在参数 图像坐标 2d Output 3D 点 是从相机中心发出的光线穿过图像平面上的 2d 点与网格的交点 我试图找到网格上的 3d 点 This is the process From Multip
  • OpenCV 跟踪器:模型未在函数 init 中初始化

    在视频的第一帧 我运行一个对象检测器 它返回对象的边界框 如下所示
  • 如何将 Mat (opencv) 转换为 INDArray (DL4J)?

    我希望任何人都可以帮助我解决这个任务 我正在处理一些图像分类并尝试将 OpenCv 3 2 0 和 DL4J 结合起来 我知道DL4J也包含Opencv 但我认为它没什么用 谁能帮我 如何转换成 INDArray 我尝试阅读一些问题here
  • OpenCV VideoWriter 未写入 Output.avi

    我正在尝试编写一段简单的代码来获取视频 裁剪视频并写入输出文件 系统设置 OS Windows 10 Conda Environment Python Version 3 7 OpenCV Version 3 4 2 ffmpeg Vers
  • “没有名为‘cv2’的模块”,但已安装

    我已经安装了包含 opencv 贡献的 whl 文件 因为我想使用 SIFT 算法 我在 conda 环境中使用 pip 安装了它 所以当我在 conda list 中提示时 它会向我显示 opencv python 3 4 5 contr
  • 在 Visual Studio C++ 2008 中包含 dll

    有没有办法将 dll 包含在项目中 这样我就不必在编译后将这些 dll 与可执行文件放在同一文件夹中 这样我就可以用它们编译我的项目 这是否有可能 如果是 有人可以指导我 我的项目是一个 opencv 项目 有很多 dll 我必须包含在文件
  • 为什么Android的ImageReader类这么慢?

    我尝试了适用于 Android 3 4 1 的全新 OpenCVJavaCamera2View但它太慢了 仅显示相机视图约 15 fps 当我尝试较旧的JavaCameraView相反 它给了我很好的结果 30fps 这是我相机的极限 我想
  • opencv水印周围的轮廓

    我想在图像中的水印周围画一个框 我已经提取了水印并找到了轮廓 但是 不会在水印周围绘制轮廓 轮廓是在我的整个图像上绘制的 请帮我提供正确的代码 轮廓坐标的输出为 array 0 0 0 634 450 634 450 0 dtype int
  • 开放简历fisherfaces

    我有这个问题 当我使用 vs2010 调试 opencv 2 4 0 facetec demo c 运行时 程序出现此错误 OpenCV错误 未知函数中图像步长错误 矩阵不连续 因此其行数无法更改 文件 src opencv modul e
  • 使用卡尔曼滤波器跟踪位置和速度

    我正在使用卡尔曼滤波器 恒定速度模型 来跟踪物体的位置和速度 我测量对象的 x y 并跟踪 x y vx vy 这是有效的 但是如果在传感器读数 x y vx vy 上添加 20 mm 的高斯噪声 即使该点没有移动 只是噪声也会发生波动 对
  • 让网络摄像头在 OpenCV 中工作

    我正在尝试让我的网络摄像头在 Windows 7 64 位中的 OpenCV 版本 2 2 中捕获视频 但是 我遇到了一些困难 OpenCV 附带的示例二进制文件都无法检测到我的网络摄像头 最近我发现这篇文章表明答案在于重新编译一个文件 o
  • 使用 OpenCV 进行相机校准 - 如何调整棋盘方块大小?

    我正在使用 OpenCV Python 示例开发相机校准程序 来自 OpenCV 教程 http opencv python tutroals readthedocs io en latest py tutorials py calib3d
  • 选择合适的IDE

    您会推荐使用以下哪种 IDE 语言来在 Windows 下开发涉及识别手势并与操作系统交互的项目 我将使用 OpenCV 库来执行图像处理任务 之后 我将使用 win32 API 或 NET 框架与操作系统交互 具体取决于您建议的工具 性能
  • 在Python中从整个图像中检测表格部分

    我有一张尺寸为 3500x5000 的图像 现在我只想检测整个图像中的表格部分 如果不能直接进行 OCR 处理 则对其进行裁剪和旋转 经过所有搜索后 我想到了使用裁剪图像中的每个单元格的想法https medium com coinmonk
  • 相机校准:如何正确进行

    我正在尝试使用棋盘格通过众所周知的张氏方法进行校准 然后进行捆绑调整 该方法在 Matlab 和 OpenCV 中都可用 有很多经验指南 但从我个人的经验来看 准确性是相当随机的 它有时可能非常好 但有时也可能非常糟糕 实际上 只需将棋盘放
  • C++ OpenCV 3.4 / FFMPEG 3.4.1 VideoWriter 和 MP4 输出文件格式

    我正在运行 Linux 内核 4 9 35 ti r44 的 ARM BeagleBone X 15 Debian 机器 在我的 C Qt 5 应用程序中 我想将 cv Mat 帧保存为 MP4 格式视频 我安装了 libx264 并从头开
  • 车辆分割和跟踪

    我已经从事一个项目一段时间了 目的是在无人机捕获的视频中检测和跟踪 移动 车辆 目前我正在使用 SVM 该 SVM 接受了从车辆和背景图像中提取的局部特征的特征袋表示的训练 然后 我使用滑动窗口检测方法来尝试定位图像中的车辆 然后我想要跟踪

随机推荐

  • 基础密码学知识和python pycrypto库的介绍使用

    一 密码学基础概念 1 密码 对文本进行编码 使偷窥者无法识别的算法 是一套编码方案 一种特殊的报文编码和相应的解码方式的结合体 加密之前的原始报文称为明文 使用密码之后的报文叫密文 一个简单的例子 这个例子是著名的三字符循环移位密码rot
  • 求你了,别再用 pip 那乌龟的速度去安装库了!

    前言 本文的文字及图片来源于网络 仅供学习 交流使用 不具有任何商业用途 如有问题请及时联系我们以作处理 PS 如有需要Python学习资料的小伙伴可以点击下方链接自行获取 python免费学习资料 代码以及交流解答点击即可加入 学习 Py
  • mysql pool-recycle_sqlalchemy错误记录

    错误类型 sqlalchemy exc OperationalError mysql connector errors OperationalError MySQL Connection not available 超过mysql连接池 尝
  • Rancher 资料收集

    1 是什么 Rancher 是一个全面的企业级容器管理平台 它可以让容器在各种基础设施平台的生产环境上部署和运行更容易 通过Rancher 企业再也不必自己使用一系列的开源软件去从头搭建容器服务平台 Rancher提供了在生产环境中使用的管
  • 批量添加-动态拼接字符串

    字符串拼接主要包括以下三类 第三种方法是今天的重点 Sring format StringBuilder Append 一 对于少量固定的字符串拼接 我们可以简单利用 string s a b c 这样写 系统或优化成如下代码 不会新建多个
  • Python 基于循环神经网络的情感分类系统设计与实现,附可视化界面.

    1 简介 循环神经网络是一种能够有效处理序列数据的深度学习模型 在情感分类任务中具有广泛的应用 因此开发环节采用了GRU框架作为循环神经网络的实现模型 开发完成的情感分类系统能够自动识别用户的留言情感分类 将留言有效区分为积极或消极 并且在
  • python操作excel文件的构建

    一 使用python构建txt文件 1 应用 做最大字符长度检验 需要构架一定数量的数据 如100 200 对象 open 文件名 打开方式 encoding utf 8 with open 文件名 打开方式 encoding utf 8
  • java -jar 远程调试_Java Remote Debug(idea远程调试)

    概述 对于分布式系统的调试不知道大家有什么好的方法 对于我来说 在知道远程调试这个方法之前就是在代码中打各种log 然后重新部署 上线 调试 这样比较费时 今天咱们来了解了解Java远程调试这个牛逼的功能 本文以Intellij IDEA为
  • 云计算与大数据- 云计算概览练习题及答案

    第1章 云计算概览习题 1 1 选择题 1 下列关于云计算的说法错误的是 D A 可以提供按需使用 按量计费的服务 B 可以满足用户的弹性使用需求 C 用户可以在任意时间和地点通过网络获取所需的资源 D 主要基于非虚拟化资源池 2 以下不属
  • jdbc编程六步

    1 加载驱动 2 获取连接 3 创建预编译对象 4 执行sql 5 处理结果集 6 释放资源
  • 蓝桥杯oj 算法训练 大小写转换

    算法训练 大小写转换 时间限制 1 0s 内存限制 512 0MB 锦囊1 锦囊2 锦囊3 问题描述 编写一个程序 输入一个字符串 长度不超过20 然后把这个字符串内的每一个字符进行大小写变换 即将大写字母变成小写 小写字母变成大写 然后把
  • 数据仓库主题三-(实施篇)

    背景 如何从具体的需求或项目转换为可实施的解决方案 如何进行需求分析 架构设计 详细模型设计等 则是模型实施过程中讨论的内容 业界常用两种数据仓库建设模型思想分为两种kimball和inmon模型 具体的kimball和inmon 模型思想
  • 逻辑设计基础_第1章_初识数字逻辑

    这一个月打算学习数字逻辑设计 刚听完课 现在做一下笔记 第1章 初始数字逻辑 本节知识总结为三个方面 分别是数字逻辑的知识脉络 数字逻辑设计的用途和三种二进制编码 下面分别说明 1 1 数字逻辑的知识脉络 首先 学习逻辑代数 其次 根据逻辑
  • docker容器拷贝

    背景 当前jenkins服务器部署在内网环境 需要迁移到云服务器 版本和配置以及之前安装过的jenkins插件都需要同步迁移 方案1 使用docker commit将当前容器打包成镜像 docker commit contain id co
  • CSR867x — 蓝牙音频发射器方案(支持USB、模拟和SPDIF)

    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XX 作 者 文化人 XX 联系方式 或进群 471144274 XX 版权声明 原创文章 欢迎评论和转载 转载时能告诉我一声就
  • 傅里叶变换公式整理

    1 一维傅里叶变换 1 1 一维连续傅里叶变换 正变换 F
  • RS485(Modbus RTU)协议

    Modbus是啥 Modbus 是一种串行通信协议 是施耐德电气为使用可编程逻辑控制器 PLC 通信而发布 是工业领域通信协议的业界标准 并且是工业电子设备之间常用的连接方式 读完好像还是不知道是啥 没关系 你只要记住一点 Modbus是与
  • LeetCode初级算法-,买卖股票数组算法

    题目 给定一个数组 prices 其中 prices i 是一支给定股票第 i 天的价格 设计一个算法来计算你所能获取的最大利润 你可以尽可能地完成更多的交易 多次买卖一支股票 JAVA class Solution public int
  • DNS的解析流程,DNS主从配置,使用httpd服务演示安全上下文值的设定(selinux),使用web服务端口的改变来演示端口的设定(selinux)

    DNS的解析流程 一 DNS的解析方式 1 正向解析 正向解析文件中存储的记录称为A记录 A记录记录着域名和IP的映射关系 2 反向解析 反向解析文件中存储的记录称为PTR指针 PTR记录着IP和域名的映射关系 二 DNS域名的分层结构 国
  • OpenCV 二维码定位与识别

    因为二维码本身含有信息 因此可以作为产品的信息载体 如 产品特征 在工业领域常用在产品入库 分拣和包装上 但常常会因为二维码图像污点 光照不均匀以及二维码图像倾斜等原因 使得二维码的识别正确率低 针对这些问题 通过学习贾老师OpenCV课程