見出し画像

節分で豆を年齢数だけ数えるのがめんどくさいのでPythonに数えてもらった

ちょっとタイトル詐欺で申し訳ないのですが,自分で数えた方が明らかに早いです.  ちょっとしたお遊びと思ってご覧ください.

節分は,年齢の数(あるいは+1)だけ豆を食べると良いといいますよね.
私は現在25歳なので,25個食べることになります.お皿に出してみました.

soybeans.png

しかし,豆って数えづらいですよね.どこまで数えたのか分からなくなってしまいます.  そこでPythonに数えてもらうことにしました.

次のライブラリをインポートします.

import cv2
import numpy as np
import matplotlib.pyplot as plt

画像を読み込みましょう.お皿が映ると一気に難易度が増すので豆の部分だけクロップしています.

datapath = './soybeans.png'
img_raw = cv2.imread(datapath, 1)
img_raw = cv2.cvtColor(img_raw, cv2.COLOR_BGR2RGB)  # openCV GBRをmatplotlib RGBに変換
plt.imshow(img_raw)

豆の皮がめくれている部分があり,このままだとノイズになってしまいます.そこでフィルタを強めにかけて画像をぼかしました.

img_blur = cv2.medianBlur(img_raw, ksize=25)
plt.imshow(img_blur)

次に,画像をグレースケールにします.大豆は茶色っぽいので,RGBのうちRだけ取り出すことにします.

plt.imshow(img_blur[:, :, 0], cmap='gray')
plt.colorbar()

さて,2値化処理をかけたいので,閾値を決めるために画素値のヒストグラムを見てみましょう.

plt.hist(img_blur[:, :, 0].flatten(), bins=np.linspace(0, 255, 100))

ヒストグラムをみながら,実際に閾値処理をかけてみてちょうどよかった210あたりで2値化します.

_, img_thresh = cv2.threshold(img_blur[:, :, 0], 210, 255, cv2.THRESH_BINARY)
plt.imshow(img_thresh, cmap='gray')

このままだと,まだ二つの豆がつながってしまっている箇所などが目立ちますね.そこで豆の領域を縮小(Erosion)して,つながっている箇所を切断しようと思います.

kernel = np.ones((5, 5), np.uint8)
img_erode = cv2.erode(img_thresh, kernel, iterations=10)
plt.imshow(img_erode, cmap='gray')

良い感じですね.あとはオブジェクトの輪郭を検出するOpenCVのfindContoursメソッドを使用します.

img = img_raw.copy()  # 元画像のコピーに描き込む
contours, hierarchy = cv2.findContours(img_erode, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)

cnt = 0
for contour in contours:
    if len(contour) > 0:

        # オブジェクトの大きさでフィルタリング(ここはマニュアルです...)
        if cv2.contourArea(contour) < 1000 or cv2.contourArea(contour) > 50000 :
            continue

        cnt += 1
        cv2.polylines(img, contour, True, (255, 0, 0), 10)  # 輪郭を描く
        
        # オブジェクトの重心に何個目かを示すアノテーション
        M = cv2.moments(contour)
        cx = M["m10"] / M["m00"]
        cy = M["m01"] / M["m00"]
        plt.annotate(s=cnt, xy=(cx, cy), color='k')

plt.imshow(img)
print(cnt)   # 28個

うん,だいぶ大雑把でしたができているようです!
Pythonの出力がなかなか25になってくれない!とイライラしていたら,普通に28個ありました.しっかり数え間違えてしまっていましたね.

処理をまとめるとこんな感じです.

今回のコードは以下のウェブサイトから大半を参考にさせていただきました(本当にありがとうございます)!

というわけで,今回はPythonに豆の個数を数えてもらいました.
(画像処理も相変わらずドがつくほどの素人につき,何か間違いがあったら大変申し訳ございません.)

試しているうちに日付を超えてしまいましたが,年齢層が高めの方には特にオススメですので(やめろ),来年はぜひ試してみてください!

この記事が参加している募集

やってみた

この記事が気に入ったらサポートをしてみませんか?