128 lines
4.3 KiB
Python
128 lines
4.3 KiB
Python
"""
|
|
验证码图片匹配脚本
|
|
在 1.jpg 中找到 2.png、3.png、4.png 的位置
|
|
"""
|
|
import cv2
|
|
import numpy as np
|
|
import os
|
|
|
|
def find_template_in_image(main_img_path, template_path, threshold=0.5):
|
|
"""
|
|
在主图中查找模板图片的位置(原始尺寸 + 多尺度)
|
|
支持 PNG alpha 通道作为模板轮廓
|
|
返回置信度最高的匹配结果
|
|
"""
|
|
main_img = cv2.imread(main_img_path)
|
|
template = cv2.imread(template_path, cv2.IMREAD_UNCHANGED)
|
|
|
|
if main_img is None:
|
|
print(f"无法读取主图: {main_img_path}")
|
|
return []
|
|
if template is None:
|
|
print(f"无法读取模板: {template_path}")
|
|
return []
|
|
|
|
h, w = template.shape[:2]
|
|
main_gray = cv2.cvtColor(main_img, cv2.COLOR_BGR2GRAY)
|
|
|
|
# 如果模板有 alpha 通道且 RGB 全黑,用 alpha 通道作为灰度图
|
|
if template.shape[2] == 4:
|
|
alpha = template[:, :, 3]
|
|
rgb_sum = template[:, :, :3].sum()
|
|
if rgb_sum == 0:
|
|
tmpl_gray = alpha # 用 alpha 通道
|
|
else:
|
|
tmpl_gray = cv2.cvtColor(template[:, :, :3], cv2.COLOR_BGR2GRAY)
|
|
else:
|
|
tmpl_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
|
|
|
|
best = None
|
|
|
|
# 先尝试原始尺寸
|
|
scales = [1.0] + list(np.linspace(0.6, 1.4, 17))
|
|
for scale in scales:
|
|
rw, rh = int(w * scale), int(h * scale)
|
|
if rh < 5 or rw < 5:
|
|
continue
|
|
if rh > main_gray.shape[0] or rw > main_gray.shape[1]:
|
|
continue
|
|
|
|
resized_tmpl = cv2.resize(tmpl_gray, (rw, rh))
|
|
res = cv2.matchTemplate(main_gray, resized_tmpl, cv2.TM_CCOEFF_NORMED)
|
|
_, max_val, _, max_loc = cv2.minMaxLoc(res)
|
|
|
|
if best is None or max_val > best["confidence"]:
|
|
best = {
|
|
"x": max_loc[0],
|
|
"y": max_loc[1],
|
|
"w": rw,
|
|
"h": rh,
|
|
"confidence": max_val,
|
|
"scale": scale,
|
|
"center_x": max_loc[0] + rw // 2,
|
|
"center_y": max_loc[1] + rh // 2,
|
|
}
|
|
|
|
if best is None or best["confidence"] < threshold:
|
|
return []
|
|
return [best]
|
|
|
|
|
|
def main():
|
|
base_dir = os.path.join(os.path.dirname(__file__), "images")
|
|
main_img_path = os.path.join(base_dir, "1.jpg")
|
|
templates = ["2.png", "3.png", "4.png"]
|
|
|
|
print(f"主图: {main_img_path}\n")
|
|
|
|
all_results = {}
|
|
for tmpl_name in templates:
|
|
tmpl_path = os.path.join(base_dir, tmpl_name)
|
|
matches = find_template_in_image(main_img_path, tmpl_path, threshold=0.5)
|
|
all_results[tmpl_name] = matches
|
|
|
|
if matches:
|
|
m = matches[0]
|
|
print(f"[{tmpl_name}] 找到匹配:")
|
|
print(f" 位置: ({m['x']}, {m['y']})")
|
|
print(f" 中心点: ({m['center_x']}, {m['center_y']})")
|
|
print(f" 尺寸: {m['w']}x{m['h']}")
|
|
print(f" 置信度: {m['confidence']:.4f}")
|
|
print(f" 缩放比例: {m['scale']:.2f}")
|
|
else:
|
|
print(f"[{tmpl_name}] 未找到匹配(置信度不足)")
|
|
print()
|
|
|
|
# 可视化结果,保存标注图
|
|
main_img = cv2.imread(main_img_path)
|
|
colors = [(0, 0, 255), (0, 255, 0), (255, 0, 0)] # 红、绿、蓝
|
|
for i, tmpl_name in enumerate(templates):
|
|
matches = all_results.get(tmpl_name, [])
|
|
for m in matches:
|
|
x, y, w, h = m["x"], m["y"], m["w"], m["h"]
|
|
color = colors[i % len(colors)]
|
|
cv2.rectangle(main_img, (x, y), (x + w, y + h), color, 2)
|
|
cv2.putText(main_img, tmpl_name, (x, y - 5),
|
|
cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
|
|
# 画中心点
|
|
cx, cy = m["center_x"], m["center_y"]
|
|
cv2.circle(main_img, (cx, cy), 5, color, -1)
|
|
|
|
output_path = os.path.join(base_dir, "result.jpg")
|
|
cv2.imwrite(output_path, main_img)
|
|
print(f"标注结果已保存到: {output_path}")
|
|
|
|
# 打印点击坐标汇总(用于自动化点击)
|
|
print("\n=== 点击坐标汇总 ===")
|
|
for tmpl_name in templates:
|
|
matches = all_results.get(tmpl_name, [])
|
|
if matches:
|
|
m = matches[0]
|
|
print(f"{tmpl_name}: 点击 ({m['center_x']}, {m['center_y']})")
|
|
else:
|
|
print(f"{tmpl_name}: 未找到")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|