基于OpenCV的条形码检测

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

推荐阅读python

42个pycharm使用技巧,瞬间从黑铁变王者git

Google C++项目编程风格指南 (中文版) 分享github

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=概述算法

 

在平常生活中,常常会看到条形码的应用,好比超市买东西的生活,图书馆借书的时候。。。编程

那么这些东西是如何作到准确检测出条形码的位置呢?ide

这就是今天要介绍的内容了函数

这篇博文的目标是演示使用计算机视觉和图像处理技术实现条形码的检测。学习

经过本篇文章的学习,咱们能学到的内容包括:测试

一、图像处理中经常使用的一些操做流程,包括滤波、阈值化处理、膨胀、腐蚀和轮廓查找等ui

二、更重要的一点,但愿经过这个案例,可以帮助你们创建分析问题和处理问题的思路

须要注意的是,这个算法并不适用于全部的条形码,可是它应该能给你一个基本的直觉,告诉你应该应用什么类型的技术。

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= 

条形码的检测

 

对于下面这个例子,咱们将检测下图中的条形码:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

目标:找到条形码的位置,而去除掉干扰的因素

 

思路:

利用条形码的自身特色,通常都是矩形形状,并且条码的条带是黑色的,矩形区域是白色的

 

 

让咱们继续写一些代码。打开一个新文件,将其命名为 detect_barcode.py,如何开始写代码:

  •  
# 导入必要的包/库import numpy as npimport argparseimport imutilsimport cv2
# 构造参数解析并分析参数ap = argparse.ArgumentParser()ap.add_argument("-i","--image", required = True, help = "path to the image file")args = vars(ap.parse_args())

 

咱们首先要作的是导入咱们须要的包。咱们将使用numpy进行数字处理,argparse用于解析命令行参数,cv2进行opencv绑定。

而后咱们将设置命令行参数。咱们这里只须要一个开关,即 --image,它是咱们图像的路径,其中包含咱们想要检测的条形码。

如今,让我进行实际的图像处理吧 导入图片并转化为灰度图

  •  
image = cv2.imread(args["image"])gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 计算图片x和y方向的Scharr梯度大小ddepth = cv2.cv.CV_32F if imutils.is_cv2() else cv2.CV_32FgradX = cv2.Sobel(gray, ddepth=ddepth , dx=1, dy=0, ksize=-1)gradY = cv2.Sobel(gray, ddepth=ddepth , dx=0, dy=1, ksize=-1)
# 用x方向的梯度减去y方向的梯度gradient = cv2.subtract(gradX,gradY)gradient = cv2.convertScaleAbs(gradient)

 

首先咱们先读入图片并将其转换为灰度图;

而后咱们使用Scharr操做符(这里制定ksize=1)去构造图片在水平和垂直方向上的梯度幅值表示。

这里,咱们用Scharr算子的x方向梯度减去y方向的梯度。经过这个相减操做,咱们就只剩下了高水平梯度和低垂直梯度的图像区域。

咱们上述原始图像的梯度表示以下图所示

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

请注意梯度操做是如何检测出图片的条形码区域的。接下来的步骤是如何过滤掉图片中的噪声,重点关注条形码区域。

  •  
# 对图片进行模糊和阈值化操做blurred = cv2.blur(gradient,(9,9))(_,thresh) = cv2.threshold(blurred, 255, 255, cv2.THRESH_BINARY)

咱们作的第一件事是使用一个卷积核大小为9x9的均值滤波做用于梯度图片。对图片进行这个操做将有助于平滑图片中的高频噪声。

而后我将模糊化后的图片进行阈值化,在梯度图片中,全部的像素点的灰度值低于255的将设为0(黑色),其他设为255(白色)。

模糊和阈值化处理后的输出结果以下:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

然而,正如你所看到的上图阈值化图片,在条形码的垂直方向上存在这间隙。为了缩小这些间隙,并使得咱们的算法更加容易的检测出条形码的“斑点”状区域,咱们须要执行一些基础的形态学操做:

  •  
# 构造一个闭合核并应用于阈值图片kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

 

咱们经过使用函数cv2.getStructuringElement构造一个矩形核。这个核的宽度大于高度,所以容许咱们缩小条形码垂直条带之间的间隙。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

固然,如今图片中非条形码的区域存在着不少斑点,这将会干扰轮廓的检测。

如今,咱们继续尝试移除这些小的斑点

  •  
# 执行一系列的腐蚀和膨胀操做closed = cv2.erode(closed, None, iterations = 4)closed = cv2.dilate(closed, None, iterations = 4)

 

咱们如今要作的是进行4次腐蚀操做,而后再进行4次膨胀操做。腐蚀操做将会“腐蚀”掉图片中的白色像素点,所以将会清除这些小的斑点,而膨胀操做将会“扩张”剩余的白色像素,并使白色区域变长。

若是在腐蚀过程当中去除了小的斑点,则在膨胀的过程当中不会再次出现。

在一系列的腐蚀和膨胀操做以后,这些小斑点已经被成功的移除了,只剩下条形码的区域。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

最后寻找一下图片中条形码的区域的轮廓。

  •  
# 找到阈值化后图片中的轮廓,而后进行根据区域进行排序,仅保留最大区域cnts = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnts = imutils.grab_contours(cnts)c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
# 计算最大轮廓的旋转边界框rect = cv2.minAreaRect(c)box = cv2.cv.BoxPoints(rect) if imutils.is_cv2() else cv2.boxPoints(rect)box = np.int0(box)
# 在检测到的条形码周围绘制边界框并显示图片cv2.drawContours(image, [box], -1, (0,255,0), 3)cv2.imshow("Image", image)cv2.waitKey(0)

幸运的是,opencv中提供了相应的接口,能够很容易地找到图像中的最大轮廓,若是咱们正确地完成了图像处理步骤,它应该会对应于条形码区域。

而后,咱们肯定最大轮廓的最小的边界框,并最后显示检测到的条形码。

正如咱们下图所示,咱们已经成功的检测到条形码

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

代码连接:https://github.com/DWCTOD/AI_study/tree/master/%E5%90%88%E6%A0%BC%E7%9A%84CV%E5%B7%A5%E7%A8%8B%E5%B8%88/%E5%AE%9E%E6%88%98%E7%AF%87/opencv/%EF%BC%88%E4%BA%94%EF%BC%89%E7%94%A8python%E5%92%8Copencv%E6%A3%80%E6%B5%8B%E5%9B%BE%E5%83%8F%E4%B8%AD%E7%9A%84%E6%9D%A1%E5%BD%A2%E7%A0%81

 

使用方法:python3 detect_barcode.py --image images/barcode_01.jpg

另外还提供了其余的测试图片

 

英文原文连接:https://www.pyimagesearch.com/2014/11/24/detecting-barcodes-images-python-opencv/

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= 

总结

 

值得去思考的点

一、为啥要转变成灰度图

二、如何去除干扰因素,特别是条形码下面的材料说明的区域是采用什么办法去除的,小的斑点是如何去除的

 

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=