pixel-hunter/scanner.py
2026-07-29 21:12:25 +03:00

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)