Spaces:
Sleeping
Sleeping
not save img
Browse files- identify_cards.py +44 -51
- main.py +1 -1
identify_cards.py
CHANGED
@@ -31,6 +31,8 @@ SUIT_TEMPLATE_PATH = "templates/suits/"
|
|
31 |
SUITS_BY_COLOR = {"black": "S", "green": "C", "red": "H", "orange": "D"}
|
32 |
SCALE_STANDARD = 2032
|
33 |
|
|
|
|
|
34 |
|
35 |
def load_suit_templates(template_path):
|
36 |
templates = {}
|
@@ -60,7 +62,8 @@ def get_img_with_rect(img, rects, color, thickness):
|
|
60 |
|
61 |
|
62 |
def save_img_with_rect(filename, img, rects, color=(0, 255, 0), thickness=2):
|
63 |
-
|
|
|
64 |
|
65 |
|
66 |
def get_masks(hsv):
|
@@ -86,7 +89,8 @@ def find_best_contour(image, is_best):
|
|
86 |
mask, cv2.MORPH_CLOSE, kernel, iterations=2
|
87 |
)
|
88 |
|
89 |
-
|
|
|
90 |
contours, _ = cv2.findContours(
|
91 |
closed_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
|
92 |
)
|
@@ -167,7 +171,8 @@ def find_center_seal(image, bw, bh):
|
|
167 |
kernel = np.ones((7, 7), np.uint8)
|
168 |
closed_mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2)
|
169 |
|
170 |
-
|
|
|
171 |
contours, _ = cv2.findContours(
|
172 |
closed_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
|
173 |
)
|
@@ -321,12 +326,15 @@ def get_suit_from_image_rules(rank_image_patch, thresholds):
|
|
321 |
rank_image_patch, rank_image_patch, mask=text_mask
|
322 |
)
|
323 |
|
324 |
-
|
325 |
-
|
326 |
-
|
|
|
|
|
|
|
327 |
|
328 |
-
|
329 |
-
|
330 |
|
331 |
lab_patch = cv2.cvtColor(masked_char_image, cv2.COLOR_BGR2LAB)
|
332 |
avg_lab = cv2.mean(lab_patch, mask=text_mask)
|
@@ -405,7 +413,6 @@ def get_suit_from_color_rules(avg_lab, thresholds, timestamp=0):
|
|
405 |
|
406 |
def preprocess_img(img):
|
407 |
gray_region = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
408 |
-
debug_region = img.copy()
|
409 |
|
410 |
# --- ステップ1: カードマスクの作成 (変更なし) ---
|
411 |
_, card_mask = cv2.threshold(gray_region, 160, 255, cv2.THRESH_BINARY)
|
@@ -452,24 +459,6 @@ def filter_size(contours, scale, img):
|
|
452 |
max(0, y) : min(y + h, img.shape[0]),
|
453 |
max(0, x) : min(x + w, img.shape[1]),
|
454 |
]
|
455 |
-
|
456 |
-
# hsv_patch = cv2.cvtColor(no_padding_img, cv2.COLOR_BGR2HSV)
|
457 |
-
# s_channel = hsv_patch[:, :, 1]
|
458 |
-
# v_channel = hsv_patch[:, :, 2]
|
459 |
-
# mask_s = cv2.threshold(s_channel, 30, 255, cv2.THRESH_BINARY)[1]
|
460 |
-
# mask_v = cv2.threshold(v_channel, 210, 255, cv2.THRESH_BINARY_INV)[
|
461 |
-
# 1
|
462 |
-
# ]
|
463 |
-
text_mask = get_not_white_mask(no_padding_img)
|
464 |
-
# デバッグ用のフォルダがなければ作成
|
465 |
-
debug_dir = "debug_chars"
|
466 |
-
if not os.path.exists(debug_dir):
|
467 |
-
os.makedirs(debug_dir)
|
468 |
-
|
469 |
-
# マスクを使って元のカラー画像から文字部分のみを抽出
|
470 |
-
masked_char_image = cv2.bitwise_and(
|
471 |
-
no_padding_img, no_padding_img, mask=text_mask
|
472 |
-
)
|
473 |
res.append(
|
474 |
{
|
475 |
"img": cropped_img,
|
@@ -491,10 +480,6 @@ def filter_thickness(
|
|
491 |
cropped_img = candidate["img"]
|
492 |
|
493 |
text_mask = get_not_white_mask(no_padding_img)
|
494 |
-
# デバッグ用のフォルダがなければ作成
|
495 |
-
debug_dir = "debug_chars"
|
496 |
-
if not os.path.exists(debug_dir):
|
497 |
-
os.makedirs(debug_dir)
|
498 |
|
499 |
# マスクを使って元のカラー画像から文字部分のみを抽出
|
500 |
masked_char_image = cv2.bitwise_and(
|
@@ -504,12 +489,18 @@ def filter_thickness(
|
|
504 |
cropped_dist = cv2.distanceTransform(cropped_bin, cv2.DIST_L2, 3)
|
505 |
_, max_val, _, _ = cv2.minMaxLoc(cropped_dist)
|
506 |
|
507 |
-
|
508 |
-
|
509 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
510 |
|
511 |
-
|
512 |
-
|
513 |
|
514 |
print(
|
515 |
f" 候補 at ({candidate['pos']}) - 厚みスコア: {max_val:.2f} {timestamp}"
|
@@ -610,7 +601,8 @@ def find_rank_candidates(region_image, suit_templates, player_name, scale=1):
|
|
610 |
return []
|
611 |
|
612 |
preprocessed = preprocess_img(region_image)
|
613 |
-
|
|
|
614 |
|
615 |
contours, _ = cv2.findContours(
|
616 |
preprocessed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
|
@@ -729,21 +721,22 @@ def recognize_cards(region_image, suit_templates, player_name, trocr_pipeline):
|
|
729 |
{"name": card_name, "pos": candidate["pos"]}
|
730 |
)
|
731 |
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
|
|
|
|
|
|
|
|
|
|
742 |
)
|
743 |
-
cv2.imwrite(f"debug_detection_{player_name}.jpg", debug_region)
|
744 |
-
print(
|
745 |
-
f"{player_name} の検出結果を debug_detection_{player_name}.jpg に保存しました。"
|
746 |
-
)
|
747 |
return [c["name"] for c in recognized_ranks]
|
748 |
|
749 |
|
|
|
31 |
SUITS_BY_COLOR = {"black": "S", "green": "C", "red": "H", "orange": "D"}
|
32 |
SCALE_STANDARD = 2032
|
33 |
|
34 |
+
IS_DEBUG = False
|
35 |
+
|
36 |
|
37 |
def load_suit_templates(template_path):
|
38 |
templates = {}
|
|
|
62 |
|
63 |
|
64 |
def save_img_with_rect(filename, img, rects, color=(0, 255, 0), thickness=2):
|
65 |
+
if IS_DEBUG:
|
66 |
+
cv2.imwrite(filename, get_img_with_rect(img, rects, color, thickness))
|
67 |
|
68 |
|
69 |
def get_masks(hsv):
|
|
|
89 |
mask, cv2.MORPH_CLOSE, kernel, iterations=2
|
90 |
)
|
91 |
|
92 |
+
if IS_DEBUG:
|
93 |
+
cv2.imwrite(f"debug_mask{i}.jpg", closed_mask)
|
94 |
contours, _ = cv2.findContours(
|
95 |
closed_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
|
96 |
)
|
|
|
171 |
kernel = np.ones((7, 7), np.uint8)
|
172 |
closed_mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2)
|
173 |
|
174 |
+
if IS_DEBUG:
|
175 |
+
cv2.imwrite(f"debug_seal.jpg", closed_mask)
|
176 |
contours, _ = cv2.findContours(
|
177 |
closed_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
|
178 |
)
|
|
|
326 |
rank_image_patch, rank_image_patch, mask=text_mask
|
327 |
)
|
328 |
|
329 |
+
if IS_DEBUG:
|
330 |
+
# ユニークなファイル名を生成
|
331 |
+
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S_%f")
|
332 |
+
debug_filename = os.path.join(
|
333 |
+
debug_dir, f"masked_char_{timestamp}.png"
|
334 |
+
)
|
335 |
|
336 |
+
# 画像を保存
|
337 |
+
cv2.imwrite(debug_filename, masked_char_image)
|
338 |
|
339 |
lab_patch = cv2.cvtColor(masked_char_image, cv2.COLOR_BGR2LAB)
|
340 |
avg_lab = cv2.mean(lab_patch, mask=text_mask)
|
|
|
413 |
|
414 |
def preprocess_img(img):
|
415 |
gray_region = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
|
416 |
|
417 |
# --- ステップ1: カードマスクの作成 (変更なし) ---
|
418 |
_, card_mask = cv2.threshold(gray_region, 160, 255, cv2.THRESH_BINARY)
|
|
|
459 |
max(0, y) : min(y + h, img.shape[0]),
|
460 |
max(0, x) : min(x + w, img.shape[1]),
|
461 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
462 |
res.append(
|
463 |
{
|
464 |
"img": cropped_img,
|
|
|
480 |
cropped_img = candidate["img"]
|
481 |
|
482 |
text_mask = get_not_white_mask(no_padding_img)
|
|
|
|
|
|
|
|
|
483 |
|
484 |
# マスクを使って元のカラー画像から文字部分のみを抽出
|
485 |
masked_char_image = cv2.bitwise_and(
|
|
|
489 |
cropped_dist = cv2.distanceTransform(cropped_bin, cv2.DIST_L2, 3)
|
490 |
_, max_val, _, _ = cv2.minMaxLoc(cropped_dist)
|
491 |
|
492 |
+
if IS_DEBUG:
|
493 |
+
debug_dir = "debug_chars"
|
494 |
+
if not os.path.exists(debug_dir):
|
495 |
+
os.makedirs(debug_dir)
|
496 |
+
debug_dir = "debug_chars"
|
497 |
+
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S_%f")
|
498 |
+
debug_filename = os.path.join(
|
499 |
+
debug_dir, f"dist_char_{timestamp}.png"
|
500 |
+
)
|
501 |
|
502 |
+
# 画像を保存
|
503 |
+
cv2.imwrite(debug_filename, cropped_dist)
|
504 |
|
505 |
print(
|
506 |
f" 候補 at ({candidate['pos']}) - 厚みスコア: {max_val:.2f} {timestamp}"
|
|
|
601 |
return []
|
602 |
|
603 |
preprocessed = preprocess_img(region_image)
|
604 |
+
if IS_DEBUG:
|
605 |
+
cv2.imwrite(f"debug_ocr_preprocess_{player_name}.jpg", preprocessed)
|
606 |
|
607 |
contours, _ = cv2.findContours(
|
608 |
preprocessed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
|
|
|
721 |
{"name": card_name, "pos": candidate["pos"]}
|
722 |
)
|
723 |
|
724 |
+
if IS_DEBUG:
|
725 |
+
for card in recognized_ranks:
|
726 |
+
cv2.putText(
|
727 |
+
debug_region,
|
728 |
+
card["name"],
|
729 |
+
(card["pos"][0], card["pos"][1] - 10),
|
730 |
+
cv2.FONT_HERSHEY_SIMPLEX,
|
731 |
+
1.0,
|
732 |
+
(255, 255, 0),
|
733 |
+
2,
|
734 |
+
cv2.LINE_AA,
|
735 |
+
)
|
736 |
+
cv2.imwrite(f"debug_detection_{player_name}.jpg", debug_region)
|
737 |
+
print(
|
738 |
+
f"{player_name} の検出結果を debug_detection_{player_name}.jpg に保存しました。"
|
739 |
)
|
|
|
|
|
|
|
|
|
740 |
return [c["name"] for c in recognized_ranks]
|
741 |
|
742 |
|
main.py
CHANGED
@@ -127,7 +127,7 @@ async def analyze_image(image_paths: list[UploadFile]):
|
|
127 |
# )
|
128 |
# NumPy配列(メモリ上のデータ)から画像をデコード
|
129 |
file_bytes = await image_path.read()
|
130 |
-
print("file", file_bytes)
|
131 |
file_array = np.asarray(bytearray(file_bytes), dtype=np.uint8)
|
132 |
image = cv2.imdecode(file_array, cv2.IMREAD_COLOR)
|
133 |
# image = image_path.file
|
|
|
127 |
# )
|
128 |
# NumPy配列(メモリ上のデータ)から画像をデコード
|
129 |
file_bytes = await image_path.read()
|
130 |
+
# print("file", file_bytes)
|
131 |
file_array = np.asarray(bytearray(file_bytes), dtype=np.uint8)
|
132 |
image = cv2.imdecode(file_array, cv2.IMREAD_COLOR)
|
133 |
# image = image_path.file
|