質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.42%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

PyCharm

エディター・開発ツール

Q&A

解決済

1回答

1008閲覧

牌譜検定用麻雀牌効率ツールにおける、牌が認識されるものの、一部テキストに変換できない点について

roasis93

総合スコア1

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

PyCharm

エディター・開発ツール

0グッド

0クリップ

投稿2023/05/03 04:28

実現したいこと

・麻雀の牌譜検定の為のツール作成
・画面キャプチャーで牌をスキャン
・用意した牌の画像と照らし合わせ、重複した箇所に赤い四角で囲む
・その後に、牌の画像の名前を出力(5m等)
・テキストとして5m6m2p3p7s等になる
・何か解決に向けてアイディアがありましたらお教え願いたいです。

前提

プログラミング初心者です。
Pycharmを用いてpython3で作成しています。

発生している問題・エラーメッセージ

重複した画像に対して、テキストとして表示されない。

例:5m5m6m7m8m4p5p5s4s6s7s8s9sの牌を読み取らせているのに、出力結果は5m6m7m8m4p5p5s4s6s7s8s9sとなる。

該当のソースコード

python3

1from typing import List 2 3import pyautogui 4import cv2 5import numpy as np 6 7# 画面キャプチャーの実行 8image = pyautogui.screenshot() 9 10# 画像の保存 11image.save('screenshot.png') 12 13# 入力画像の読み込み 14img = cv2.imread('screenshot.png') 15 16# テンプレート画像のファイルパスをリストで用意 17template_file_paths = ['5m.png', '6m.png', '7m.png', '8m.png', '4p.png', '5p.png', '5s.png', '4s.png', '5s.png', '6s.png', '7s.png', '8s.png', '9s.png'] 18 19# 各テンプレート画像について処理 20detected_templates: list[str] = [] 21for template_file_path in template_file_paths: 22 # テンプレート画像の読み込み 23 template = cv2.imread(template_file_path) 24 25 # テンプレートマッチングの実行 26 result = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED) 27 28 # 最大のマッチング位置を検出 29 threshold = 0.8 # 類似度の閾値 30 locations = np.where(result >= threshold) 31 locations = list(zip(*locations[::-1])) 32 33 # マッチング位置を描画 34 for loc in locations: 35 h, w = template.shape[:2] 36 top_left = loc 37 bottom_right = (top_left[0] + w, top_left[1] + h) 38 cv2.rectangle(img, top_left, bottom_right, (0, 0, 255), 2) 39 40 # マッチングした画像のテンプレート画像のファイル名を取得 41 template_file_name = template_file_path.split('/')[-1] # ファイル名のみ抽出 42 43 # 新しく検出した画像に対してのみファイル名を出力 44 if template_file_name in detected_templates: 45 continue # 既に検出したものはカウントしない 46 else: 47 detected_templates.append(template_file_name) 48 count = len(locations) 49 if count > 0: 50 print((template_file_name[:-4]) * min(count, 1), end='') 51 52# 結果を表示 53cv2.imshow('result', img) 54cv2.waitKey(0) 55 56# ウィンドウを閉じる 57cv2.destroyAllWindows()

試したこと

検知されるごとに、テキストを出力する。(重複していない牌に関しても重複して表示され失敗)
ChatGPTに見てもらう
4時間粘ったものの進展無し

考察

ファイル名で指定している為ややこしいことになっている(?)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

melian

2023/05/03 05:08

print((template_file_name[:-4]) * min(count, 1), end='') min(count, 1) としているので、同じ牌がある場合には最初の牌以外は全て無視されてしまうことになります。
roasis93

2023/05/03 13:49 編集

コメント本当にありがとうございます。 printの後は色々試してみたんですが、重複して返してしまうんですよね。 回答くださった方の print(''.join([item[1] for item in sorted(detected_templates)])) ですと、識別したい牌が 5m5m6m7m8m4p5p4s5s6s7s8s9sの場合、 5m5m5m5m5m5m5m5m5m5m5m5m5m5m5m5m5m5m6m6m6m6m6m6m6m6m6m6m6m7m7m7m7m7m7m7m7m7m8m8m8m8m8m8m8m8m8m8m8m4p4p4p4p4p5p4s4s4s4s4s5s5s5s5s5s6s6s6s6s6s7s7s7s7s7s8s8s8s8s8s9s9s9s9s9s9s9sと出力されてしまいます。 1つしかない画像であっても、重複して検知されてしまっているのでしょうか。
guest

