对于条码的识别程序,网上有很多,不过很多都是只识别一个,并且此处的“识别”指的是找出图片中的条码,并没有对条码进行译码。本篇博客将先实现第一个功能,即,找出图中的多个条码。下篇博客会实现第二个功能,即,对找出的条码进行译码。
下面看代码:
from sys import exit
import numpy as np
import cv2
# 加载图片并把它转换为灰度图片
image = cv2.imread('F:/work/barcode/bar_code/8.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray_Image", gray)
cv2.waitKey(0)
'''
# 索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量
gradX = cv2.Sobel(gray, ddepth = cv2.CV_32F, dx = 1, dy = 0, ksize = -1)
gradY = cv2.Sobel(gray, ddepth = cv2.CV_32F, dx = 0, dy = 1, ksize = -1)
# x灰度减去y灰度
gradient = cv2.subtract(gradX, gradY)
# 转回uint8
gradient = cv2.convertScaleAbs(gradient)
absX = cv2.convertScaleAbs(gradX) # 转回uint8
absY = cv2.convertScaleAbs(gradY)
gradient = cv2.addWeighted(absX,0.5,absY,0.5,0) # 组合
'''
gradient = cv2.Canny(gray , 50 ,400)
cv2.imshow("S/C_Image", gradient)
cv2.waitKey(0)
(_, thresh) = cv2.threshold(gradient, 250, 255, cv2.THRESH_BINARY) # 二值化
cv2.imshow("threshold_Image", thresh)
cv2.waitKey(0)
# 构建kernel然后应用到 thresholded 图像上
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 5))#形态学处理,定义矩形结构
#closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)#闭运算,先膨胀后腐蚀
#closed = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)#开运算,先腐蚀后膨胀
#closed = cv2.erode(thresh, kernel, iterations = 1)#腐蚀图像,去除噪声点
closed = cv2.dilate(thresh, kernel, iterations = 1)#膨胀图像,连接断点
cv2.imshow("dilate_Image", closed)
cv2.waitKey(0)
# 找到条码轮廓
# 保留大的区域,有时会有没过滤掉的干扰
im, contours, hierarchy = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
c = sorted(contours, key = cv2.contourArea, reverse = True)[0]
#获取轮廓数量
x = len(contours)
s = []
for i in range(0,x):
s.append(cv2.contourArea(contours[i]))
#打印面积
for j in s:
print "s was : %f",j
#筛选出面积大于等于8000的轮廓
for k in range(0,x):
if s[k] >= 8000.0 :
rect = cv2.minAreaRect(contours[k])#返回矩形的中心点坐标,长宽,旋转角度
box = np.int0(cv2.boxPoints(rect))
cv2.drawContours(image, [box], -1, (255, 0, 0), 2)#画一个方框把条形码区域圈起来
else:
continue
cv2.imshow("Image", image)
cv2.waitKey(0)
exit(0)
解释几个关键的地方。首先是计算机怎么把条码找出来的,观察程序运行过程中弹出来的图像可以知道,计算机框出来的其实是白块,所以前面做的处理为的是让条码变成的白块更加明显,然后这个函数
cv2.findContours()
就可以找到条码的轮廓,由于找的是白块,因此对条码和二维码都适用。然后是如何找出多个条码,还是上面那个函数,其实,那个函数会把图像中所有的白块都找出来。因为条码要大一些,所以用面积这个筛选条件,把符合要求的轮廓都筛选出来,最后画出来。
另外,程序中有不少注释掉的代码,这是因为程序找条码的方法还是比较简单粗暴的,对不同的情况需要不同的处理。各位可以取消注释运行下试试,比如用索贝尔算法取代Canny算法、进行开运算/闭运算等。
放上一张结果图: