使用Python和OpenCV检测图片上的条形码
這篇博文的目的是應用計算機視覺和圖像處理技術,展示一個條形碼檢測的基本實現。我所實現的算法本質上基于StackOverflow 上的這個問題,瀏覽代碼之后,我提供了一些對原始算法的更新和改進。
首先需要留意的是,這個算法并不是對所有條形碼有效,但會給你基本的關于應用什么類型的技術的直覺。
假設我們要檢測下圖中的條形碼:
圖1:包含條形碼的示例圖片
現在讓我們開始寫點代碼,新建一個文件,命名為detect_barcode.py,打開并編碼:
| 1 2 3 4 5 6 7 8 9 | # import the necessary packages importnumpy as np importargparse importcv2 # construct the argument parse and parse the arguments ap?=argparse.ArgumentParser() ap.add_argument("-i",?"--image", required?= True,?help= "path to the image file") args?=vars(ap.parse_args()) |
我們首先做的是導入所需的軟件包,我們將使用NumPy做數值計算,argparse用來解析命令行參數,cv2是OpenCV的綁定。
然后我們設置命令行參數,我們這里需要一個簡單的選擇,–image是指包含條形碼的待檢測圖像文件的路徑。
現在開始真正的圖像處理:
| 1 2 3 4 5 6 7 8 9 10 11 12 | # load the image and convert it to grayscale image?=cv2.imread(args["image"]) gray?=cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # compute the Scharr gradient magnitude representation of the images # in both the x and y direction gradX?=cv2.Sobel(gray, ddepth?=cv2.cv.CV_32F, dx?=1, dy?=0, ksize?=-1) gradY?=cv2.Sobel(gray, ddepth?=cv2.cv.CV_32F, dx?=0, dy?=1, ksize?=-1) # subtract the y-gradient from the x-gradient gradient?=cv2.subtract(gradX, gradY) gradient?=cv2.convertScaleAbs(gradient) |
2~3行:從磁盤載入圖像并轉換為灰度圖。
7~8行:使用Scharr操作(指定使用ksize = -1)構造灰度圖在水平和豎直方向上的梯度幅值表示。
11~12行:Scharr操作之后,我們從x-gradient中減去y-gradient,通過這一步減法操作,最終得到包含高水平梯度和低豎直梯度的圖像區域。
上面的gradient表示的原始圖像看起來是這樣的:
圖:2:條形碼圖像的梯度表示
注意條形碼區域是怎樣通過梯度操作檢測出來的。下一步將通過去噪僅關注條形碼區域。
| 1 2 3 | # blur and threshold the image blurred?=cv2.blur(gradient, (9,?9)) (_, thresh)?=cv2.threshold(blurred,?225,?255, cv2.THRESH_BINARY) |
2行:我們要做的第一件事是使用9*9的內核對梯度圖進行平均模糊,這將有助于平滑梯度表征的圖形中的高頻噪聲。
3行:然后我們將模糊化后的圖形進行二值化,梯度圖中任何小于等于255的像素設為0(黑色),其余設為255(白色)。
模糊并二值化后的輸出看起來是這個樣子:
圖3:二值化梯度圖以此獲得長方形條形碼區域的粗略近似
然而,如你所見,在上面的二值化圖像中,條形碼的豎杠之間存在縫隙,為了消除這些縫隙,并使我們的算法更容易檢測到條形碼中的“斑點”狀區域,我們需要進行一些基本的形態學操作:
| 1 2 3 | # construct a closing kernel and apply it to the thresholded image kernel?=cv2.getStructuringElement(cv2.MORPH_RECT, (21,?7)) closed?=cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) |
2行:我們首先使用cv2.getStructuringElement構造一個長方形內核。這個內核的寬度大于長度,因此我們可以消除條形碼中垂直條之間的縫隙。
3行:這里進行形態學操作,將上一步得到的內核應用到我們的二值圖中,以此來消除豎杠間的縫隙。
現在,你可以看到這些縫隙相比上面的二值化圖像基本已經消除:
圖4:使用形態學中的閉運算消除條形碼豎條之間的縫隙
當然,現在圖像中還有一些小斑點,不屬于真正條形碼的一部分,但是可能影響我們的輪廓檢測。
讓我們來消除這些小斑點:
| 1 2 3 | # perform a series of erosions and dilations closed?=cv2.erode(closed,?None, iterations?=4) closed?=cv2.dilate(closed,?None, iterations?=4) |
我們這里所做的是首先進行4次腐蝕(erosion),然后進行4次膨脹(dilation)。腐蝕操作將會腐蝕圖像中白色像素,以此來消除小斑點,而膨脹操作將使剩余的白色像素擴張并重新增長回去。
如果小斑點在腐蝕操作中被移除,那么在膨脹操作中就不會再出現。
經過我們這一系列的腐蝕和膨脹操作,可以看到我們已經成功地移除小斑點并得到條形碼區域。
圖5:應用一系列的腐蝕和膨脹來移除不相關的小斑點
最后,讓我們找到圖像中條形碼的輪廓:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # find the contours in the thresholded image, then sort the contours # by their area, keeping only the largest one (cnts, _)?=cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, ?cv2.CHAIN_APPROX_SIMPLE) c?=sorted(cnts, key?=cv2.contourArea, reverse?=True)[0] # compute the rotated bounding box of the largest contour rect?=cv2.minAreaRect(c) box?=np.int0(cv2.cv.BoxPoints(rect)) # draw a bounding box arounded the detected barcode and display the # image cv2.drawContours(image, [box],?-1, (0,?255,?0),?3) cv2.imshow("Image", image) cv2.waitKey(0) |
3~5行:幸運的是這一部分比較容易,我們簡單地找到圖像中的最大輪廓,如果我們正確完成了圖像處理步驟,這里應該對應于條形碼區域。
8~9行:然后我們為最大輪廓確定最小邊框
13~15行:最后顯示檢測到的條形碼
正如你在下面的圖片中所見,我們已經成功檢測到了條形碼:
圖6:成功檢測到示例圖像中的條形碼
下一部分,我們將嘗試更多圖像。
成功的條形碼檢測
要跟隨這些結果,請使用文章下面的表單去下載本文的源碼以及隨帶的圖片。
一旦有了代碼和圖像,打開一個終端來執行下面的命令:
| 1 | $ python detect_barcode.py?--image images/barcode_02.jpg |
圖7:使用OpenCV檢測圖像中的一個條形碼
檢測椰油瓶子上的條形碼沒有問題。
讓我們試下另外一張圖片:
| 1 | $ python detect_barcode.py?--image images/barcode_03.jpg |
圖8:使用計算機視覺檢測圖像中的一個條形碼
我們同樣能夠在上面的圖片中找到條形碼。
關于食品的條形碼檢測已經足夠了,書本上的條形碼怎么樣呢:
| 1 | $ python detect_barcode.py?--image images/barcode_04.jpg |
圖9:使用Python和OpenCV檢測書本上的條形碼
沒問題,再次通過。
那包裹上的跟蹤碼呢?
| 1 | $ python detect_barcode.py?--image images/barcode_05.jpg |
圖10:使用計算機視覺和圖像處理檢測包裹上的條形碼
我們的算法再次成功檢測到條形碼。
最后,我們再嘗試一張圖片,這個是我最愛的意大利面醬—饒氏自制伏特加醬(Rao’s Homemade Vodka Sauce):
| 1 | $ python detect_barcode.py?--image images/barcode_06.jpg |
圖11:使用Python和Opencv很容易檢測條形碼
我們的算法又一次檢測到條形碼!
總結
這篇博文中,我們回顧了使用計算機視覺技術檢測圖像中條形碼的必要步驟,使用Python編程語言和OpenCV庫實現了我們的算法。
算法概要如下:
需要注意的是,該方法做了關于圖像梯度表示的假設,因此只對水平條形碼有效。
如果你想實現一個更加魯棒的條形碼檢測算法,你需要考慮圖像的方向,或者更好的,應用機器學習技術如Haar級聯或者HOG + Linear SVM去掃描圖像條形碼區域。
源碼下載
英文原文:http://www.pyimagesearch.com/2014/11/24/detecting-barcodes-images-python-opencv/
轉載自:http://blog.jobbole.com/80448/
總結
以上是生活随笔為你收集整理的使用Python和OpenCV检测图片上的条形码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中心频率和一些概念解释
- 下一篇: STL sort()函数详解