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)
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)
我们这里所做的是首先进行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,
39cv2.CHAIN_APPROX_SIMPLE)
40 c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
41
42 # compute the rotated bounding box of the largest contour
43 rect = cv2.minAreaRect(c)
44 box = np.int0(cv2.cv.BoxPoints(rect))
45
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)
38~40行:幸运的是这一部分比较容易,我们简单地找到图像中的最大轮廓,如果我们正确完成了图像处理步骤,这里应该对应于条形码区域。
43~44行:然后我们为最大轮廓确定最小边框
48~50行:最后显示检测到的条形码
正如你在下面的图片中所见,我们已经成功检测到了条形码:
图6:成功检测到示例图像中的条形码
下一部分,我们将尝试更多图像。 成功的条形码检测
要跟随这些结果,请使用文章下面的表单去下载本文的源码以及随带的图片。
一旦有了代码和图像,打开一个终端来执行下面的命令: