86 lines
2.9 KiB
Python
86 lines
2.9 KiB
Python
import cv2
|
|
import numpy as np
|
|
from PIL import ImageGrab
|
|
|
|
|
|
class Scanner:
|
|
def __init__(self, config):
|
|
self.config = config
|
|
self.template = cv2.imread(config['template_path'])
|
|
if self.template is None:
|
|
raise FileNotFoundError(f"Template not found: {config['template_path']}")
|
|
self.th, self.tw = self.template.shape[:2]
|
|
self.last_score = 0.0
|
|
self.last_box = None
|
|
|
|
def find(self, screen):
|
|
if self.config.get('search_mode') == 'purple_frame':
|
|
return self.find_purple_frame(screen)
|
|
|
|
screen_h, screen_w = screen.shape[:2]
|
|
if self.tw > screen_w or self.th > screen_h:
|
|
self.last_score = 0.0
|
|
self.last_box = None
|
|
return None
|
|
|
|
res = cv2.matchTemplate(screen, self.template, cv2.TM_CCOEFF_NORMED)
|
|
_, max_val, _, max_loc = cv2.minMaxLoc(res)
|
|
self.last_score = max_val
|
|
if max_val >= self.config['confidence']:
|
|
left, top = max_loc
|
|
self.last_box = (left, top, self.tw, self.th)
|
|
cx = left + self.tw // 2
|
|
cy = top + self.th // 2
|
|
return (cx, cy)
|
|
self.last_box = None
|
|
return None
|
|
|
|
def find_purple_frame(self, screen):
|
|
"""Find the rectangular purple highlight, ignoring everything inside it."""
|
|
hsv = cv2.cvtColor(screen, cv2.COLOR_BGR2HSV)
|
|
lower = np.array(
|
|
self.config.get('frame_hsv_lower', [125, 60, 120]),
|
|
dtype=np.uint8,
|
|
)
|
|
upper = np.array(
|
|
self.config.get('frame_hsv_upper', [150, 255, 255]),
|
|
dtype=np.uint8,
|
|
)
|
|
mask = cv2.inRange(hsv, lower, upper)
|
|
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
|
|
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
|
|
|
|
contours, _ = cv2.findContours(
|
|
mask,
|
|
cv2.RETR_EXTERNAL,
|
|
cv2.CHAIN_APPROX_SIMPLE,
|
|
)
|
|
min_size = int(self.config.get('frame_min_size', 40))
|
|
min_rectangularity = float(
|
|
self.config.get('frame_min_rectangularity', 0.80)
|
|
)
|
|
candidates = []
|
|
|
|
for contour in contours:
|
|
x, y, w, h = cv2.boundingRect(contour)
|
|
if w < min_size or h < min_size:
|
|
continue
|
|
rectangularity = cv2.contourArea(contour) / float(w * h)
|
|
if rectangularity < min_rectangularity:
|
|
continue
|
|
candidates.append((w * h, rectangularity, x, y, w, h))
|
|
|
|
if not candidates:
|
|
self.last_score = 0.0
|
|
self.last_box = None
|
|
return None
|
|
|
|
_, rectangularity, x, y, w, h = max(candidates)
|
|
self.last_score = rectangularity
|
|
self.last_box = (x, y, w, h)
|
|
return (x + w // 2, y + h // 2)
|
|
|
|
def grab_screen(self):
|
|
img = ImageGrab.grab()
|
|
return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
|