Computer vision · Pose · IMU

Read a cello stroke like a machine watching it.

A vision and embedded-sensing toolkit that turns bowing motion, posture, and early technique signals into measurable metrics and live feedback — webcam first, optional bow-mounted IMU second.

OpenCV MediaPipe Pose Tracking Bow Tracking Technique Feedback ESP32-C3 · IMU Python
BOWSCOPE · POSE + BOW OVERLAY SYNTHETIC FEED
shoulder elbow wrist
Bow angle θ
–28.0°
Contact drift
+0.0px
Smoothness σ
0.00
Shoulder
nominal
Bow analysis demo
recorded demo
docs/assets/bow_metrics_demo.gif
Recorded bow-analysis demo.
Why it matters

Beginners raise the shoulder and drift the bow without ever seeing it.

Stiff wrists, a lifted bow-side shoulder, a stroke that wanders off straight — these happen below a player's awareness. This project converts them into motion metrics and an overlay you can actually watch, so the correction has something to point at.

  • Computer vision for human-movement tracking
  • Geometry-based technique metrics
  • Musician-focused feedback loops
  • A clean path to real-time and embedded deployment
  • An optional IMU extension for sensor fusion
  • A desktop IMU Studio for capture, labeling, and 3D motion
In this first version
01

Pose landmarks

Tracks right shoulder, elbow, and wrist with MediaPipe Pose.

02

Bow-arm angle

Estimates the arm angle from elbow to wrist, frame by frame.

03

Wrist path

Records the wrist trajectory over time to expose drift.

04

Shoulder elevation

Measures rise above a relaxed neutral baseline.

05

Motion smoothness

Estimates jerk from changes in stroke velocity.

06

Live overlay

Renders technique feedback straight onto the video.

07

Webcam or file

Runs on a live camera or a recorded clip, with optional saved output.

08

Clip analyzer

A single tool for bow, posture, or combined feedback.

09

IMU Studio

Desktop capture: serial connect, labeling, CSV, live 3D motion.

Example outputs

Sample frames from real clips.

Reference frames showing how the analyzer adapts to different camera angles and visible technique cues.

How the metrics work

Four signals, each one geometry you can read off the frame.

If a clip can't support confident bow tracking, the analyzer falls back to posture-only feedback instead of forcing noisy numbers. Here's the math behind each signal — exactly what the overlay above is computing.

baseline_y elevation

Shoulder elevation posture

The vertical rise of the bow-side shoulder above a relaxed baseline. In clips where the shoulder is visible, the analyzer flips into a posture overlay and flags tension cues; right now it's a visual coaching layer rather than a full landmark measurement.

python
if shoulder_baseline_y is None:
    shoulder_baseline_y = shoulder.y

shoulder_elevation = max(0.0, shoulder_baseline_y - shoulder.y)
θ (x1,y1) (x2,y2)

Bow-arm angle bow

For bow-visible clips, the analyzer fits the bow line and reports how far it drifts from a flatter stroke. angle_error_deg is the absolute deviation from that reference direction.

python
import math

angle_deg = math.degrees(math.atan2(y2 - y1, x2 - x1))
angle_error_deg = abs(((angle_deg + 90.0) % 180.0) - 90.0)
string_center

Wrist path & contact drift bow

The bow demo trails the contact point where the stroke crosses the strings — making drift, direction, and consistency visible frame to frame. The contact point is the intersection of the bow line with the string-center reference; drift is measured against the first stable point.

python
t = (string_center_x - x1) / (x2 - x1)
contact_y = y1 + t * (y2 - y1)

if contact_baseline_y is None:
    contact_baseline_y = contact_y
contact_drift = contact_y - contact_baseline_y
speed_t

Motion smoothness bow

Estimated from how much stroke speed fluctuates over time. Large swings read as jerky bowing; steadier values read as a smooth stroke. Lower σ is better.

python
import numpy as np

speed_history.append(speed_t)   # dist(midpoint_t, midpoint_t-1)
smoothness = float(np.std(np.diff(np.array(speed_history))))
Optional IMU extension · camera-first by design

A bow-mounted sensor, only once vision hits its limit.

The core repo works with no special hardware. The optional path mounts an ESP32-C3 SuperMini and a small inertial sensor on the bow to add roll, angular velocity, and jerk — fused with the video metrics rather than replacing them.

BowTrack IMU prototype side view
side view
prototype side.jpeg
BowTrack IMU prototype back view
back view
prototype_back.jpeg
Bow-mounted prototype — IMU + ESP32-C3 ride directly on the bow.
PROTOTYPE · ESP32-C3 + IMU · SCHEMATIC
ESP32-C3 IMU x y z
Schematic — both IMU and microcontroller ride on the bow.
ComponentApprox.Source
GY-85 9-axis IMUITG3205 + ADXL345 + HMC5883L. Bow-mounted, requires soldering. $4.38 AliExpress ↗
ESP32-C3 SuperMini ×2Microcontroller board, requires soldering. $5.49
/ two
Temu ↗
WEP 926LED V3 soldering station130W kit: solder wire, 5 tips, tweezers, sucker, cleaner, temp control. $29.99 Amazon ↗
BowTrack IMU Studio

