import pygetwindow as gw # Get size & coords of specific window with It's handle(hwnd), not title from pywinauto import Desktop # Get size & coords of specific window with It's title *USE THIS!!!* from mss import mss # Capture windows with given coords import cv2 # You know what It is import numpy as np # sure import time from skimage.metrics import structural_similarity as ssim def resize_with_ratio(image, scale=1.5, inter=cv2.INTER_LINEAR): # 이미지 크기 가져오기 (h, w) = image.shape[:2] # 너비와 높이를 1.5배로 확대 new_size = (int(w * scale), int(h * scale)) # 리사이즈 적용 resized = cv2.resize(image, new_size, interpolation=inter) return resized def pad_to_match_size(card1, card2): # 카드 1과 카드 2의 크기 확인 h1, w1 = card1.shape[:2] h2, w2 = card2.shape[:2] # 두 카드의 최대 너비와 높이 계산 max_h = max(h1, h2) max_w = max(w1, w2) # 카드 1에 패딩 추가 (상하좌우에 패딩을 균일하게 추가) pad_top_1 = (max_h - h1) // 2 pad_bottom_1 = max_h - h1 - pad_top_1 pad_left_1 = (max_w - w1) // 2 pad_right_1 = max_w - w1 - pad_left_1 padded_card1 = cv2.copyMakeBorder(card1, pad_top_1, pad_bottom_1, pad_left_1, pad_right_1, cv2.BORDER_CONSTANT, value=[0, 0, 0]) # 카드 2에 패딩 추가 pad_top_2 = (max_h - h2) // 2 pad_bottom_2 = max_h - h2 - pad_top_2 pad_left_2 = (max_w - w2) // 2 pad_right_2 = max_w - w2 - pad_left_2 padded_card2 = cv2.copyMakeBorder(card2, pad_top_2, pad_bottom_2, pad_left_2, pad_right_2, cv2.BORDER_CONSTANT, value=[0, 0, 0]) return padded_card1, padded_card2 # def compare_cards(card1, card2): #============================================= L2 norm # resized_card1, resized_card2 = pad_to_match_size(card1, card2) # return cv2.norm(resized_card1, resized_card2, cv2.NORM_L2) # def compare_cards(card1, card2): #============================================= ORB # orb = cv2.ORB_create() # # 카드에서 특징점 검출 # kp1, des1 = orb.detectAndCompute(card1, None) # kp2, des2 = orb.detectAndCompute(card2, None) # # BFMatcher로 특징점 매칭 # bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) # matches = bf.match(des1, des2) # # 매칭 결과를 거리 기준으로 정렬 # matches = sorted(matches, key=lambda x: x.distance) # # 거리 합산으로 차이 계산 (거리가 클수록 더 많은 차이) # return sum([match.distance for match in matches]) # def compare_cards(card1, card2): #============================================= 정적배경차분 # resized_card1, resized_card2 = pad_to_match_size(card1, card2) # # 이미지 차이 계산 # diff = cv2.absdiff(resized_card1, resized_card2) # # 차이가 나는 픽셀의 합계를 계산 # difference_score = np.sum(diff) # return difference_score # def compare_cards(card1, card2): #============================================= Canny edge detection # resized_card1, resized_card2 = pad_to_match_size(card1, card2) # # Canny Edge Detection 적용 # edges1 = cv2.Canny(resized_card1, 30, 150) # edges2 = cv2.Canny(resized_card2, 30, 150) # # 이미지 차이 계산 (엣지 차이) # diff = cv2.absdiff(edges1, edges2) # # 차이가 나는 픽셀의 합계를 계산 # difference_score = np.sum(diff) # return difference_score # def compare_cards(card1, card2): #============================================= 히스토그램 비교 # resized_card1, resized_card2 = pad_to_match_size(card1, card2) # # 히스토그램 계산 # hist1 = cv2.calcHist([resized_card1], [0], None, [256], [0, 256]) # hist2 = cv2.calcHist([resized_card2], [0], None, [256], [0, 256]) # # 히스토그램을 정규화 # hist1 = cv2.normalize(hist1, hist1) # hist2 = cv2.normalize(hist2, hist2) # # 히스토그램 차이 계산 (Chi-Square 비교) # score = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CHISQR) # return score # def compare_cards(card1, card2): #============================================= 템플릿 매칭 # resized_card1, resized_card2 = pad_to_match_size(card1, card2) # # 템플릿 매칭 # result = cv2.matchTemplate(resized_card1, resized_card2, cv2.TM_CCOEFF_NORMED) # # 매칭 값 (1에 가까울수록 유사, 0에 가까울수록 차이) # min_val, max_val, _, _ = cv2.minMaxLoc(result) # return max_val # def compare_cards(card1, card2): #============================================= 로그적용 정적배경차분 # resized_card1, resized_card2 = pad_to_match_size(card1, card2) # # LoG 필터 적용 # log_card1 = cv2.Laplacian(cv2.GaussianBlur(resized_card1, (3, 3), 0), cv2.CV_64F) # log_card2 = cv2.Laplacian(cv2.GaussianBlur(resized_card2, (3, 3), 0), cv2.CV_64F) # # log_card1 = cv2.Laplacian(resized_card1, cv2.CV_64F) # # log_card2 = cv2.Laplacian(resized_card2, cv2.CV_64F) # # 이미지 차이 계산 # diff = cv2.absdiff(log_card1, log_card2) # # 차이 합계 계산 # difference_score = np.sum(diff) # return difference_score def compare_cards(card1, card2): #============================================= SSIM resized_card1, resized_card2 = pad_to_match_size(card1, card2) # SSIM 비교 (grayscale로 변환한 후) ssim_score, _ = ssim(resized_card1, resized_card2, full=True) return ssim_score target_window = "S22 Ultra" windows = Desktop(backend="uia").windows() selected_window = None for w in windows: if target_window.lower() in w.window_text().lower(): # 대소문자 구분 없이 비교 selected_window = w break if selected_window != None: rect = selected_window.rectangle() monitor_coords = {"top": rect.top, "left": rect.left, "width": rect.width(), "height": rect.height()} with mss() as sct: while True: rect = selected_window.rectangle() monitor_coords = {"top": rect.top, "left": rect.left, "width": rect.width(), "height": rect.height()} sct_img = sct.grab(monitor_coords) img = np.array(sct_img) # Now we're gonna do some CV things # Preprocessing gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray, (5, 5), 0) _, thresh = cv2.threshold(blur, 245, 255, cv2.THRESH_BINARY_INV) kernel = np.ones((3, 3), np.uint8) thresh = cv2.erode(thresh, kernel, iterations=1) _, thresh = cv2.threshold(thresh, 100, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # Find contour contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cv2.imshow("Preprocessed", thresh) cards = [] for i, cnt in enumerate(contours): x, y, w, h = cv2.boundingRect(cnt) if 60 < w < 200 and 100 < h < 300: # 카드 크기 aspect_ratio = float(w) / h if 0.5 < aspect_ratio < 1.0: # 카드 비율 card_gray = gray[y:y+h, x:x+w] card_resized = resize_with_ratio(card_gray, 2) _, card_thresh = cv2.threshold(card_resized, 130, 255, cv2.THRESH_BINARY_INV) card_kernel = np.ones((1, 1), np.uint8) # 커널 크기로 글자 두께 조절 card_eroded = cv2.erode(card_thresh, card_kernel, iterations=1) cv2.imshow("card", card_eroded) cards.append((card_eroded, cnt)) # 카드 이미지와 윤곽선 정보 함께 저장 cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) # 차이 계산 differences = [] if len(cards) > 1: for i in range(len(cards)): min_diff = float('inf') # 비교 시 최소값을 찾기 위한 초기값 설정 card_image_1, _ = cards[i] # 기준 카드 이미지 for j in range(len(cards)): if i != j: # 자기 자신과는 비교하지 않음 card_image_2, _ = cards[j] # 비교할 다른 카드 이미지 diff = compare_cards(card_image_1, card_image_2) # 두 카드 이미지 비교 if diff < min_diff: min_diff = diff # 최소 차이값 업데이트 differences.append((i, min_diff)) # 차이비교 if differences: max_different_card = max(differences, key=lambda x: x[1]) # 차이가 가장 큰 카드 (간혹 방식에 따라 반대일 수 있음) min_different_card = min(differences, key=lambda x: x[1]) # 차이가 가장 작은 카드 # 가장 큰 차이가 있는 카드의 윤곽선 _, cnt_max = cards[max_different_card[0]] x_max, y_max, w_max, h_max = cv2.boundingRect(cnt_max) cv2.rectangle(img, (x_max, y_max), (x_max + w_max, y_max + h_max), (0, 0, 255), 2) # 빨간색 cv2.putText(img, f'Conf: {max_different_card}%', (x_max, y_max - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 0, 0), 2) # 가장 작은 차이가 있는 카드의 윤곽선 _, cnt_min = cards[min_different_card[0]] x_min, y_min, w_min, h_min = cv2.boundingRect(cnt_min) cv2.rectangle(img, (x_min, y_min), (x_min + w_min, y_min + h_min), (255, 0, 0), 2) # 파란색 cv2.putText(img, f'Conf: {min_different_card}%', (x_min, y_min - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 0, 0), 2) print("\rtotal cards: {}".format(len(cards)), end="") cv2.imshow("Capturing target", img) if cv2.waitKey(1) & 0xFF == ord('q'): break cv2.destroyAllWindows()