OpenCV检测与识别条码、二维码(BarcodeDetector,QRCodeDetector)

原文链接:http://www.juzicode.com/opencv-note-barcodedetector-qrcodedetector

​在 zbar:给我来10G打码图片 一文中桔子菌介绍了怎么用pyzbar识别条码和二维码的方法,今天我们聊聊怎么用OpenCV检测和识别条码、二维码。

1、BarcodeDetector 识别条形码

OpenCV在V4.5.3版本的contrib包中提供了一个barcode::BarcodeDetector类,用这个类可以实现条形码的识别,不过目前仅支持EAN13编码的条形码,其他类型的条形码在当前版本的BarcodeDetector还不支持。

在Python中使用,需要先安装opencv的contrib包:

pip install opencv-contrib-python

导入模块时无差异仍然使用import cv2。

下面我们来看下具体的使用过程,首先创建一个条码检测实例:

import cv2
detect_obj = cv2.barcode_BarcodeDetector()

然后用detectAndDecode()方法检测和识别条码,该方法将检测条码的存在和识别条码封装在一起:

img = cv2.imread("bar.jpg")
is_ok, bar_info, bar_type, points = detect_obj.detectAndDecode(img)

返回的结果包含4个元素,分别是是否检测到条码、识别的条码信息、条码类型和条码位置:

print('is_ok:',is_ok)
print('bar_info:',bar_info)
print('bar_type:',bar_type)
print('points:',points)

运行结果:

is_ok: True
bar_info: ['9787121110085']
bar_type: [2]
points: [[[248.0772  446.5566 ]
  [248.50542 168.47102]
  [725.2236  169.20511]
  [724.79535 447.2907 ]]]

这其中条码位置包含了4个元素,代表了检测到的矩形框的4个角的坐标。

利用这些坐标可以在图像中标注识别到条码位置:

for pos in points:
    color=(0,0,255)
    thick=3
    for p in [(0,1),(1,2),(2,3),(3,0)]:
        start = int(pos[p[0]][0]),int(pos[p[0]][1])
        end = int(pos[p[1]][0]),int(pos[p[1]][1])
        #print(start,end )
        cv2.line(img,start,end,color,thick)

cv2.imshow('img',img)
cv2.imwrite('bar-detect.jpg',img)
cv2.waitKey()
cv2.destroyAllWindows()

当然上述检测方法detectAndDecode()也可以拆分成2个步骤进行,第1步先用detect()检测是否有条码:

img = cv2.imread("bar.jpg")
is_ok, points = detect_obj.detect(img)
print('is_ok:',is_ok)
print('points:',points)

运行结果:

is_ok: True
points: [[[248.0772  446.5566 ]
  [248.50542 168.47102]
  [725.2236  169.20511]
  [724.79535 447.2907 ]]]

第2步将检测到的points传入decode()方法进行识别:

is_ok, bar_info, sn_type = detect_obj.decode(img,points)
print('is_ok:',is_ok)
print('bar_info:',bar_info)
print('bar_type:',bar_type)

运行结果:

is_ok: True
bar_info: ['9787121110085']
bar_type: [2]

标注识别到的条码位置和前面一样,这里不再重复。

2、QRCodeDetector 识别二维码

OpenCV中的QRCodeDetector类可以实现二维码的检测,QRCodeDetector类在OpenCV的3.0版本中就已经出现了,而且是在正式库不是contrib库中。

首先用QRCodeDetector()创建实例:

import  cv2
detect_obj = cv2.QRCodeDetector()

然后将图像传入到detectAndDecode()方法中检测和识别:

img = cv2.imread("qr.jpg")
qr_info, points, qr_img = detect_obj.detectAndDecode(img)

返回的结果包含3个元素,第1个为识别的二维码信息,utf8格式的字符串;第2个为检测到的位置,包含4个点;第3个为二值化后的二维码,尺寸较原图更小。

print('qr_info:',qr_info)
print('points:',points)
print('qr_img.shape:',qr_img.shape)
cv2.imshow('qr_img',qr_img)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果:

qr_info: http://weixin.qq.com/r/Ejr54d-EkYLurZuC928A
points: [[[ 74.  74.]
  [308.  74.]
  [308. 308.]
  [ 74. 308.]]]
