實(shí)操教程|基于OpenCV的條形碼區(qū)域分割

極市導(dǎo)讀
?本文在Anaconda中采用Python 2.7 完成從圖像中提取出含有條形碼的區(qū)域。?>>加入極市CV技術(shù)交流群,走在計(jì)算機(jī)視覺(jué)的最前沿

我們將一起學(xué)習(xí)如何從圖像中提取出含有條形碼的區(qū)域。下面的代碼,我們將在Anaconda中采用Python 2.7 完成,當(dāng)然OpenCV中的圖像處理庫(kù)也是必不可少的。
分割是識(shí)別圖像內(nèi)一個(gè)或多個(gè)對(duì)象的位置的過(guò)程。我們要介紹的技術(shù)其實(shí)非常簡(jiǎn)單,它利用了形態(tài)算子的擴(kuò)張和侵蝕,以及諸如開(kāi)運(yùn)算,閉運(yùn)算和黑帽算子的組合。
簡(jiǎn)介
安裝Anaconda后,讓我們從Anaconda的提示符下使用以下命令轉(zhuǎn)到OpenCV安裝:conda install -c https://conda.anaconda.org/menpo opencv現(xiàn)在,讓我們從Anaconda啟動(dòng)器啟動(dòng)Spyder IDE。

Anaconda啟動(dòng)器一旦運(yùn)行了Spyder,建議驗(yàn)證OpenCV安裝是否成功。在Python控制臺(tái)的右下角,我們進(jìn)行以下測(cè)試:
import?cv2
代碼講解
我們已經(jīng)創(chuàng)建了一個(gè)啟動(dòng)GitHub存儲(chǔ)庫(kù)。小伙伴可以使用以下方法直接克隆它:
git?clone?--branch?step1
https://github.com/lucapiccinelli/BarcodesTutorial.git
現(xiàn)在,我們將要下載測(cè)試圖像,并對(duì)他們進(jìn)行讀取和顯示。

import?cv2
import?matplotlib.pyplot?as?plt
im?=?cv2.imread(r’img\barcodes.jpg’,?cv2.IMREAD_GRAYSCALE)
plt.imshow(im,?cmap=’Greys_r’)
接下來(lái),我們將對(duì)圖像進(jìn)行二值化處理,這樣可以通過(guò)閾值的設(shè)定來(lái)提取出我們感興趣的部分。使用黑帽運(yùn)算符,我們可以增加較暗的圖像元素。我們可以首先使用簡(jiǎn)單的全局閾值安全地對(duì)圖像進(jìn)行二值化處理。黑帽運(yùn)算符使我們可以使用非常低的閾值,而不必過(guò)多地關(guān)注噪聲。
在應(yīng)用blackhat時(shí),我們使用的內(nèi)核會(huì)更加重視垂直圖像元素。內(nèi)核具有固定的大小,因此可以縮放圖像,這也可以提高性能(并支持某種輸入歸一化)。

黑帽+閾值處理它遵循其他形態(tài)運(yùn)算符的采用,順序地將它們組合在一起以獲得條形碼位置中的連接組件。
#riscalatura?dell'immagine
scale?=?800.0?/?im.shape[1]
im?=?cv2.resize(im,?(int(im.shape[1]?*?scale),?int(im.shape[0]?*?scale)))
#blackhat
kernel?=?np.ones((1,?3),?np.uint8)
im?=?cv2.morphologyEx(im,?cv2.MORPH_BLACKHAT,?kernel,?anchor=(1,?0))
#sogliatura
thresh,?im?=?cv2.threshold(im,?10,?255,?cv2.THRESH_BINARY)
膨脹和閉合的這種組合在測(cè)試圖像上效果很好,但可能無(wú)法在其他圖像上達(dá)到相同的效果。這沒(méi)有關(guān)系,大家可以嘗試改變參數(shù)和運(yùn)算符的組合,直到對(duì)結(jié)果滿意為止。

膨脹+閉運(yùn)算最后的預(yù)處理步驟是應(yīng)用具有很大內(nèi)核的開(kāi)運(yùn)算符,以刪除太少而無(wú)法適合條形碼形狀的元素。
kernel = np.ones((21, 35), np.uint8)
im = cv2.morphologyEx(im, cv2.MORPH_OPEN, kernel, iterations=1)
這是我們希望得到的最終結(jié)果:

使用35x21內(nèi)核打開(kāi)現(xiàn)在,我們可以運(yùn)行連接的組件的檢測(cè)算法,并檢索帶有坐標(biāo)和尺寸的條形碼矩形。如大家在上一張圖像中所看到的那樣,最后的形態(tài)學(xué)步驟并未濾除全部的噪聲。但是,在這種情況下,將它們過(guò)濾掉非常簡(jiǎn)單,以矩形區(qū)域值作為閾值就可以了。
#rilettura?dell'immagine,?stavolta?a?colori
im_out?=?cv2.imread(r'img\barcodes.jpg')
#estrazione?dei?componenti?connessi
contours,?hierarchy?=?cv2.findContours(im,?cv2.RETR_EXTERNAL,?cv2.CHAIN_APPROX_NONE)
unscale?=?1.0?/?scale
if?contours?!=?None:
????for?contour?in?contours:
????????
????????#?se?l'area?non?è?grande?a?sufficienza?la?salto?
????????if?cv2.contourArea(contour)?<=?2000:
????????????continue
????????
????????#estraggo?il?rettangolo?di?area?minima?(in?formato?(centro_x,?centro_y),?(width,?height),?angolo)
????????rect?=?cv2.minAreaRect(contour)
????????#l'effetto?della?riscalatura?iniziale?deve?essere?eliminato?dalle?coordinate?rilevate
????????rect?=?\
????????????((int(rect[0][0]?*?unscale),?int(rect[0][1]?*?unscale)),?\
?????????????(int(rect[1][0]?*?unscale),?int(rect[1][1]?*?unscale)),?\
?????????????rect[2])
????????
????????#disegno?il?tutto?sull'immagine?originale
????????box?=?np.int0(cv2.cv.BoxPoints(rect))
????????cv2.drawContours(im_out,?[box],?0,?(0,?255,?0),?thickness?=?2)
????????
plt.imshow(im_out)
#scrittura?dell'?immagine?finale
cv2.imwrite(r'img\out.png',?im_out)
最后,在上面的代碼中,我使用提取的矩形繪制它們,并將其覆蓋在原始圖像上。

