101 lines
3.0 KiB
Python
101 lines
3.0 KiB
Python
from dataclasses import dataclass
|
|
from typing import Literal, overload
|
|
|
|
import cv2
|
|
import numpy as np
|
|
from cv2.typing import MatLike
|
|
|
|
from kotonebot.backend.image import TemplateMatchResult
|
|
|
|
from kotonebot.kaa import R
|
|
from kotonebot import action, color, image
|
|
from kotonebot.backend.color import HsvColor
|
|
from kotonebot.util import Rect
|
|
from kotonebot.backend.core import Image
|
|
from kotonebot.backend.preprocessor import HsvColorFilter
|
|
|
|
|
|
def filter_rectangles(
|
|
img: MatLike,
|
|
color_ranges: tuple[HsvColor, HsvColor],
|
|
aspect_ratio_threshold: float,
|
|
area_threshold: int,
|
|
rect: Rect | None = None
|
|
) -> list[Rect]:
|
|
"""
|
|
过滤出指定颜色,并执行轮廓查找,返回符合要求的轮廓的 bound box。
|
|
返回结果按照 y 坐标排序。
|
|
"""
|
|
img_hsv =cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
|
|
|
|
white_mask = cv2.inRange(img_hsv, np.array(color_ranges[0]), np.array(color_ranges[1]))
|
|
contours, _ = cv2.findContours(white_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
|
result_rects = []
|
|
for contour in contours:
|
|
x, y, w, h = cv2.boundingRect(contour)
|
|
# 如果不在指定范围内,跳过
|
|
if rect is not None:
|
|
rect_x1, rect_y1, rect_w, rect_h = rect
|
|
rect_x2 = rect_x1 + rect_w
|
|
rect_y2 = rect_y1 + rect_h
|
|
if not (
|
|
x >= rect_x1 and
|
|
y >= rect_y1 and
|
|
x + w <= rect_x2 and
|
|
y + h <= rect_y2
|
|
):
|
|
continue
|
|
aspect_ratio = w / h
|
|
area = cv2.contourArea(contour)
|
|
if aspect_ratio >= aspect_ratio_threshold and area >= area_threshold:
|
|
result_rects.append((x, y, w, h))
|
|
result_rects.sort(key=lambda x: x[1])
|
|
return result_rects
|
|
|
|
@action('按钮是否禁用', screenshot_mode='manual-inherit')
|
|
def button_state(*, target: Image | None = None, rect: Rect | None = None) -> bool | None:
|
|
"""
|
|
判断按钮是否处于禁用状态。
|
|
|
|
:param rect: 按钮的矩形区域。必须包括文字或图标部分。
|
|
:param target: 按钮目标模板。
|
|
"""
|
|
img = device.screenshot()
|
|
if rect is not None:
|
|
_rect = rect
|
|
elif target is not None:
|
|
result = image.find(target)
|
|
if result is None:
|
|
return None
|
|
_rect = result.rect
|
|
else:
|
|
raise ValueError('Either rect or target must be provided.')
|
|
if color.find('#babcbd', rect=_rect):
|
|
return False
|
|
elif color.find('#ffffff', rect=_rect):
|
|
return True
|
|
else:
|
|
raise ValueError(f'Unknown button state: {img}')
|
|
|
|
|
|
WHITE_LOW = (0, 0, 200)
|
|
WHITE_HIGH = (180, 30, 255)
|
|
|
|
|
|
class WhiteFilter(HsvColorFilter):
|
|
"""
|
|
匹配时,只匹配图像和模板中的白色部分。
|
|
|
|
此类用于识别空心/透明背景的白色图标或文字。
|
|
"""
|
|
|
|
def __init__(self):
|
|
super().__init__(WHITE_LOW, WHITE_HIGH)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
from pprint import pprint as print
|
|
from kotonebot.backend.context import init_context, manual_context, device
|
|
|
|
init_context()
|
|
manual_context().begin() |