|
1 | 1 | import types |
2 | | -from typing import Any, Callable, Dict, List, Optional, Union |
| 2 | +from typing import Any, Callable, Dict, List, Optional, Sequence, Union |
3 | 3 |
|
4 | 4 | from je_auto_control.utils.exception.exception_tags import ( |
5 | 5 | action_is_null_error_message, add_command_exception_error_message, |
@@ -3282,6 +3282,47 @@ def _match_masked_all(template: str, mask: Any = None, min_score: Any = 0.9, |
3282 | 3282 | return {"count": len(matches), "matches": [m.to_dict() for m in matches]} |
3283 | 3283 |
|
3284 | 3284 |
|
| 3285 | +def _seq_arg(value: Any, default: Sequence[float]) -> Sequence[float]: |
| 3286 | + """Coerce a JSON-string / list arg into a tuple of floats, or the default.""" |
| 3287 | + import json |
| 3288 | + if isinstance(value, str): |
| 3289 | + value = json.loads(value) if value.strip() else None |
| 3290 | + return tuple(float(v) for v in value) if value else tuple(default) |
| 3291 | + |
| 3292 | + |
| 3293 | +def _match_rotated(template: str, min_score: Any = 0.8, scales: Any = None, |
| 3294 | + angles: Any = None, region: Any = None, |
| 3295 | + method: str = "ccoeff_normed") -> Dict[str, Any]: |
| 3296 | + """Adapter: best rotation/scale-tolerant template match on the screen.""" |
| 3297 | + import json |
| 3298 | + from je_auto_control.utils.rotated_match import match_rotated |
| 3299 | + if isinstance(region, str): |
| 3300 | + region = json.loads(region) if region.strip() else None |
| 3301 | + match = match_rotated(template, region=region, |
| 3302 | + scales=_seq_arg(scales, (1.0,)), |
| 3303 | + angles=_seq_arg(angles, (0.0,)), |
| 3304 | + min_score=float(min_score), method=method) |
| 3305 | + return {"found": match is not None, |
| 3306 | + "match": match.to_dict() if match else None} |
| 3307 | + |
| 3308 | + |
| 3309 | +def _match_rotated_all(template: str, min_score: Any = 0.8, scales: Any = None, |
| 3310 | + angles: Any = None, max_results: Any = 20, |
| 3311 | + nms_iou: Any = 0.3, region: Any = None) -> Dict[str, Any]: |
| 3312 | + """Adapter: every rotation/scale-tolerant template match (NMS).""" |
| 3313 | + import json |
| 3314 | + from je_auto_control.utils.rotated_match import match_rotated_all |
| 3315 | + if isinstance(region, str): |
| 3316 | + region = json.loads(region) if region.strip() else None |
| 3317 | + matches = match_rotated_all(template, region=region, |
| 3318 | + scales=_seq_arg(scales, (1.0,)), |
| 3319 | + angles=_seq_arg(angles, (0.0,)), |
| 3320 | + min_score=float(min_score), |
| 3321 | + max_results=int(max_results), |
| 3322 | + nms_iou=float(nms_iou)) |
| 3323 | + return {"count": len(matches), "matches": [m.to_dict() for m in matches]} |
| 3324 | + |
| 3325 | + |
3285 | 3326 | def _find_color_region(rgb: Any, tolerance: Any = 20, min_area: Any = 50, |
3286 | 3327 | region: Any = None) -> Dict[str, Any]: |
3287 | 3328 | """Adapter: locate coloured regions on the screen, largest first.""" |
@@ -5684,6 +5725,8 @@ def __init__(self): |
5684 | 5725 | "AC_match_template_all": _match_template_all, |
5685 | 5726 | "AC_match_masked": _match_masked, |
5686 | 5727 | "AC_match_masked_all": _match_masked_all, |
| 5728 | + "AC_match_rotated": _match_rotated, |
| 5729 | + "AC_match_rotated_all": _match_rotated_all, |
5687 | 5730 | "AC_ssim_compare": _ssim_compare, |
5688 | 5731 | "AC_ssim_changed_regions": _ssim_changed_regions, |
5689 | 5732 | "AC_feature_match": _feature_match, |
|
0 commit comments