基于OpenCV的条形码区域分割
本期,我们将一起学习如何从图像中提取出含有条形码的区域。下面的代码,我们将在Anaconda中采用Python 2.7 完成,当然OpenCV中的图像处理库也是必不可少的。
分割是识别图像内一个或多个对象的位置的过程。我们要介绍的技术其实非常简单,它利用了形态算子的扩张和侵蚀,以及诸如开运算,闭运算和黑帽算子的组合。
01.简介
安装Anaconda后,让我们从Anaconda的提示符下使用以下命令转到OpenCV安装:
conda install -c https://conda.anaconda.org/menpo opencv
现在,让我们从Anaconda启动器启动Spyder IDE。
Anaconda启动器
一旦运行了Spyder,建议验证OpenCV安装是否成功。在Python控制台的右下角,我们进行以下测试:
import cv2
代码讲解
我们已经创建了一个启动GitHub存储库。小伙伴可以使用以下方法直接克隆它:
git clone --branch step1
https://github.com/lucapiccinelli/BarcodesTutorial.git
现在,我们将要下载测试图像,并对他们进行读取和显示。
测试图片
import cv2
import matplotlib.pyplot as plt
im = cv2.imread(r’imgbarcodes.jpg’, cv2.IMREAD_GRAYSCALE)
plt.imshow(im, cmap=’Greys_r’)
接下来,我们将对图像进行二值化处理,这样可以通过阈值的设定来提取出我们感兴趣的部分。使用黑帽运算符,我们可以增加较暗的图像元素。我们可以首先使用简单的全局阈值安全地对图像进行二值化处理。黑帽运算符使我们可以使用非常低的阈值,而不必过多地关注噪声。
在应用blackhat时,我们使用的内核会更加重视垂直图像元素。内核具有固定的大小,因此可以缩放图像,这也可以提高性能(并支持某种输入归一化)。
黑帽+阈值处理
它遵循其他形态运算符的采用,顺序地将它们组合在一起以获得条形码位置中的连接组件。
#riscalatura dell'immagine
scale = 800.0 / im.shape[1]
im = cv2.resize(im, (int(im.shape[1] * scale), int(im.shape[0] * scale)))
#blackhat
kernel = np.ones((1, 3), np.uint8)
im = cv2.morphologyEx(im, cv2.MORPH_BLACKHAT, kernel, anchor=(1, 0))
#sogliatura
thresh, im = cv2.threshold(im, 10, 255, cv2.THRESH_BINARY)
膨胀和闭合的这种组合在测试图像上效果很好,但可能无法在其他图像上达到相同的效果。这没有关系,大家可以尝试改变参数和运算符的组合,直到对结果满意为止。
膨胀+闭运算
最后的预处理步骤是应用具有很大内核的开运算符,以删除太少而无法适合条形码形状的元素。
kernel = np.ones((21, 35), np.uint8)
im = cv2.morphologyEx(im, cv2.MORPH_OPEN, kernel, iterations=1)
这是我们希望得到的最终结果:
使用35x21内核打开
现在,我们可以运行连接的组件的检测算法,并检索带有坐标和尺寸的条形码矩形。如大家在上一张图像中所看到的那样,最后的形态学步骤并未滤除全部的噪声。但是,在这种情况下,将它们过滤掉非常简单,以矩形区域值作为阈值就可以了。
#rilettura dell'immagine, stavolta a colori
im_out = cv2.imread(r'imgbarcodes.jpg')
#estrazione dei componenti connessi
contours, hierarchy = cv2.findContours(im, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
unscale = 1.0 / scale
if contours != None:
for contour in contours:
# se l'area non è grande a sufficienza la salto
if cv2.contourArea(contour) <= 2000:
continue
#estraggo il rettangolo di area minima (in formato (centro_x, centro_y), (width, height), angolo)
rect = cv2.minAreaRect(contour)
#l'effetto della riscalatura iniziale deve essere eliminato dalle coordinate rilevate
rect =
((int(rect[0][0] * unscale), int(rect[0][1] * unscale)),
(int(rect[1][0] * unscale), int(rect[1][1] * unscale)),
rect[2])
#disegno il tutto sull'immagine originale
box = np.int0(cv2.cv.BoxPoints(rect))
cv2.drawContours(im_out, [box], 0, (0, 255, 0), thickness = 2)
plt.imshow(im_out)
#scrittura dell' immagine finale
cv2.imwrite(r'imgout.png', im_out)
最后,在上面的代码中,我使用提取的矩形绘制它们,并将其覆盖在原始图像上。
最终结果,条形码以绿色框突出显示。
结论
• 提出的技术非常简单有效,但存在一些令人讨厌的缺点:
• 它对条形码偏斜非常敏感;它可以很好地工作到大约45度,然后您必须执行第二遍,修改内核的方向。
• 它只能在固定尺寸范围内找到条形码。
• 尽管对矩形区域施加了过滤,但仍有可能无法清除某些非条形码。
第一个和第二个可能不是真正的问题,但是最后一个可能会花费大家大量时间来尝试解码非条形码的内容。
一个很好的解决方案是将条形码特征(图像梯度,傅立叶变换)输入给神经网络(或一些其他一些分类器),并在第二时刻过滤掉噪声。
下面给出完整的示例代码。
import cv2
import matplotlib.pyplot as plt
import numpy as np
im = cv2.imread(r'imgbarcodes.jpg', cv2.IMREAD_GRAYSCALE)
im_out = cv2.imread(r'imgbarcodes.jpg')
#riscalatura dell'immagine
scale = 800.0 / im.shape[1]
im = cv2.resize(im, (int(im.shape[1] * scale), int(im.shape[0] * scale)))
#blackhat
kernel = np.ones((1, 3), np.uint8)
im = cv2.morphologyEx(im, cv2.MORPH_BLACKHAT, kernel, anchor=(1, 0))
#sogliatura
thresh, im = cv2.threshold(im, 10, 255, cv2.THRESH_BINARY)
#operazioni morfologiche
kernel = np.ones((1, 5), np.uint8)
im = cv2.morphologyEx(im, cv2.MORPH_DILATE, kernel, anchor=(2, 0), iterations=2) #dilatazione
im = cv2.morphologyEx(im, cv2.MORPH_CLOSE, kernel, anchor=(2, 0), iterations=2) #chiusura
kernel = np.ones((21, 35), np.uint8)
im = cv2.morphologyEx(im, cv2.MORPH_OPEN, kernel, iterations=1)
#estrazione dei componenti connessi
contours, hierarchy = cv2.findContours(im, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
unscale = 1.0 / scale
if contours != None:
for contour in contours:
# se l'area non è grande a sufficienza la salto
if cv2.contourArea(contour) <= 2000:
continue
#estraggo il rettangolo di area minima (in formato (centro_x, centro_y), (width, height), angolo)
rect = cv2.minAreaRect(contour)
#l'effetto della riscalatura iniziale deve essere eliminato dalle coordinate rilevate
rect =
((int(rect[0][0] * unscale), int(rect[0][1] * unscale)),
(int(rect[1][0] * unscale), int(rect[1][1] * unscale)),
rect[2])
#disegno il tutto sull'immagine originale
box = np.int0(cv2.cv.BoxPoints(rect))
cv2.drawContours(im_out, [box], 0, (0, 255, 0), thickness = 2)
plt.imshow(im_out)
#scrittura dell' immagine finale
cv2.imwrite(r'imgout.png', im_out)
下载1:OpenCV黑魔法
在「AI算法与图像处理」公众号后台回复:OpenCV黑魔法,即可下载小编精心编写整理的计算机视觉趣味实战教程
下载2 CVPR2020
在「AI算法与图像处理」公众号后台回复:CVPR2020,即可下载1467篇CVPR 2020论文个人微信(如果没有备注不拉群!)请注明:地区+学校/企业+研究方向+昵称
- Python基础知识梳理-第01部分
- 卷积神经网络之卷积操作
- Silverlight体积优化
- 江湖秘笈:说烦了破解、渗透等,不如大家一起聊聊硬盘加密?
- Nodejs学习笔记(十三)— PM2
- 十分钟带你了解服务化框架
- 十分钟带你了解服务化框架
- WCF技术剖析之十七:消息(Message)详解(上篇)
- 微信年底重磅更新,这次小程序才是重头戏!
- 《EnterLib PIAB深入剖析》系列博文汇总
- Nodejs学习笔记(八)--- Node.js + Express 实现上传文件功能(felixge/node-formidable)
- 大牛教你使用7种卷积神经网络进行物体检测!
- Enterprise Library深入解析与灵活应用(3):倘若将Unity、PIAB、Exception Handling引入MVP模式.. .. ..
- 别对我说谎!你的小九九我都知道
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- linux下安装zabbix服务器shell脚本-添加主机-邮件监控报警zabbix-自动化运维
- Nginx——开启 GZIP 压缩
- 谈谈Vue.use的原理
- Nginx——ubuntu安装Nginx并配置https
- Istio 中业务开发需要关注的二三事
- MongoDB——Ubuntu安装及配置带认证的副本集(亲测)
- 经验——SpringBoot 获取 resource 目录下的文件
- 聚类热图怎么按自己的意愿调整分支的顺序?
- H5|HTTP-FLV|WS-FLV|HLS|RTMP免费直播点播播放器如何自定义层叠DIV全屏后显示在视频上方?
- 什么是时间分片(Time Slicing)?
- 48岁的C语言,你知道它背后的历史吗?
- 【技术创作101训练营】我是如何使用freemarker生成Word文件的?
- 4种主流超参数调优技术
- PyTorch 最佳实践:模型保存和加载
- 突击并发编程JUC系列-启航篇