Visualize hand tracking data in 3D space
(streamer)
| 10 | import array |
| 11 | |
| 12 | def hand_tracking_visualizer(streamer): |
| 13 | """Visualize hand tracking data in 3D space""" |
| 14 | |
| 15 | def generate_frame(blank_frame): |
| 16 | h, w = blank_frame.shape[:2] |
| 17 | |
| 18 | # Dark background |
| 19 | blank_frame[:] = [20, 20, 20] |
| 20 | |
| 21 | # Get latest hand tracking data |
| 22 | latest = streamer.get_latest() |
| 23 | if latest is None: |
| 24 | cv2.putText(blank_frame, "Waiting for hand data...", (w//2 - 200, h//2), |
| 25 | cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2) |
| 26 | return blank_frame |
| 27 | |
| 28 | # Draw virtual 3D space |
| 29 | center_x, center_y = w // 2, h // 2 |
| 30 | |
| 31 | # Draw coordinate axes |
| 32 | cv2.line(blank_frame, (center_x, center_y), (center_x + 100, center_y), (0, 0, 255), 2) |
| 33 | cv2.line(blank_frame, (center_x, center_y), (center_x, center_y - 100), (0, 255, 0), 2) |
| 34 | cv2.putText(blank_frame, "X", (center_x + 110, center_y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) |
| 35 | cv2.putText(blank_frame, "Y", (center_x, center_y - 110), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) |
| 36 | |
| 37 | # Project and draw hand positions |
| 38 | left_wrist = latest.get("left_wrist") |
| 39 | right_wrist = latest.get("right_wrist") |
| 40 | left_fingers = latest.get("left_fingers") |
| 41 | right_fingers = latest.get("right_fingers") |
| 42 | |
| 43 | # Draw left hand |
| 44 | if left_wrist is not None and left_fingers is not None: |
| 45 | left_fingers_world = left_wrist @ left_fingers |
| 46 | lx, ly = int(center_x + float(left_wrist[0, 0, 3]) * 400), int(center_y - float(left_wrist[0, 1, 3]) * 400) |
| 47 | left_pinch = latest.get("left_pinch_distance", 0) |
| 48 | color = (0, 255, 0) if left_pinch < 0.02 else (100, 100, 255) |
| 49 | cv2.circle(blank_frame, (lx, ly), 15, color, -1) |
| 50 | cv2.putText(blank_frame, "L", (lx - 8, ly + 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2) |
| 51 | |
| 52 | for i in range(left_fingers_world.shape[0]): |
| 53 | fx = int(center_x + float(left_fingers_world[i, 0, 3]) * 400) |
| 54 | fy = int(center_y - float(left_fingers_world[i, 1, 3]) * 400) |
| 55 | cv2.circle(blank_frame, (fx, fy), 3, (150, 150, 255), -1) |
| 56 | |
| 57 | # Draw right hand |
| 58 | if right_wrist is not None and right_fingers is not None: |
| 59 | right_fingers_world = right_wrist @ right_fingers |
| 60 | rx, ry = int(center_x + float(right_wrist[0, 0, 3]) * 400), int(center_y - float(right_wrist[0, 1, 3]) * 400) |
| 61 | right_pinch = latest.get("right_pinch_distance", 0) |
| 62 | color = (0, 255, 0) if right_pinch < 0.02 else (255, 100, 100) |
| 63 | cv2.circle(blank_frame, (rx, ry), 15, color, -1) |
| 64 | cv2.putText(blank_frame, "R", (rx - 8, ry + 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2) |
| 65 | |
| 66 | for i in range(right_fingers_world.shape[0]): |
| 67 | fx = int(center_x + float(right_fingers_world[i, 0, 3]) * 400) |
| 68 | fy = int(center_y - float(right_fingers_world[i, 1, 3]) * 400) |
| 69 | cv2.circle(blank_frame, (fx, fy), 3, (255, 150, 150), -1) |
no outgoing calls
no test coverage detected