春のパン祭りシール点数集計の続きです。
今回の内容
前回、春のパン祭り画像から点数文字の輪郭を取得できましたが、まだ1画像でしか試していないので、 他の画像でもやってみます。
関数化
いつも通りの手順ですが、内容が増えてきたので、関数化しておきたいと思います。
関数の内容は、
- 画像のリサイズ
- 2値化
- 輪郭検出
になります。
リサイズについて
画像のリサイズについては、今までは固定の縮小率にしていましたが、今回はリサイズ後の画像サイズの目標を設定して、それに向けたリサイズをするようにします。
前回も少し考えたように、
- シール台紙は画像全体の縦横半分程度は写るようにする
- シールが縦横に5個ずつ並ぶ
という前提条件を設定して、あとシール領域の解像度の目標を決めたいですが、
前回の画像を見返してみると、リサイズ後でだいたい縦横80pixelずつでした。
ということで、
- 解像度は縦横それぞれ80x5x2=800pixel以上
にリサイズするようにしたいと思います。
2値化について
前回は2値化の後にClosing処理で細かい輪郭の除去をしていましたが、輪郭検出後の面積でのフィルタリングでも十分そうだったので、Closing処理は省いてみます。
import cv2 import numpy as np %matplotlib inline from matplotlib import pyplot as plt # image: Input image, BGR format def calculate_harupan(image, debug): h, w, chs = image.shape if h > 800 or w > 800: k = 800.0/h if w > h else 800.0/w else: k = 1.0 img = cv2.resize(image, None, fx=k, fy=k, interpolation=cv2.INTER_AREA) if debug: print('Resized to ', img.shape) hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) ret, th_hue = cv2.threshold(hsv[:,:,0], 135, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(th_hue, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) indices0 = [i for i,hier in enumerate(hierarchy[0,:,:]) if hier[3] == -1] indices1 = [i for i,hier in enumerate(hierarchy[0,:,:]) if hier[3] in indices0] if debug: print('Number of contours: ', len(contours)) print('Number of indices0: ', len(indices0), 'indices1: ', len(indices1)) contours1 = [contours[i] for i in indices1] contours1_filtered = [ctr for ctr in contours1 if cv2.contourArea(ctr) > 800*800/4000] if debug: return contours1_filtered, img else: return contours1_filtered
実践
では、各画像に適用してみます。
img1 = cv2.imread('harupan_190428_1.jpg') img2 = cv2.imread('harupan_190428_2.jpg') img3 = cv2.imread('harupan_200317_1.jpg') img4 = cv2.imread('harupan_210227_2.jpg') img5 = cv2.imread('harupan_210402_1.jpg') img6 = cv2.imread('harupan_210402_2.jpg') img7 = cv2.imread('harupan_210414_1.jpg') imgs = [img1, img2, img3, img4, img5, img6, img7] plt.figure(figsize=(20,15), dpi=100) for i,im in enumerate(imgs): ctrs, img_resize = calculate_harupan(im, True) img_ctrs = cv2.drawContours(img_resize, ctrs, -1, (0,255,0), 2) plt.subplot(241+i), plt.imshow(cv2.cvtColor(img_ctrs, cv2.COLOR_BGR2RGB)), plt.xticks([]), plt.yticks([]) plt.show()
Resized to (1067, 800, 3)
Number of contours: 2534
Number of indices0: 1264 indices1: 1048
Resized to (1067, 800, 3)
Number of contours: 2427
Number of indices0: 1217 indices1: 1049
Resized to (1067, 800, 3)
Number of contours: 1836
Number of indices0: 434 indices1: 630
Resized to (1067, 800, 3)
Number of contours: 1021
Number of indices0: 295 indices1: 683
Resized to (1067, 800, 3)
Number of contours: 1689
Number of indices0: 480 indices1: 1063
Resized to (1067, 800, 3)
Number of contours: 1320
Number of indices0: 367 indices1: 844
Resized to (1067, 800, 3)
Number of contours: 873
Number of indices0: 424 indices1: 392
いい感じです。
気になるのは、
- 1番目の画像、シール部分での光の反射で'0'の文字が1つ検出できていない
- 3番目の画像、点数文字以外の輪郭が残っている
おそらく台紙が画像全体に写っていて、細かい文字の面積も大きくなってしまったため
というところ。
光の反射は対処が難しいなー...
どうしようか。
ここまで
今回はここまでにします。
一部課題はありますが、おおむね前回の方針でよさそうということで。
次回はテンプレートマッチングをやっていきたいと思います。