计算机视觉实战项目——基于OpenCV的条形码区域分割
摘要:
本项目将讲解如何从一副图片中分割出含有条形码的区域,并使用矩形框来进行标注。
开发环境:
python3.7、OpenCV3图像处理库、pycharm
开发流程:
1、导入我们要用到的包
import cv2 # OpenCV
import matplotlib.pyplot as plt # 绘制图像用到的包
import numpy as np # 在进行黑帽运算、阈值处理、膨胀、闭运算时会用到
2、读取二维码图片
image = cv2.imread('./image/barcodes.jpg', cv2.IMREAD_GRAYSCALE)
# cv2.IMREAD_GRAYSCALE读取一副灰度图
image_out = cv2.imread('image/barcodes.jpg') # 后期重新读取图片用矩形标注二维码区域

3、改变图片尺寸
scale = 800.0 / image.shape[1]
image = cv2.resize(image, (int(image.shape[1] * scale), int(image.shape[0] * scale)))#重新定义图片大小
4、对图像进行二值化运算,使用黑帽运算符增加较暗的图像元素。使用简单的全局阈值对图像进行二值化处理。黑帽运算符可以使我们获得非常低的阈值,从而不必过多的关注噪声。
kernel = np.ones((1,3), np.uint8) # 创建一个一行三列的1矩阵 [[1,1,1]]
image = cv2.morphologyEx(image, cv2.MORPH_BLACKHAT, kernel, anchor=(1,0)) # 黑帽运算
thresh, image = cv2.threshold(image, 10, 255, cv2.THRESH_BINARY) # 阈值处理,此处设置阈值为10,填充色为255,阈值类型设为二值化化,大于阈值使用255填充,小于阈值设为0

5、对图像做膨胀运算和闭运算
kernel = np.ones((1,5), np.uint8)
image = cv2.morphologyEx(image, cv2.MORPH_DILATE, kernel, anchor=(2, 0), iterations=2) # 膨胀运算
image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel, anchor=(2, 0), iterations=2) # 闭运算

6、使用很大的内核进行开运算,从而删除太少而无法适合条形码形状的元素
kernel = np.ones((21,35), np.uint8)
image = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel, iterations=1)

7、检测二维码的轮廓
contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # 只检测外轮廓,存储所有的轮廓点,相邻的两个点的像素差不超过1
# contours:轮廓本身,type:list; hierarchy:每条轮廓对应的属性,type:ndarray
8、过滤噪声,绘制轮廓
unscale = 1.0 / scale
if contours != None: # 判断检测出的轮廓列表是否为空
for contour in contours: # 循环读取每个轮廓
if cv2.contourArea(contour) <= 2000: # 计算轮廓面积,如果小于2000,就丢弃掉,继续读取下一个轮廓
continue
rect = cv2.minAreaRect(contour) # 计算每个轮廓包含点集的最小面积
# minAreaRect()返回一个Box2D结构rect:(最小外接矩形的中心(x,y),(宽度,高度),旋转角度)
rect = ((int(rect[0][0] * unscale), int(rect[0][1] * unscale)),
(int(rect[1][0] * unscale), int(rect[1][1] * unscale)),
rect[2])
box = np.int0(cv2.boxPoints(rect)) # 获取到外接矩形的四个顶点坐标
cv2.drawContours(image_out, [box], 0, (0, 255, 0), thickness=2) # 绘制轮廓,(指明在哪幅图片上绘制轮廓,轮廓本身-是一个list,指明绘制轮廓的list中的哪条轮廓,线条颜色,线条宽度)
9、绘制图像,将标注完二维码轮廓的图像保存下来
plt.imshow(image_out)
cv2.imwrite('image/out.jpg', image_out)
结果:

结语:
至此,二维码区域分割已完成。虽然在此测试图像上表现比较好,但是此方法存在一些问题:
(1)他对条形码偏斜非常敏感,它可以很好地工作到45度,然后必须执行第二遍,修改内核的方向
(2)他只能在固定尺寸范围内找到条形码
(3)过滤效果差,仍然不能过滤掉某些非条形码
解决方法:将条形码特征输入给神经网络,并在第二时刻过滤掉噪声。
参考文章:https://blog.youkuaiyun.com/qq_42722197/article/details/108971078
优快云下载:https://download.youkuaiyun.com/download/qq_39330829/16798820