最終結(jié)果,條形碼以綠色框突出顯示。
結(jié)論
提出的技術(shù)非常簡(jiǎn)單有效,但存在一些缺點(diǎn):
它對(duì)條形碼偏斜非常敏感;它可以很好地工作到大約45度,然后必須執(zhí)行第二遍,修改內(nèi)核的方向。 它只能在固定尺寸范圍內(nèi)找到條形碼。 盡管對(duì)矩形區(qū)域施加了過(guò)濾,但仍有可能無(wú)法清除某些非條形碼。第一個(gè)和第二個(gè)可能不是真正的問(wèn)題,但是最后一個(gè)可能會(huì)花費(fèi)大家大量時(shí)間來(lái)嘗試解碼非條形碼的內(nèi)容。一個(gè)很好的解決方案是將條形碼特征(圖像梯度,傅立葉變換)輸入給神經(jīng)網(wǎng)絡(luò)(或一些其他一些分類器),并在第二時(shí)刻過(guò)濾掉噪聲。下面給出完整的示例代碼。
import?cv2
import?matplotlib.pyplot?as?plt
import?numpy?as?np
im?=?cv2.imread(r'img\barcodes.jpg',?cv2.IMREAD_GRAYSCALE)
im_out?=?cv2.imread(r'img\barcodes.jpg')
#riscalatura?dell'immagine
scale?=?800.0?/?im.shape[1]
im?=?cv2.resize(im,?(int(im.shape[1]?*?scale),?int(im.shape[0]?*?scale)))
#blackhat
kernel?=?np.ones((1,?3),?np.uint8)
im?=?cv2.morphologyEx(im,?cv2.MORPH_BLACKHAT,?kernel,?anchor=(1,?0))
#sogliatura
thresh,?im?=?cv2.threshold(im,?10,?255,?cv2.THRESH_BINARY)
#operazioni??morfologiche
kernel?=?np.ones((1,?5),?np.uint8)
im?=?cv2.morphologyEx(im,?cv2.MORPH_DILATE,?kernel,?anchor=(2,?0),?iterations=2)?#dilatazione
im?=?cv2.morphologyEx(im,?cv2.MORPH_CLOSE,?kernel,?anchor=(2,?0),?iterations=2)??#chiusura
kernel?=?np.ones((21,?35),?np.uint8)
im?=?cv2.morphologyEx(im,?cv2.MORPH_OPEN,?kernel,?iterations=1)
#estrazione?dei?componenti?connessi
contours,?hierarchy?=?cv2.findContours(im,?cv2.RETR_EXTERNAL,?cv2.CHAIN_APPROX_NONE)
unscale?=?1.0?/?scale
if?contours?!=?None:
????for?contour?in?contours:
????????
????????#?se?l'area?non?è?grande?a?sufficienza?la?salto?
????????if?cv2.contourArea(contour)?<=?2000:
????????????continue
????????
????????#estraggo?il?rettangolo?di?area?minima?(in?formato?(centro_x,?centro_y),?(width,?height),?angolo)
????????rect?=?cv2.minAreaRect(contour)
????????#l'effetto?della?riscalatura?iniziale?deve?essere?eliminato?dalle?coordinate?rilevate
????????rect?=?\
????????????((int(rect[0][0]?*?unscale),?int(rect[0][1]?*?unscale)),?\
?????????????(int(rect[1][0]?*?unscale),?int(rect[1][1]?*?unscale)),?\
?????????????rect[2])
????????
????????
????????#disegno?il?tutto?sull'immagine?originale
????????box?=?np.int0(cv2.cv.BoxPoints(rect))
????????cv2.drawContours(im_out,?[box],?0,?(0,?255,?0),?thickness?=?2)
????????
plt.imshow(im_out)
#scrittura?dell'?immagine?finale
cv2.imwrite(r'img\out.png',?im_out)
如果覺(jué)得有用,就請(qǐng)分享到朋友圈吧!
公眾號(hào)后臺(tái)回復(fù)“數(shù)據(jù)集”獲取深度學(xué)習(xí)數(shù)據(jù)集分類下載~

#?CV技術(shù)社群邀請(qǐng)函?#

備注:姓名-學(xué)校/公司-研究方向-城市(如:小極-北大-目標(biāo)檢測(cè)-深圳)
即可申請(qǐng)加入極市目標(biāo)檢測(cè)/圖像分割/工業(yè)檢測(cè)/人臉/醫(yī)學(xué)影像/3D/SLAM/自動(dòng)駕駛/超分辨率/姿態(tài)估計(jì)/ReID/GAN/圖像增強(qiáng)/OCR/視頻理解等技術(shù)交流群
每月大咖直播分享、真實(shí)項(xiàng)目需求對(duì)接、求職內(nèi)推、算法競(jìng)賽、干貨資訊匯總、與?10000+來(lái)自港科大、北大、清華、中科院、CMU、騰訊、百度等名校名企視覺(jué)開(kāi)發(fā)者互動(dòng)交流~

