GEEKY TRAVELLER - Detecting Barcodes in Images with Python and OpenCV
opencvにも手を出してみようと使い方・考え方を知るために上記サイトで紹介してあるコードを自分で試しながら書いてみます。
行列とか画像処理とか知らないので、雰囲気で理解していっています。
環境
- VSCode
- python 3.11.0
使用ライブラリ
- numpy
- opencv-python
バーコード検出
画像を読み込む
import numpy as np import cv2 file = "./barcode.jpg" #画像を読み込む img = cv2.imread(file) #画像を表示。画面は表示されるけど何かを待っている cv2.imshow("original", img) #これを呼び出すと画像が表示された cv2.waitKey() #キー押下しても破棄を明示しないと閉じない cv2.destroyAllWindows()
画像表示部はあとでたくさん使うので関数にしておきます
def showImg(title, img): cv2.imshow(title, img) cv2.waitKey() cv2.destroyAllWindows()
グレースケールにする
cv2.cvtColor
で簡単にできました。
第2引数に膨大なパターンを渡せるようです。
#グレースケール gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) showImg("gray scale", gray)
ゾーベルフィルタをかける
ここからすでに何がしたいのかわかりません。
X方向、Y方向にゾーベルフィルタ*1とやらをかけているようです。
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) showImg("gradX", gradX) showImg("gradY", gradY)
結果の差をとる
こうすることで、水平方向のグラデーションが高く、垂直方向のグラデーションが低い画像となるようです。
(言っている意味は分からないけど)画像が変わっているのはわかります。
gradient = cv2.subtract(gradX, gradY) showImg("gradient", gradient) gradient = cv2.convertScaleAbs(gradient) showImg("gradient", gradient)
ぼかして閾値を設定、2値化する
ぼかすことでノイズを滑らかにし、それに対して閾値を指定して2値化しています。
blurred = cv2.blur(gradient, (9, 9)) showImg("blurred", blurred) (_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY) showImg("thresh", thresh)
なんだか胡散臭くなってきました。
矩形カーネルでバー間のギャップを埋める
もはや日本語に訳しても何言ってるかわかりません。
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7)) closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) showImg("closed", closed) closed = cv2.erode(closed, None, iterations = 4) showImg("closed", closed) closed = cv2.dilate(closed, None, iterations = 4) showImg("closed", closed)
バーコードの輪郭を見つける
もはやラストまで一気にコピペです。
(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(img, [box], -1, (0, 255, 0), 3) showImg("last", img)
結果
見つけられませんでした。
おしまい
人間が見て認識するのと近しい精度を出すのって簡単ではないということはよくわかりました。
いつか検出できるようにリベンジしたいところ。
追記
ちょっとパラメータいじったらこんなのになった。 python入門Top
*1:ゾーベルフィルタ:1次微分により画像のエッジ検出をするための演算の一つ