Fred808 commited on
Commit
8b73a5b
·
verified ·
1 Parent(s): 3347d33

Upload 17 files

Browse files
cursor_tracker.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Cursor detection and action logging utilities for notebooks or scripts.
3
+ """
4
+ import cv2
5
+ import numpy as np
6
+ import json
7
+ from pathlib import Path
8
+ import os
9
+
10
+ def to_rgb(img):
11
+ if img is None:
12
+ return None
13
+ if len(img.shape) == 2:
14
+ return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
15
+ if img.shape[2] == 4:
16
+ return cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
17
+ return img
18
+
19
+ def get_mask_from_alpha(template_img):
20
+ if template_img is not None and len(template_img.shape) == 3 and template_img.shape[2] == 4:
21
+ return (template_img[:, :, 3] > 0).astype(np.uint8) * 255
22
+ return None
23
+
24
+ def detect_cursor_in_frame_multi(frame, cursor_templates, threshold=0.8):
25
+ best_pos = None
26
+ best_conf = -1
27
+ best_template_name = None
28
+ frame_rgb = to_rgb(frame)
29
+
30
+ for template_name, cursor_template in cursor_templates.items():
31
+ template_rgb = to_rgb(cursor_template)
32
+ mask = get_mask_from_alpha(cursor_template)
33
+
34
+ if template_rgb is None or frame_rgb is None or template_rgb.shape[2] != frame_rgb.shape[2]:
35
+ print(f"[WARN] Skipping template {template_name} due to channel mismatch or load error.")
36
+ continue
37
+
38
+ try:
39
+ result = cv2.matchTemplate(frame_rgb, template_rgb, cv2.TM_CCOEFF_NORMED, mask=mask)
40
+ except Exception as e:
41
+ print(f"[WARN] matchTemplate failed for {template_name}: {e}")
42
+ continue
43
+
44
+ _, max_val, _, max_loc = cv2.minMaxLoc(result)
45
+ if max_val > best_conf:
46
+ best_conf = max_val
47
+ if max_val >= threshold:
48
+ cursor_w, cursor_h = template_rgb.shape[1], template_rgb.shape[0]
49
+ cursor_x = max_loc[0] + cursor_w // 2
50
+ cursor_y = max_loc[1] + cursor_h // 2
51
+ best_pos = (cursor_x, cursor_y)
52
+ best_template_name = template_name
53
+
54
+ if best_conf >= threshold:
55
+ return best_pos, best_conf, best_template_name
56
+ return None, best_conf, None
57
+
58
+ def ensure_dir(path):
59
+ if not os.path.exists(path):
60
+ os.makedirs(path, exist_ok=True)
61
+
62
+ def track_cursor(frames_dir, cursor_templates_dir, output_json_path, threshold=0.8, start_frame=1):
63
+ frames_dir = Path(frames_dir)
64
+ ensure_dir(Path(output_json_path).parent)
65
+
66
+ # Load cursor templates
67
+ cursor_templates = {}
68
+ for template_file in Path(cursor_templates_dir).glob('*.png'):
69
+ template_img = cv2.imread(str(template_file), cv2.IMREAD_UNCHANGED)
70
+ if template_img is not None:
71
+ cursor_templates[template_file.name] = template_img
72
+ else:
73
+ print(f"[WARN] Could not load template: {template_file}")
74
+ if not cursor_templates:
75
+ raise FileNotFoundError(f"No cursor templates found in: {cursor_templates_dir}")
76
+
77
+ # Process frames
78
+ results = []
79
+ for frame_file in sorted(frames_dir.glob('*.png')):
80
+ try:
81
+ frame_num = int(frame_file.stem)
82
+ except:
83
+ continue
84
+
85
+ if frame_num < start_frame:
86
+ continue
87
+
88
+ frame = cv2.imread(str(frame_file), cv2.IMREAD_UNCHANGED)
89
+ if frame is None:
90
+ print(f"[WARN] Could not load frame: {frame_file}")
91
+ continue
92
+
93
+ pos, conf, template_name = detect_cursor_in_frame_multi(frame, cursor_templates, threshold)
94
+ if pos is not None:
95
+ print(f"{frame_file.name}: Cursor at {pos} (template: {template_name})")
96
+ results.append({
97
+ 'frame': frame_file.name,
98
+ 'cursor_active': True,
99
+ 'x': pos[0],
100
+ 'y': pos[1],
101
+ 'confidence': conf,
102
+ 'template': template_name
103
+ })
104
+ else:
105
+ print(f"{frame_file.name}: Cursor disabled")
106
+ results.append({
107
+ 'frame': frame_file.name,
108
+ 'cursor_active': False,
109
+ 'x': None,
110
+ 'y': None,
111
+ 'confidence': conf,
112
+ 'template': None
113
+ })
114
+
115
+ with open(output_json_path, 'w') as f:
116
+ json.dump(results, f, indent=2)
117
+
118
+ print(f"[DONE] Cursor tracking results saved to: {output_json_path}")
cursors/1.png ADDED
cursors/10.png ADDED
cursors/11.png ADDED
cursors/12.png ADDED
cursors/13.png ADDED
cursors/14.png ADDED
cursors/15.png ADDED
cursors/16.png ADDED
cursors/2.png ADDED
cursors/3.png ADDED
cursors/4.png ADDED
cursors/5.png ADDED
cursors/6.png ADDED
cursors/7.png ADDED
cursors/8.png ADDED
cursors/9.png ADDED