240 lines
9.3 KiB
Python
240 lines
9.3 KiB
Python
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() |