如何从图像中如何读取条形码码

用 Python 和 OpenCV 检测图片上的条形码 - 文章 - 伯乐在线
& 用 Python 和 OpenCV 检测图片上的条形码
更新:这篇文章的介绍看起来有点“离题”,某些方面是因为在写文章之前,我刚看完《南方公园黑色星期五》,所以我肯定在僵尸购物者、黑色星期五的混乱和《权利的游戏》中得到一些灵感。
黑色星期五要来了。
疯狂的消费者成群结队,中西部的中年女性蜂拥而出,露出没有牙齿的嗜血牙龈,直奔当地沃尔玛75%折扣的最新一季的《权利的游戏》。
感恩节之夜,他们将在沃尔玛门外排起长队,团结在一起,用他们的双手和头部,击打紧锁的大门,直到身体鲜血淋淋,就像《惊变28天》中的僵尸一样,只不过不是为了肉身,他们渴望小小的消费寄托,他们的战争呐喊着折扣,销售额将会上升到极点,他们雷鸣般的脚步造成整个大平原的地震。
当然,媒体也无济于事,他们将危言耸听每一个小场景。从冻伤的家庭在寒风中露营整晚,到瞒姗老太在大门打开后被蜂拥而入的低价抢购人群踩踏,就像侏罗纪公园中似鸡龙的蹂躏。这所有的一切只是因为她想为9岁的孙女蒂米买到最新的光晕游戏,而蒂米的父母,在去年的这个时候离世了,就在沃尔玛,在这黑色星期五。
我不得不问,所有的这些混乱值得么?
见鬼,当然不。
我在这个黑色星期五时的购物都是在网上完成的,就像用一杯咖啡和少量泰诺(Tylenol)护理宿醉一样。
但是如果你决定外出到现实世界勇敢地低价抢购,你会想先下载本文附带的源码。
想象一下你会觉得多么愚蠢,排队,等待结账,只是为了扫描一下最新一季的《权利的游戏》上的条形码,然后查明它便宜了5美元。
接下来,我将展示给你怎样仅仅通过Python和Opencv,来检测图片中的条形码。
用 Python 和 OpenCV 检测图片上的的条形码
这篇博文的目的是应用计算机视觉和图像处理技术,展示一个条形码检测的基本实现。我所实现的算法本质上基于,浏览代码之后,我提供了一些对原始算法的更新和改进。
首先需要留意的是,这个算法并不是对所有条形码有效,但会给你基本的关于应用什么类型的技术的直觉。
假设我们要检测下图中的条形码:
图1:包含条形码的示例图片
现在让我们开始写点代码,新建一个文件,命名为detect_barcode.py,打开并编码:
1 # import the necessary packages
2 import numpy as np
3 import argparse
4 import cv2
6 # construct the argument parse and parse the arguments
7 ap = argparse.ArgumentParser()
8 ap.add_argument("-i", "--image", required = True, help = "path to the image file")
9 args = vars(ap.parse_args())
1 # import the necessary packages2 import numpy as np3 import argparse4 import cv256 # construct the argument parse and parse the arguments7 ap = argparse.ArgumentParser()8 ap.add_argument("-i", "--image", required = True, help = "path to the image file")9 args = vars(ap.parse_args())
我们首先做的是导入所需的软件包,我们将使用NumPy做数值计算,argparse用来解析命令行参数,cv2是OpenCV的绑定。
然后我们设置命令行参数,我们这里需要一个简单的选择,–image是指包含条形码的待检测图像文件的路径。
现在开始真正的图像处理:
11 # load the image and convert it to grayscale
12 image = cv2.imread(args["image"])
13 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
15 # compute the Scharr gradient magnitude representation of the images
16 # in both the x and y direction
17 gradX = cv2.Sobel(gray, ddepth = cv2.cv.CV_32F, dx = 1, dy = 0, ksize = -1)
18 gradY = cv2.Sobel(gray, ddepth = cv2.cv.CV_32F, dx = 0, dy = 1, ksize = -1)
20 # subtract the y-gradient from the x-gradient
21 gradient = cv2.subtract(gradX, gradY)
22 gradient = cv2.convertScaleAbs(gradient)
123456789101112
11 # load the image and convert it to grayscale12 image = cv2.imread(args["image"])13 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)1415 # compute the Scharr gradient magnitude representation of the images16 # in both the x and y direction17 gradX = cv2.Sobel(gray, ddepth = cv2.cv.CV_32F, dx = 1, dy = 0, ksize = -1)18 gradY = cv2.Sobel(gray, ddepth = cv2.cv.CV_32F, dx = 0, dy = 1, ksize = -1)1920 # subtract the y-gradient from the x-gradient21 gradient = cv2.subtract(gradX, gradY)22 gradient = cv2.convertScaleAbs(gradient)
12~13行:从磁盘载入图像并转换为灰度图。
17~18行:使用Scharr操作(指定使用ksize = -1)构造灰度图在水平和竖直方向上的梯度幅值表示。
21~22行:Scharr操作之后,我们从x-gradient中减去y-gradient,通过这一步减法操作,最终得到包含高水平梯度和低竖直梯度的图像区域。
上面的gradient表示的原始图像看起来是这样的:
图:2:条形码图像的梯度表示
注意条形码区域是怎样通过梯度操作检测出来的。下一步将通过去噪仅关注条形码区域。
24 # blur and threshold the image
25 blurred = cv2.blur(gradient, (9, 9))
26 (_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)
24 # blur and threshold the image25 blurred = cv2.blur(gradient, (9, 9))26 (_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)
25行:我们要做的第一件事是使用9*9的内核对梯度图进行平均模糊,这将有助于平滑梯度表征的图形中的高频噪声。
26行:然后我们将模糊化后的图形进行二值化,梯度图中任何小于等于255的像素设为0(黑色),其余设为255(白色)。
模糊并二值化后的输出看起来是这个样子:
图3:二值化梯度图以此获得长方形条形码区域的粗略近似
然而,如你所见,在上面的二值化图像中,条形码的竖杠之间存在缝隙,为了消除这些缝隙,并使我们的算法更容易检测到条形码中的“斑点”状区域,我们需要进行一些基本的形态学操作:
28 # construct a closing kernel and apply it to the thresholded image
29 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))
30 closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
28 # construct a closing kernel and apply it to the thresholded image29 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))30 closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
29行:我们首先使用cv2.getStructuringElement构造一个长方形内核。这个内核的宽度大于长度,因此我们可以消除条形码中垂直条之间的缝隙。
30行:这里进行形态学操作,将上一步得到的内核应用到我们的二值图中,以此来消除竖杠间的缝隙。
现在,你可以看到这些缝隙相比上面的二值化图像基本已经消除:
图4:使用形态学中的闭运算消除条形码竖条之间的缝隙
当然,现在图像中还有一些小斑点,不属于真正条形码的一部分,但是可能影响我们的轮廓检测。
让我们来消除这些小斑点:
32 # perform a series of erosions and dilations
33 closed = cv2.erode(closed, None, iterations = 4)
34 closed = cv2.dilate(closed, None, iterations = 4)
32 # perform a series of erosions and dilations33 closed = cv2.erode(closed, None, iterations = 4)34 closed = cv2.dilate(closed, None, iterations = 4)
我们这里所做的是首先进行4次腐蚀(erosion),然后进行4次膨胀(dilation)。腐蚀操作将会腐蚀图像中白色像素,以此来消除小斑点,而膨胀操作将使剩余的白色像素扩张并重新增长回去。
如果小斑点在腐蚀操作中被移除,那么在膨胀操作中就不会再出现。
经过我们这一系列的腐蚀和膨胀操作,可以看到我们已经成功地移除小斑点并得到条形码区域。
图5:应用一系列的腐蚀和膨胀来移除不相关的小斑点
最后,让我们找到图像中条形码的轮廓:
36 # find the contours in the thresholded image, then sort the contours
37 # by their area, keeping only the largest one
38 (cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL,
39 cv2.CHAIN_APPROX_SIMPLE)
40 c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
42 # compute the rotated bounding box of the largest contour
43 rect = cv2.minAreaRect(c)
44 box = np.int0(cv2.cv.BoxPoints(rect))
46 # draw a bounding box arounded the detected barcode and display the
47 # image
48 cv2.drawContours(image, [box], -1, (0, 255, 0), 3)
49 cv2.imshow("Image", image)
50 cv2.waitKey(0)
123456789101112131415
36 # find the contours in the thresholded image, then sort the contours37 # by their area, keeping only the largest one38 (cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL,39 cv2.CHAIN_APPROX_SIMPLE)40 c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]41 42 # compute the rotated bounding box of the largest contour43 rect = cv2.minAreaRect(c)44 box = np.int0(cv2.cv.BoxPoints(rect))45 46 # draw a bounding box arounded the detected barcode and display the47 # image48 cv2.drawContours(image, [box], -1, (0, 255, 0), 3)49 cv2.imshow("Image", image)50 cv2.waitKey(0)
38~40行:幸运的是这一部分比较容易,我们简单地找到图像中的最大轮廓,如果我们正确完成了图像处理步骤,这里应该对应于条形码区域。
43~44行:然后我们为最大轮廓确定最小边框
48~50行:最后显示检测到的条形码
正如你在下面的图片中所见,我们已经成功检测到了条形码:
图6:成功检测到示例图像中的条形码
下一部分,我们将尝试更多图像。
成功的条形码检测
要跟随这些结果,请使用文章下面的表单去下载本文的源码以及随带的图片。
一旦有了代码和图像,打开一个终端来执行下面的命令:
$ python detect_barcode.py --image images/barcode_02.jpg
$ python detect_barcode.py --image images/barcode_02.jpg
图7:使用OpenCV检测图像中的一个条形码
检测椰油瓶子上的条形码没有问题。
让我们试下另外一张图片:
$ python detect_barcode.py --image images/barcode_03.jpg
$ python detect_barcode.py --image images/barcode_03.jpg
图8:使用计算机视觉检测图像中的一个条形码
我们同样能够在上面的图片中找到条形码。
关于食品的条形码检测已经足够了,书本上的条形码怎么样呢:
$ python detect_barcode.py --image images/barcode_04.jpg
$ python detect_barcode.py --image images/barcode_04.jpg
图9:使用Python和OpenCV检测书本上的条形码
没问题,再次通过。
那包裹上的跟踪码呢?
$ python detect_barcode.py --image images/barcode_05.jpg
$ python detect_barcode.py --image images/barcode_05.jpg
图10:使用计算机视觉和图像处理检测包裹上的条形码
我们的算法再次成功检测到条形码。
最后,我们再尝试一张图片,这个是我最爱的意大利面酱—饶氏自制伏特加酱(Rao’s Homemade Vodka Sauce):
$ python detect_barcode.py --image images/barcode_06.jpg
$ python detect_barcode.py --image images/barcode_06.jpg
图11:使用Python和Opencv很容易检测条形码
我们的算法又一次检测到条形码!
这篇博文中,我们回顾了使用计算机视觉技术检测图像中条形码的必要步骤,使用Python编程语言和OpenCV库实现了我们的算法。
算法概要如下:
计算x方向和y方向上的Scharr梯度幅值表示
将x-gradient减去y-gradient来显示条形码区域
模糊并二值化图像
对二值化图像应用闭运算内核
进行系列的腐蚀、膨胀
找到图像中的最大轮廓,大概便是条形码
需要注意的是,该方法做了关于图像梯度表示的假设,因此只对水平条形码有效。
如果你想实现一个更加鲁棒的条形码检测算法,你需要考虑图像的方向,或者更好的,应用机器学习技术如Haar级联或者HOG + Linear SVM去扫描图像条形码区域。
源码下载:
关于作者:
可能感兴趣的话题
只能检测条形码区域,不能扫描条形码内容。
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线内容团队正试图以我们微薄的力量,把优秀的原创文章和译文分享给读者,为“快餐”添加一些“营养”元素。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2016 伯乐在线手机读出条形码中的“秘密”(图)
来源:人民网
  水星家纺四件套“2折”158元,“我查查”查出折前价仅198元  屠仕超 房浩促销海报宣称四件套折前价768元 屠仕超 摄  “定价”768元的全棉印花四件套,巴黎春天商场里的水星家纺将其“打折”到158元。然而,消费者购买后查询商品条形码,却显示参考价只有198元,“这不是忽悠我们吗?”日前,读者陆先生致电本报962288新闻热线,表示巴黎春天、水星家纺作为知名品牌,搞这样的“价格优惠”使他“看不懂”。  条形码让价格“现形”  9月3日晚上,记者接到读者投诉后,赶到淮海中路巴黎春天。在6楼,水星家纺正在搞促销活动。销售员拿出一张大海报,上面写着“全棉印花四件套”定价768元,疯抢价158元。价格的上方还有一行小字“2折!每天限量15套,每人每天限购1套!抢购时间:每日17:00起,超值爆款!”销售员称,“全棉印花四件套”原价需768元,现在促销只卖158元!  记者与陆先生见了面,他拿出下午刚刚购买的“全棉印花四件套”和收费小票。他说,下午2时不到,妻子和母亲就排在巴黎春天门口,好不容易等到下午5时,才抢购到两套“全棉印花四件套”。可拿回家后,他用智能手机里的“我查查”软件一查商品条形码,价格竟是198元,而不是水星家纺所宣称的768元!他顿时很气愤,觉得家人被巴黎春天、水星家纺“玩弄了一把”。  价格虚高顾客不买账  记者用智能手机、电脑软件多次查询,输入陆先生所购买的“全棉印花四件套”条形码“5”,显示结果也是198元。那么,巴黎春天水星家纺所宣称的定价768元,又是怎么来的呢?  对此,水星家纺销售员说,768元是上面定的价格,他们也不清楚。记者拨打水星家纺促销活动专线,工作人员解释,公司系统里面“全棉印花四件套”价格确实是768元,至于条形码为何显示198元的价格,他们也要进一步研究。  有部分顾客买了促销后的“全棉印花四件套”,觉得“不划算”,又前去办理退货手续。“两个枕套,一张床单,一个被套,简简单单的"四件套"原价说是768元,你信吗?”有顾客这样说道。昨天下午,巴黎春天水星家纺终于答应,给陆先生购买的两套“全棉印花四件套”全部退款。
(来源:新民晚报)
(责任编辑:UN606)
主演:黄晓明/陈乔恩/乔任梁/谢君豪/吕佳容/戚迹
主演:陈晓/陈妍希/张馨予/杨明娜/毛晓彤/孙耀琦
主演:陈键锋/李依晓/张迪/郑亦桐/张明明/何彦霓
主演:尚格?云顿/乔?弗拉尼甘/Bianca Bree
主演:艾斯?库珀/ 查宁?塔图姆/ 乔纳?希尔
baby14岁写真曝光
李冰冰向成龙撒娇争宠
李湘遭闺蜜曝光旧爱
美女模特教老板走秀
曝搬砖男神奇葩择偶观
柳岩被迫成赚钱工具
大屁小P虐心恋
匆匆那年大结局
乔杉遭粉丝骚扰
男闺蜜的尴尬初夜
社区热帖推荐
皮卡丘:我过气了吗?……[]
客服热线:86-10-
客服邮箱:

我要回帖

更多关于 如何读取条形码 的文章

 

随机推荐