""" Inspection script to calibrate exact bounding boxes for: - 5 Player cards (left vertical column) - 5 Opponent cards (right vertical column) on the DirtyLeague Battle Screen (3840x2050 design resolution). """ import os import cv2 import numpy as np from card_embedder import CardEmbedder # Normalized relative coordinates (rx1, ry1, rx2, ry2) for 3840x2050 # Calibrated from actual 4K battle screenshot PLAYER_CARD_SLOTS = [ # Slot 1 (top left) (0.226, 0.150, 0.294, 0.278), # Slot 2 (0.226, 0.295, 0.294, 0.423), # Slot 3 (0.226, 0.440, 0.294, 0.568), # Slot 4 (0.226, 0.585, 0.294, 0.713), # Slot 5 (bottom left) (0.226, 0.730, 0.294, 0.858), ] OPPONENT_CARD_SLOTS = [ # Slot 1 (top right) (0.693, 0.150, 0.761, 0.278), # Slot 2 (0.693, 0.295, 0.761, 0.423), # Slot 3 (0.693, 0.440, 0.761, 0.568), # Slot 4 (0.693, 0.585, 0.761, 0.713), # Slot 5 (bottom right) (0.693, 0.730, 0.761, 0.858), ] def extract_cards(frame: np.ndarray): fh, fw = frame.shape[:2] player_crops = [] opponent_crops = [] for rx1, ry1, rx2, ry2 in PLAYER_CARD_SLOTS: x1, y1 = int(rx1 * fw), int(ry1 * fh) x2, y2 = int(rx2 * fw), int(ry2 * fh) player_crops.append(frame[y1:y2, x1:x2]) for rx1, ry1, rx2, ry2 in OPPONENT_CARD_SLOTS: x1, y1 = int(rx1 * fw), int(ry1 * fh) x2, y2 = int(rx2 * fw), int(ry2 * fh) opponent_crops.append(frame[y1:y2, x1:x2]) return player_crops, opponent_crops def main(): img_path = os.path.join("dataset", "raw", "dl_screen_20260910_233743_310.png") if not os.path.exists(img_path): print(f"[ERROR] Sample battle screenshot not found at: {img_path}") return frame = cv2.imread(img_path) fh, fw = frame.shape[:2] print(f"\nAnalyzing battle frame resolution: {fw}x{fh}") player_crops, opponent_crops = extract_cards(frame) os.makedirs("debug_cards", exist_ok=True) embedder = CardEmbedder() print("\n--- Player Cards (Left Column 1..5) ---") for i, crop in enumerate(player_crops, 1): crop_path = os.path.join("debug_cards", f"player_card_{i}.png") cv2.imwrite(crop_path, crop) vec = embedder.embed(crop) print(f" Player Slot #{i}: {crop.shape[1]}x{crop.shape[0]}px | Vector norm: {np.linalg.norm(vec):.4f} | Saved to: {crop_path}") print("\n--- Opponent Cards (Right Column 1..5) ---") for i, crop in enumerate(opponent_crops, 1): crop_path = os.path.join("debug_cards", f"opponent_card_{i}.png") cv2.imwrite(crop_path, crop) vec = embedder.embed(crop) print(f" Opponent Slot #{i}: {crop.shape[1]}x{crop.shape[0]}px | Vector norm: {np.linalg.norm(vec):.4f} | Saved to: {crop_path}") # Draw visual overlay on whole frame annotated = frame.copy() for i, (rx1, ry1, rx2, ry2) in enumerate(PLAYER_CARD_SLOTS, 1): x1, y1 = int(rx1 * fw), int(ry1 * fh) x2, y2 = int(rx2 * fw), int(ry2 * fh) cv2.rectangle(annotated, (x1, y1), (x2, y2), (0, 255, 0), 3) cv2.putText(annotated, f"Player #{i}", (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) for i, (rx1, ry1, rx2, ry2) in enumerate(OPPONENT_CARD_SLOTS, 1): x1, y1 = int(rx1 * fw), int(ry1 * fh) x2, y2 = int(rx2 * fw), int(ry2 * fh) cv2.rectangle(annotated, (x1, y1), (x2, y2), (0, 0, 255), 3) cv2.putText(annotated, f"Enemy #{i}", (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 0, 255), 2) preview_path = os.path.join("debug_cards", "annotated_battle_slots.png") cv2.imwrite(preview_path, cv2.resize(annotated, (1920, 1025))) print(f"\n[SUCCESS] Full annotated battle preview saved to: {preview_path}") if __name__ == "__main__": main()