This commit is contained in:
HuangHai
2026-01-12 22:04:41 +08:00
parent 231f52d3ee
commit de62305a28
11 changed files with 302 additions and 189 deletions

View File

@@ -2,7 +2,7 @@ import logging
import os
import cv2
import numpy as np
import time
import time
import hashlib
from Apps.XinDianTu.Config.Setting import BOTTOM_SAFE_EXCLUDE_RATIO
from Config.Config import TEMP_IMAGE_DIR
@@ -96,82 +96,7 @@ def clear_temp_dir(save_dir=TEMP_IMAGE_DIR):
logger.error(f"无法删除文件 {file_path}: {e}")
def click_image_template(d, template_path, timeout=5.0, threshold=0.8):
"""
使用 OpenCV 模板匹配查找并点击图片
:param d: uiautomator2 设备对象
:param template_path: 模板图片路径
:param timeout: 超时时间(秒)
:param threshold: 匹配阈值 (0.0 - 1.0)
:return: 是否点击成功
"""
if not os.path.exists(template_path):
logger.info(f"Template file not found: {template_path}")
return False
template = read_image(template_path)
if template is None:
logger.info(f"Failed to load template: {template_path}")
return False
t_h, t_w = template.shape[:2]
start_time = time.time()
best_val_overall = 0.0
while time.time() - start_time < timeout:
# 临时截图
temp_uuid = "temp_click_check"
screenshot_path = take_screenshot(d, temp_uuid, save_dir=TEMP_IMAGE_DIR)
target = read_image(screenshot_path)
if target is None:
time.sleep(0.5)
continue
# 多尺度匹配
found = None
# 缩放比例从 0.5 到 1.5,步长 0.1
for scale in np.linspace(0.5, 1.5, 11):
# 调整模板大小
resized_template = cv2.resize(template, (int(t_w * scale), int(t_h * scale)))
r_h, r_w = resized_template.shape[:2]
# 如果模板比目标还大,跳过
if r_h > target.shape[0] or r_w > target.shape[1]:
continue
result = cv2.matchTemplate(target, resized_template, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
if max_val > best_val_overall:
best_val_overall = max_val
if max_val >= threshold:
found = (max_val, max_loc, r_w, r_h)
break # 找到满足阈值的即停止当前截图的搜索
# 清理临时文件
try:
os.remove(screenshot_path)
except:
pass
if found:
max_val, max_loc, r_w, r_h = found
# 计算中心点
top_left = max_loc
center_x = top_left[0] + r_w // 2
center_y = top_left[1] + r_h // 2
logger.info(f"Found image at ({center_x}, {center_y}) with confidence {max_val:.2f}")
d.click(center_x, center_y)
return True
time.sleep(1.0)
logger.info(f"Image not found after {timeout}s (Best confidence: {best_val_overall:.2f})")
return False
def is_background_dimmed(image_path, threshold=80):
@@ -711,29 +636,29 @@ def get_row_stats(gray):
return row_means, row_stds, edge_means
def clean_station_name(name):
"""
清理场站名称,移除结尾的省略号及多余空格,方便比对
"""
if not name: return ""
name = name.strip()
# 移除结尾的 . (通常是截断标识)
while name.endswith("."):
name = name[:-1]
return name.strip()
def get_file_md5(path):
"""计算文件的 MD5 值"""
if not os.path.exists(path):
return ""
hash_md5 = hashlib.md5()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
def clean_station_name(name):
"""
清理场站名称,移除结尾的省略号及多余空格,方便比对
"""
if not name: return ""
name = name.strip()
# 移除结尾的 . (通常是截断标识)
while name.endswith("."):
name = name[:-1]
return name.strip()
def get_file_md5(path):
"""计算文件的 MD5 值"""
if not os.path.exists(path):
return ""
hash_md5 = hashlib.md5()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
def crop_cards_from_image(img_path, output_dir=None, save_debug=True):
"""
从图片中裁剪场站卡片