python: 画像から麻雀牌を抽出してみる

プログラミング
スポンサーリンク




こんにちは、おみです。

私は麻雀は好きなのですが、点数計算を覚える域までは達していないので友人とする時にアプリで点数計算を行おうとしたことがあります。

ですが、今世の中にあるそういうアプリは精度が悪すぎて使い物になりません。

そこで、自分で作ってみることにしました。

今回は、色々なパターンの画像から牌を抽出する方法について考えていこうと思います。

スポンサーリンク

前提条件

認識を行う画像は、

  1. 麻雀牌は白色(逆にそれ以外はあるのか…?)
  2. 画像中に麻雀牌より大きな白色の領域はない
  3. 牌の間に隙間はほとんどない

とします。

また、認識させる牌の並べ方のルールですが、

  1. アガリ牌は横向きにして鳴いていない手配の右に置く
  2. 鳴いて作った面子はアガリ牌の右に並べる

とします。

テスト画像

とりあえず、前回射影変換でも使用した画像をしようしたいと思います。

https://moimoiblog.com/explanation/python-explanation/python-projection-transform/

抽出方法

前提条件より

麻雀牌は白色で隙間はなく、それより大きな白色の領域は存在しない

 →「画像内で一番大きな白い領域」

を取り出せば、麻雀牌を抽出できます。

ソースに書き起こしてみる

import cv2
import os

# 画像のパスを指定(はいの画像のパスを指定してください)
file_path = "test.png"

# 画像が存在するかを確認
if not os.path.exists(file_path):
    print("画像が存在しません。")

# 画像を読み込む
img = cv2.imread(file_path)

# グレースケールに変換
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# ガウシアンフィルターをかける
gauss = cv2.GaussianBlur(gray, (5, 5), 0)

# 2値化する
thres = cv2.threshold(gauss, 200, 255, cv2.THRESH_BINARY)[1]

# 2値化した画像を表示する
cv2.imshow("thres", thres)


# 輪郭のみを検出する
cons = cv2.findContours(thres,
                        cv2.RETR_LIST,
                        cv2.CHAIN_APPROX_NONE)[0]

if len(cons) > 0:
    # 輪郭を抽出できた場合の処理
    # 1つ目の領域を最大の面積とする
    max_con = cons[0]

    # 取り出した輪郭が複数の場合、絞り込みを行う
    if len(cons) > 1:
        for con in cons[1:]:
            # 一番大きいかを判定
            if cv2.contourArea(max_con) < cv2.contourArea(con):
                max_con = con

    # 輪郭を描画する
    cv2.polylines(img, max_con, True, (0, 0, 155), 20)
else:
    # 輪郭を抽出できなかった場合の処理
    print('画像内に牌データは存在しませんでした。')

# 画像を表示する
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

実行結果

無事に麻雀牌を抽出することができました。

次回

こいつを14個に分割し、1つ1つの牌として取り出します。

コメント

タイトルとURLをコピーしました