如何可靠地检测条形码的4个角?

Bas*_*asj 5 python opencv barcode barcode-scanner zbar

我正在尝试使用Python + 模块检测此Code128条形码zbar:

(图像下载链接在这里).

这有效:

import cv2, numpy
import zbar
from PIL import Image 
import matplotlib.pyplot as plt

scanner = zbar.ImageScanner()
pil = Image.open("000.jpg").convert('L')
width, height = pil.size    
plt.imshow(pil); plt.show()
image = zbar.Image(width, height, 'Y800', pil.tobytes())
result = scanner.scan(image)

for symbol in image:
    print symbol.data, symbol.type, symbol.quality, symbol.location, symbol.count, symbol.orientation
Run Code Online (Sandbox Code Playgroud)

但是只检测到一个点:(596, 210).

如果我应用黑白阈值:

pil = Image.open("000.jpg").convert('L')
pil = pil .point(lambda x: 0 if x<100 else 255, '1').convert('L')    
Run Code Online (Sandbox Code Playgroud)

它更好,我们有3分:(596,210),(482,211),(596,212).但它增加了一个难度(找到最佳阈值 - 这里100 - 自动为每个新图像).

尽管如此,我们还没有条形码的4个角落.

问题:如何使用Python可靠地找到图像上条形码的4个角?(也许是OpenCV,或其他图书馆?)

笔记:

  • 可能的,这是一个很好的例子(但遗憾的是不是评论中提到的开源):

    物体检测,非常快速和稳健的模糊1D条码检测,适用于实时应用

    即使条形码只是整个图像的一小部分(这对我来说很重要),角点检测似乎非常好而且速度非常快.

  • 有趣的解决方案:使用Python和OpenCV在视频中进行实时条形码检测,但该方法的局限性(参见文章:条形码应该关闭等)限制了潜在的使用.此外,我更需要为此准备一个现成的库.

  • 有趣的解决方案2:使用Python和OpenCV检测图像中的条形码,但同样,它似乎不是一个生产就绪的解决方案,而是一个正在进行的研究.实际上,我在这张图片上尝试了他们的代码,但检测并没有产生成功的结果.必须注意的是,它没有考虑条形码的任何规格来检测(事实上有一个开始/停止符号等)

    import numpy as np
    import cv2
    image = cv2.imread("000.jpg")
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    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)
    gradient = cv2.subtract(gradX, gradY)
    gradient = cv2.convertScaleAbs(gradient)
    blurred = cv2.blur(gradient, (9, 9))
    (_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))
    closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
    closed = cv2.erode(closed, None, iterations = 4)
    closed = cv2.dilate(closed, None, iterations = 4)
    (_, cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
    rect = cv2.minAreaRect(c)
    box = np.int0(cv2.boxPoints(rect))
    cv2.drawContours(image, [box], -1, (0, 255, 0), 3)
    cv2.imshow("Image", image)
    cv2.waitKey(0)
    
    Run Code Online (Sandbox Code Playgroud)

bfr*_*ris 8

解决方案2非常好。导致它在您的图像上失败的关键因素是阈值。如果您将参数225降低到55,您将获得更好的结果。

我重新编写了代码,在这里和那里做了一些调整。如果您愿意,原始代码很好。OpenCV文档非常好,并且有非常好的Python 教程

import numpy as np
import cv2

image = cv2.imread("barcode.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# equalize lighting
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
gray = clahe.apply(gray)

# edge enhancement
edge_enh = cv2.Laplacian(gray, ddepth = cv2.CV_8U, 
                         ksize = 3, scale = 1, delta = 0)
cv2.imshow("Edges", edge_enh)
cv2.waitKey(0)
retval = cv2.imwrite("edge_enh.jpg", edge_enh)

# bilateral blur, which keeps edges
blurred = cv2.bilateralFilter(edge_enh, 13, 50, 50)

# use simple thresholding. adaptive thresholding might be more robust
(_, thresh) = cv2.threshold(blurred, 55, 255, cv2.THRESH_BINARY)
cv2.imshow("Thresholded", thresh)
cv2.waitKey(0)
retval = cv2.imwrite("thresh.jpg", thresh)

# do some morphology to isolate just the barcode blob
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 9))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
closed = cv2.erode(closed, None, iterations = 4)
closed = cv2.dilate(closed, None, iterations = 4)
cv2.imshow("After morphology", closed)
cv2.waitKey(0)
retval = cv2.imwrite("closed.jpg", closed)

# find contours left in the image
(_, cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
rect = cv2.minAreaRect(c)
box = np.int0(cv2.boxPoints(rect))
cv2.drawContours(image, [box], -1, (0, 255, 0), 3)
print(box)
cv2.imshow("found barcode", image)
cv2.waitKey(0)
retval = cv2.imwrite("found.jpg", image)
Run Code Online (Sandbox Code Playgroud)

边缘.jpg 在此处输入图片说明

阈值.jpg 在此处输入图片说明

关闭.jpg 在此处输入图片说明

发现.jpg在此处输入图片说明

控制台输出:

[[596 249]
 [470 213]
 [482 172]
 [608 209]]
Run Code Online (Sandbox Code Playgroud)