qr_img.shape: (37, 37)

这其中位置points包含了检测到的二维码位置,每组包含4个元素,代表了检测到的矩形框的4个角的坐标。用这些坐标可以在图像中标注识别到条码位置:

for pos in points:
    color=(0,0,255)
    thick=3
    for p in [(0,1),(1,2),(2,3),(3,0)]:
        start = int(pos[p[0]][0]),int(pos[p[0]][1])
        end = int(pos[p[1]][0]),int(pos[p[1]][1])
        #print(start,end )
        cv2.line(img,start,end,color,thick)
cv2.imwrite('qr-detect.jpg',img)
cv2.imshow('img',img)
cv2.waitKey()
cv2.destroyAllWindows()
这里是在演示检测效果,不是打广告

也可以用2个步骤分开执行,先用detect()方法检测,返回是否检测到二维码,以及二维码的位置:

img = cv2.imread("qr.jpg")
is_ok, points=detect_obj.detect(img)
print('is_ok:',is_ok)
print('points:',points)

运行结果:

is_ok: True
points: [[[ 74.  74.]
  [308.  74.]
  [308. 308.]
  [ 74. 308.]]]

再用decode()方法识别,传入图像和上一步检测的二维码位置,返回的结果包含二维码信息和二值化后的二维码图像:

qr_info, qr_img = detect_obj.decode(img,points)
print('qr_info:',qr_info)
print('qr_img.shape:',qr_img.shape)
print('qr_img:',qr_img)

运行结果:

qr_info: http://weixin.qq.com/r/Ejr54d-EkYLurZuC928A
qr_img.shape: (37, 37)
qr_img: [[  0   0   0 ...   0   0   0]
 [  0 255 255 ... 255 255   0]
 [  0 255   0 ...   0 255   0]
 ...
 [  0 255   0 ... 255   0   0]
 [  0 255 255 ... 255 255 255]
 [  0   0   0 ... 255 255   0]]

另外需要注意的是detectAndDecode()只能用来检测图像中只有1个二维码的情况,当图像中有多个二维码时,它的返回值qr_info为空字符串。

如果不确定图像中是否有多个二维码,可以用detectAndDecodeMulti()方法检测可能的多个二维码

import  cv2
detect_obj = cv2.QRCodeDetector()
img = cv2.imread("qr-multi.jpg")
is_ok, qr_info, points, qr_img = detect_obj.detectAndDecodeMulti(img)
print('is_ok:',is_ok)
print('qr_info:',qr_info)
print('points:',points)
print('qr_img:',qr_img)

运行结果:

is_ok: True
qr_info: ['this is a test image', 'www.juzicode.com  vx: juzicode']
points: [[[531.      127.     ]
  [796.      127.     ]
  [796.      392.     ]
  [531.      392.     ]]

 [[ 73.       75.     ]
  [405.00003  75.     ]
  [405.00003 406.99997]
  [ 73.      407.     ]]]
qr_img: [array([[  0,   0,   0, ...,   0,   0,   0],
       [  0, 255, 255, ..., 255, 255,   0],
       [  0, 255,   0, ...,   0, 255,   0],
       ...,
       [  0, 255,   0, ...,   0, 255,   0],
       [  0, 255, 255, ..., 255, 255,   0],
       [  0,   0,   0, ...,   0,   0,   0]], dtype=uint8), array([[  0,   0,   0, ...,   0,   0,   0],
       [  0, 255, 255, ..., 255, 255,   0],
       [  0, 255,   0, ...,   0, 255,   0],
       ...,
       [  0, 255,   0, ..., 255, 255,   0],
       [  0, 255, 255, ..., 255,   0, 255],
       [  0,   0,   0, ..., 255,   0,   0]], dtype=uint8)]

detectAndDecodeMulti()方法返回包含4个元素的元组,第1个为是否检测到二维码,第2个为检测到的二维码信息,第3个为二维码边角的4个点,第4个为二值化处理后的二维码图片,后面3个元素均为list类型。

扩展阅读:

  1.  zbar识别条形码和QR二维码
  2. OpenCV: cv::barcode::BarcodeDetector Class Reference
  3. OpenCV: cv::QRCodeDetector Class Reference

 

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注