| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- """手指滑动轨迹录制 → 生成轨迹图片 + JSON数据"""
- import sys, os, subprocess, re, time, json
- import cv2, numpy as np
- DEVICE = sys.argv[1] if len(sys.argv) > 1 else "JRLFJFSCGIGIS4LR"
- OUT_DIR = r"D:\pycharm\Project\project\tbsg\guiji_new"
- os.makedirs(OUT_DIR, exist_ok=True)
- # ── 找触摸设备 ──
- r = subprocess.run(["adb", "-s", DEVICE, "shell", "getevent", "-pl"], capture_output=True, text=True, timeout=10)
- touch_dev = None
- current = None
- axis_max_x = None
- axis_max_y = None
- for line in r.stdout.split('\n'):
- m = re.search(r'(/dev/input/event\d+)', line)
- if m:
- current = m.group(1)
- if current and 'ABS_MT_POSITION_X' in line and touch_dev is None:
- touch_dev = current
- am = re.search(r'max\s+(\d+)', line)
- if am:
- axis_max_x = int(am.group(1))
- elif current == touch_dev and 'ABS_MT_POSITION_Y' in line and axis_max_y is None:
- am = re.search(r'max\s+(\d+)', line)
- if am:
- axis_max_y = int(am.group(1))
- if touch_dev and axis_max_x and axis_max_y:
- break
- if not touch_dev:
- for d in ['/dev/input/event3', '/dev/input/event2', '/dev/input/event1']:
- r2 = subprocess.run(["adb", "-s", DEVICE, "shell", "getevent", "-pl", d], capture_output=True, text=True, timeout=5)
- if 'ABS_MT_POSITION' in r2.stdout:
- touch_dev = d
- mx = re.search(r'ABS_MT_POSITION_X.*?max\s+(\d+)', r2.stdout, re.S)
- my = re.search(r'ABS_MT_POSITION_Y.*?max\s+(\d+)', r2.stdout, re.S)
- axis_max_x = int(mx.group(1)) if mx else None
- axis_max_y = int(my.group(1)) if my else None
- break
- if not touch_dev:
- touch_dev = "/dev/input/event3"
- # ── 获取分辨率 ──
- size_r = subprocess.run(["adb", "-s", DEVICE, "shell", "wm", "size"], capture_output=True, text=True)
- m = re.search(r'(\d+)x(\d+)', size_r.stdout)
- W, H = (int(m.group(1)), int(m.group(2))) if m else (1220, 2712)
- print(f"设备: {DEVICE}")
- print(f"触摸设备: {touch_dev}")
- print(f"屏幕: {W}x{H} 原始触摸范围: {axis_max_x or '?'}x{axis_max_y or '?'}")
- print()
- print("在手机上滑动手指,手指抬起自动结束...")
- print()
- # ── 录制 ──
- proc = subprocess.Popen(
- ["adb", "-s", DEVICE, "shell", "getevent", "-lt", touch_dev],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
- )
- points = []
- lx, ly, ts = None, None, None
- idle_count = 0
- start_ts = None
- for line in proc.stdout:
- # 解析时间戳 [ 12345.678901]
- tm = re.search(r'\[\s*([\d.]+)\]', line)
- if tm:
- ts = float(tm.group(1))
- if 'ABS_MT_POSITION_X' in line:
- mm = re.search(r'([0-9a-fA-F]{8})$', line.strip())
- if mm:
- lx = int(mm.group(1), 16)
- elif 'ABS_MT_POSITION_Y' in line:
- mm = re.search(r'([0-9a-fA-F]{8})$', line.strip())
- if mm:
- ly = int(mm.group(1), 16)
- elif 'SYN_REPORT' in line and lx is not None and ly is not None:
- if start_ts is None:
- start_ts = ts
- rel_ts = (ts - start_ts) * 1000 if ts and start_ts else 0 # 相对时间ms
- raw_x, raw_y = lx, ly
- x = int(round(raw_x * (W - 1) / axis_max_x)) if axis_max_x else raw_x
- y = int(round(raw_y * (H - 1) / axis_max_y)) if axis_max_y else raw_y
- points.append({"x": x, "y": y, "raw_x": raw_x, "raw_y": raw_y,
- "ts": ts, "rel_ms": round(rel_ts, 2)})
- idle_count = 0
- if len(points) % 15 == 0:
- print(f"\r 已录 {len(points)} 点 (x={x}, y={y})", end="", flush=True)
- elif 'BTN_TOUCH' in line and 'UP' in line:
- if len(points) > 3:
- print("\n 检测到手指抬起")
- break
- elif 'ABS_MT_TRACKING_ID' in line and 'ffffffff' in line:
- if len(points) > 3:
- print("\n 检测到手指抬起")
- break
- else:
- idle_count += 1
- if idle_count > 300 and len(points) > 5:
- print("\n 超时自动结束")
- break
- proc.kill()
- print(f"\n共录制 {len(points)} 点")
- if len(points) < 3:
- print("点数太少,请重试(确保触摸了屏幕)")
- sys.exit(1)
- xs = [p["x"] for p in points]
- ys = [p["y"] for p in points]
- # ── 保存JSON ──
- ts_str = time.strftime("%Y%m%d_%H%M%S") + f"_{time.time_ns() % 1000000:06d}"
- json_path = os.path.join(OUT_DIR, f"track_{ts_str}.json")
- data = {
- "device": DEVICE,
- "screen": {"w": W, "h": H},
- "touch_axis": {"max_x": axis_max_x, "max_y": axis_max_y},
- "start_ts": start_ts,
- "total_points": len(points),
- "start": {"x": xs[0], "y": ys[0]},
- "end": {"x": xs[-1], "y": ys[-1]},
- "dx": xs[-1] - xs[0],
- "dy": ys[-1] - ys[0],
- "duration_ms": round(points[-1]["rel_ms"], 2) if points else 0,
- "points": points
- }
- with open(json_path, 'w', encoding='utf-8') as f:
- json.dump(data, f, ensure_ascii=False)
- print(f"数据: {json_path}")
- # ── 画轨迹: 多种颜色 ──
- margin_x = 40
- margin_y = 300 # 上下大留白, 轨迹居中
- min_x, max_x = min(xs), max(xs)
- min_y, max_y = min(ys), max(ys)
- width = max_x - min_x + margin_x * 2
- height = max_y - min_y + margin_y * 2
- width, height = max(width, 200), max(height, 800)
- canvas = np.ones((height, width, 3), dtype=np.uint8) * 255
- total = len(points)
- # 找折回起点: X开始持续减小
- peak_i = 0
- for i in range(1, total):
- if xs[i] >= xs[peak_i]:
- peak_i = i
- else:
- break
- # 计算右段Y波动阈值
- right_ys = ys[:peak_i+1]
- y_diffs = [abs(right_ys[j] - right_ys[j-1]) for j in range(1, len(right_ys))]
- avg_y_diff = sum(y_diffs) / len(y_diffs) if y_diffs else 0
- for i in range(1, total):
- p1 = (xs[i-1] - min_x + margin_x, ys[i-1] - min_y + margin_y)
- p2 = (xs[i] - min_x + margin_x, ys[i] - min_y + margin_y)
- if i <= peak_i:
- color = (0, 200, 0) # 绿色=往右
- else:
- color = (0, 0, 200) # 红色=折回
- cv2.line(canvas, p1, p2, color, 30)
- # 起点(绿) 折回点(黄) 终点(红)
- p0 = (xs[0] - min_x + margin_x, ys[0] - min_y + margin_y)
- pp = (xs[peak_i] - min_x + margin_x, ys[peak_i] - min_y + margin_y)
- pe = (xs[-1] - min_x + margin_x, ys[-1] - min_y + margin_y)
- cv2.circle(canvas, p0, 16, (0, 200, 0), -1)
- cv2.circle(canvas, pp, 16, (0, 200, 200), -1)
- cv2.circle(canvas, pe, 16, (0, 0, 200), -1)
- cv2.putText(canvas, "START", (p0[0]+20, p0[1]+5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,150,0), 3)
- cv2.putText(canvas, "TURN", (pp[0]+20, pp[1]+5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (200,150,0), 3)
- cv2.putText(canvas, "END", (pe[0]+20, pe[1]+5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,0,150), 3)
- info = f"GREEN=right | RED=return | S({xs[0]},{ys[0]}) E({xs[-1]},{ys[-1]}) | {xs[-1]-xs[0]}px | {data['duration_ms']}ms"
- cv2.putText(canvas, info, (margin_x, height - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (120,120,120), 1)
- img_path = os.path.join(OUT_DIR, f"track_{ts_str}.png")
- cv2.imwrite(img_path, canvas)
- print(f"图片: {img_path}")
- print(f"起点({xs[0]},{ys[0]}) -> 终点({xs[-1]},{ys[-1]})")
- print(f"X: {xs[-1]-xs[0]}px Y: {ys[-1]-ys[0]}px 时长: {data['duration_ms']}ms")
|