回答1

0

ベストアンサー

仮に、画像から検知したそれぞれのテンプレート牌画像に対応する文字を、検知したエリアのX座標昇順に左から順に並べた文字列を出力させたいという場合:

from typing import List import pyautogui import cv2 import numpy as np def nms(rects, scores, overlapth): if len(rects) <= 1: return rects rects = rects.astype("float") x1, y1, x2, y2 = np.squeeze(np.split(rects, 4, axis=1)) area = (x2 - x1 + 1) * (y2 - y1 + 1) indices = np.argsort(scores) selected = [] while len(indices) > 0: last = len(indices) - 1 selected_index = indices[last] remaining_indices = indices[:last] selected.append(selected_index) i_x1 = np.maximum(x1[selected_index], x1[remaining_indices]) i_y1 = np.maximum(y1[selected_index], y1[remaining_indices]) i_x2 = np.minimum(x2[selected_index], x2[remaining_indices]) i_y2 = np.minimum(y2[selected_index], y2[remaining_indices]) i_w = np.maximum(0, i_x2 - i_x1 + 1) i_h = np.maximum(0, i_y2 - i_y1 + 1) overlap = (i_w * i_h) / area[remaining_indices] indices = np.delete( indices, np.concatenate(([last], np.where(overlap > overlapth)[0])) ) return rects[selected].astype("int") # 画面キャプチャーの実行 image = pyautogui.screenshot() # 画像の保存 image.save('screenshot.png') # 入力画像の読み込み img = cv2.imread('screenshot.png') # テンプレート画像のファイルパスをリストで用意 # テンプレート画像のファイルパスをリストで用意 template_file_paths = ['5m.png', '6m.png', '7m.png', '8m.png', '4p.png', '5p.png', '5s.png', '4s.png', '5s.png', '6s.png', '7s.png', '8s.png', '9s.png'] # 各テンプレート画像について処理 detected_templates: list[str] = [] for template_file_path in template_file_paths: # テンプレート画像の読み込み template = cv2.imread(template_file_path) mime_data = 0 # テンプレートマッチングの実行 result = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED) # 最大のマッチング位置を検出 threshold = 0.8 # 類似度の閾値 locations = np.where(result >= threshold) scores = result[locations] rects = [] h, w = template.shape[:2] for y, x in zip(*locations): rects.append([x, y, x + w - 1, y + h - 1]) rects = nms(rects, scores, overlap=0.6) for x1, y1, x2, y2 in rects: cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) for rect in rects: template_fime_name = template_file_path.split('/')[-1] detected_templates.append((tuple(rect), template_fime_name[:-4])) print(''.join([item[1] for item in sorted(detected_templates)])) cv2.imshow('result', img) cv2.waitKey(0) # ウィンドウを閉じる cv2.destroyAllWindows()

参考:ttps://pystyle.info/opencv-non-maximum-suppression/
AIはつかってません

投稿2023/05/03 05:44

編集2023/05/09 13:35
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

roasis93

2023/05/03 13:53

コメントありがとうござます。 本当に助かります。 printの後は試行錯誤をしているんですが、マッチングに対しての理解が薄く、頓挫している状況です。 修正して頂いた回答者様のプログラムを実行したところ、 5m5m5m5m5m5m5m5m5m5m5m5m5m5m5m5m5m5m6m6m6m6m6m6m6m6m6m6m6m7m7m7m7m7m7m7m7m7m8m8m8m8m8m8m8m8m8m8m8m4p4p4p4p4p5p4s4s4s4s4s5s5s5s5s5s6s6s6s6s6s7s7s7s7s7s8s8s8s8s8s9s9s9s9s9s9s9sと、1つの牌であっても複数出力されてしまうんですよね。 この問題は以前から発生していて、解決策が全く思いつかない(申し訳ない)ので、アイディアを頂けたらこの上ない幸せです。
退会済みユーザー

退会済みユーザー

2023/05/05 07:56

同じ位置の画像を重複して検知しちゃってるんでしょ。 ググってnmsを使ってみたコードに修正した(うまくいくかはわかりません)
roasis93

2023/05/09 00:03

ありがとうございます!解決しました! nmsについて詳しく調べ、overlapの数値を上昇させたところ、うまく画像認識をすることができました! 懇切丁寧にありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.42%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問