test_img_match.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. 测试 image-match:用模板图生成合成截图(模拟手机屏中缩略图),再跑匹配并校验中心点。
  5. 用法: python test_img_match.py <template_path> [screenshot_path]
  6. - 仅 template_path: 用模板生成合成截图再匹配(用于验证流程与 RoMa 参数)
  7. - template_path + screenshot_path: 用真实截图与模板匹配(用于实机调试)
  8. 输出: 打印 JSON 结果及期望中心点(合成时),成功时退出码 0。
  9. """
  10. import os
  11. import sys
  12. import json
  13. import tempfile
  14. import subprocess
  15. # 项目根目录
  16. SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
  17. PROJECT_ROOT = os.path.dirname(os.path.dirname(SCRIPT_DIR))
  18. IMAGE_MATCH = os.path.join(SCRIPT_DIR, "image-match.py")
  19. def load_image_cv(path):
  20. import cv2
  21. import numpy as np
  22. with open(path, "rb") as f:
  23. data = np.frombuffer(f.read(), dtype=np.uint8)
  24. img = cv2.imdecode(data, cv2.IMREAD_COLOR)
  25. if img is not None:
  26. return img
  27. return cv2.imread(path)
  28. def make_synthetic_screenshot(template_path, scale=0.45, offset_x=100, offset_y=350, screen_w=1080, screen_h=2340):
  29. """用模板图生成一张合成截图:黑色背景,模板缩放后贴在 (offset_x, offset_y)。"""
  30. import cv2
  31. import numpy as np
  32. tpl = load_image_cv(template_path)
  33. if tpl is None:
  34. raise FileNotFoundError(f"无法读取模板: {template_path}")
  35. h, w = tpl.shape[:2]
  36. new_w = int(round(w * scale))
  37. new_h = int(round(h * scale))
  38. small = cv2.resize(tpl, (new_w, new_h), interpolation=cv2.INTER_AREA)
  39. screen = np.zeros((screen_h, screen_w, 3), dtype=np.uint8)
  40. screen[:] = (30, 30, 30) # 深灰模拟界面
  41. x1, y1 = offset_x, offset_y
  42. x2, y2 = min(offset_x + new_w, screen_w), min(offset_y + new_h, screen_h)
  43. sx2 = x2 - x1
  44. sy2 = y2 - y1
  45. screen[y1:y1 + sy2, x1:x1 + sx2] = small[:sy2, :sx2]
  46. expect_cx = offset_x + new_w // 2
  47. expect_cy = offset_y + new_h // 2
  48. return screen, (expect_cx, expect_cy, offset_x, offset_y, new_w, new_h)
  49. def run_match(screenshot_path, template_path, method="feature"):
  50. py = os.environ.get("PYTHON", "python")
  51. cmd = [py, IMAGE_MATCH, screenshot_path, template_path, "0.8", method]
  52. r = subprocess.run(cmd, capture_output=True, text=True, timeout=60, cwd=PROJECT_ROOT)
  53. out = (r.stdout or "").strip()
  54. err = (r.stderr or "").strip()
  55. if r.returncode != 0 and out:
  56. try:
  57. return json.loads(out)
  58. except json.JSONDecodeError:
  59. pass
  60. if out:
  61. try:
  62. return json.loads(out)
  63. except json.JSONDecodeError:
  64. pass
  65. return {"success": False, "error": err or out or "unknown error", "returncode": r.returncode}
  66. def main():
  67. if len(sys.argv) < 2:
  68. print("用法: python test_img_match.py <template_path> [screenshot_path]")
  69. sys.exit(2)
  70. template_path = os.path.abspath(sys.argv[1])
  71. if not os.path.exists(template_path):
  72. print(json.dumps({"success": False, "error": f"模板不存在: {template_path}"}))
  73. sys.exit(1)
  74. screenshot_path = sys.argv[2] if len(sys.argv) > 2 else None
  75. expect_center = None
  76. if screenshot_path is None:
  77. # 合成截图
  78. screenshot_path = os.path.join(tempfile.gettempdir(), "ef_test_screenshot.png")
  79. screen, (expect_cx, expect_cy, ox, oy, nw, nh) = make_synthetic_screenshot(
  80. template_path, scale=0.45, offset_x=100, offset_y=350
  81. )
  82. import cv2
  83. cv2.imwrite(screenshot_path, screen)
  84. expect_center = (expect_cx, expect_cy)
  85. print("合成截图已生成:", screenshot_path, "期望中心:", expect_center, file=sys.stderr)
  86. result = run_match(screenshot_path, template_path)
  87. print(json.dumps(result, ensure_ascii=False, indent=2))
  88. if expect_center and result.get("success"):
  89. cx, cy = result.get("center_x"), result.get("center_y")
  90. ex, ey = expect_center
  91. tol = 25
  92. if abs(cx - ex) <= tol and abs(cy - ey) <= tol:
  93. print("中心点与期望一致 (容差 %d px)" % tol, file=sys.stderr)
  94. else:
  95. print("中心点与期望偏差: 得到 (%d,%d) 期望 (%d,%d)" % (cx, cy, ex, ey), file=sys.stderr)
  96. if not result.get("success"):
  97. sys.exit(1)
  98. sys.exit(0)
  99. if __name__ == "__main__":
  100. main()