A motion-capture workspace, not a serial monitor.

The desktop companion treats the bow like a capture subject: connect, name a session, label takes for different gestures, and record to CSV — with live plots and a 3D acceleration-space view alongside.

  • Live serial connection to the ESP32-C3
  • Session naming and note-taking
  • Take labeling for different bowing gestures
  • CSV recording for later analysis
  • Live acceleration and gyro plots
  • Live 3D acceleration-space visualization

The 3D panel shows the changing ax, ay, az vector in space — useful for intensity and direction. Not yet a full reconstructed bow-position tracker.

ACCELERATION-SPACE · ax / ay / az
ax az ay
Illustrative — the live vector swings with motion intensity.
Setup

From clone to live overlay in a few commands.

Install

Core camera tracker

bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Desktop GUI on macOS

BowTrack IMU Studio

bash
python3.12 -m venv .venv312_gui
source .venv312_gui/bin/activate
pip install PySide6 pyqtgraph pyserial numpy PyOpenGL
python3 src/bowtracker_desktop.py

Usage

Analyze a sample clip

bash
python3 src/clip_analyzer.py \
  --input path/to/clip.mp4 \
  --out-dir results/clip_run

Run on a webcam

bash
python3 src/main.py --camera 0

Save output, hide preview

bash
python3 src/main.py \
  --input data/sample_video.mp4 \
  --output results/output_demo.mp4 --no-display

Force an analysis mode

bash
python3 src/clip_analyzer.py \
  --input path/to/clip.mp4 \
  --out-dir results/clip_run --mode combined
▶ py

Python compatibility. The prototype targets the classic MediaPipe solutions API, so Python 3.10–3.12 is safest. On 3.14, pip install mediapipe ships the Tasks-oriented layout, which omits mediapipe.solutions and stops the tracker from starting. For the macOS IMU viewer, 3.12 is also recommended — the PySide6 stack is more reliable there.

Project structure
cello-bow-motion-tracker/ ├── README.md ├── requirements.txt ├── platformio.ini ├── data/ ·gitkeep ├── demo/ ·gitkeep ├── docs/ │ ├── assets/ sample frames + prototype photos │ ├── esp32_gy85_accel_logger.ino │ └── imu_esp32_extension.md ├── results/ ·gitkeep └── src/ ├── clip_analyzer.py single-clip tool ├── bowtracker_desktop.py IMU Studio ├── main.py camera tracker ├── main.cpp ESP32 firmware ├── bow_detector.py ├── metrics.py ├── pose_tracker.py └── visualize.py
Planned next steps

Where the tracking goes next.

→ 01

Detect the bow itself with Hough line detection

→ 02

Estimate bow straightness across each stroke

→ 03

Approximate bow distance from the bridge

→ 04

Add posture and technique scoring

→ 05

Compare a student recording against a reference performance

→ 06

Deploy on Jetson with low-latency camera capture

→ 07

Add the ESP32 + IMU path for orientation and smoothness sensing

Research context

Grounded in prior bow-sensing work — mostly violin, treated as a starting point.

Most directly relevant literature studies violin rather than cello, so these are strong references rather than one-to-one validation for cello technique.

IMU vs MOCAP

A Machine Learning Approach to Violin Bow Technique Classification

Dalmazzo, Tassani & Ramírez

A professional violinist performed détaché, martelé, spiccato, and ricochet, captured by both high-precision MOCAP and a low-cost Myo armband. The Myo-based classifier slightly edged out the MOCAP one — useful feedback may not need expensive capture if the features are discriminative enough.

99.85%Myo · J4899.46%MOCAP
Read the paper ↗
Interface design

Rethinking Instrumental Interface Design: The MetaBow

Alonso Trillo, Nelson & Michailidis

Argues interface design is the real bottleneck: a device can produce good data yet fail if it's bulky or alters bow balance. MetaBow preserves traditional mechanics and frames a measurement space — speed, tilt, location, force, bridge distance, inclination, finger pressure — that maps cleanly onto this project's direction.

7parameter measurement space
Read the paper ↗
What to test next
D1

Build a labeled dataset around the four techniques: détaché, martelé, spiccato, ricochet.

D2

Train a lightweight classifier on bow angle, bridge offset, contact drift, and smoothness, then test how well they separate the strokes.

D3

Add repeatability tests: multiple takes of the same articulation, checking metric stability.

D4

Test reference feedback by comparing a student take against an expert clip, TELMI-style.

M1

Expand toward the MetaBow space: bow speed, tilt, bridge distance, force and finger-pressure proxies.

M2

Run camera-placement experiments — front, front-right, side — to see which views recover those parameters.

M3

Validate the interface itself: stays nonintrusive and usable during normal practice.

M4

Only add optional sensor fusion when single-camera vision hits its limit — keep the core low-cost.