python+opencv檢測圖片中二維碼

sas???發表於2018-08-09

緣起

需要檢測發票中二維碼的位置,以確定影像該怎麼旋轉,同時也可以為提取二維碼資訊創造先覺條件!(萬惡的需求!)

失敗的嘗試--opencv訓練大法

不感興趣的可跳過不看!

  • 參考原文:https://blog.csdn.net/qq_27063119/article/details/79247266
  • 解釋:原文作者是訓練檢測舌頭。。(蜜汁尷尬),先通過opencv自帶的人臉檢測cascade分類器進行人臉檢測然後疊加訓練的舌頭分類器完成舌頭的檢測任務。不多說。
  • 我的實踐:按照原作者的方法,換個資料集我來嘗試一下。
  • 正樣本:一波處理操作後得到以下樣本


    10780978-a1d32dd477d5f2ca.png
    image.png
  • 負樣本:一波騷操作後得到以下樣本


    10780978-e44096898e5d9926.png
    image.png
  • 訓練資料夾結構


    10780978-adf8e6650b0e8011.png
    image.png
  • 測試效果


    10780978-61084671efa81476.png
    image.png
  • 解釋:我解釋為訓練樣本太少,正樣本少,負樣本也少,原作者說負樣本的數量要多於正樣本很大一部分,然而我的負樣本確實比較少,但我按照模式識別的思想去思考一波,感覺這非常勉強。。。

成功的嘗試!

第一步:靈感的來源

第二步:消化以上實現效果的方法

經過一番瀏覽以後,作者自己就給出了總體的實現思路,如下:

  • 計算x方向和y方向上的Scharr梯度幅值表示
  • 將x-gradient減去y-gradient來顯示條形碼區域
  • 模糊並二值化影像
  • 對二值化影像應用閉運算核心
  • 進行系列的腐蝕、膨脹
  • 找到影像中的最大輪廓,大概便是條形碼
    作者最後的實現效果:


    10780978-139e43733ccc4f75.png
    image.png

    10780978-14d7943d8cd578da.png
    image.png

可以看出,思路異常清晰!效果也不錯,適合自己的需求。

第三步:觀察自己的圖片

簡單處理後是這樣的


10780978-6d75abf592faf66b.png
image.png
  • 分析:要識別二維碼,這個圖片當中顏色區分很明顯,所以首先需要把藍色以外的其他色調給去掉!

第四步:寫個小指令碼僅顯示藍色調

直接上程式碼:OnlyBlue.py

import numpy as np
import cv2
import argparse
# 藍色的範圍,不同光照條件下不一樣,可靈活調整
lower_blue = np.array([90, 90, 90])
upper_blue = np.array([130, 255, 255])
ap=argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True, help = "path to the image file")
args = vars(ap.parse_args())

image = cv2.imread(args["image"])
hsv=cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

# 3.inRange():介於lower/upper之間的為白色,其餘黑色
mask = cv2.inRange(hsv, lower_blue, upper_blue)

# 4.只保留原圖中的藍色部分
res = cv2.bitwise_and(image, image, mask=mask)

cv2.imshow('image', image)
cv2.imshow('mask', mask)
cv2.imshow('res', res)
cv2.imwrite('blue.jpg',res)

cv2.waitKey(0)

以上程式碼參考自:傳送門
也是很好的一篇部落格,感興趣的可以看看

  • 解釋:由於我這裡是比較淺的藍色調,因此更改了原來程式碼當中的上下閾值定義部分,如下:
# 藍色的範圍,不同光照條件下不一樣,可靈活調整
lower_blue = np.array([90, 90, 90])
upper_blue = np.array([130, 255, 255])
  • 效果


    10780978-292916417a06242e.png
    image.png

    這效果我感覺後面已經可以處理了,遂沒有再去調閾值引數。

第五步:寫檢測二維碼的程式指令碼

直接上程式碼:

import numpy as np
import argparse
import cv2
ap=argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True, help = "path to the image file")
args = vars(ap.parse_args())

image = cv2.imread(args["image"])
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)

cv2.imshow("gradient",gradient)
#原本沒有過濾顏色通道的時候,這個高斯模糊有效,但是如果進行了顏色過濾,不用高斯模糊效果更好
#blurred = cv2.blur(gradient, (9, 9))
(_, thresh) = cv2.threshold(gradient, 225, 255, cv2.THRESH_BINARY)
cv2.imshow("thresh",thresh)
cv2.imwrite('thresh.jpg',thresh)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 21))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
cv2.imshow("closed",closed)
cv2.imwrite('closed.jpg',closed)

closed = cv2.erode(closed, None, iterations = 4)
closed = cv2.dilate(closed, None, iterations = 4)
cv2.imwrite('closed1.jpg',closed)

img,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.imwrite("final.jpg",image)
cv2.imshow("Image", image)

cv2.waitKey(0)

關鍵錯誤bug解決

原作者文中的程式碼執行起來有些問題,主要以下兩個

第六步:測試效果

10780978-7fcd721f55e444a8.png
image.png

效果很成功!

相關文章