61 Commits
Author SHA1 Message Date
Kristian Myram 76f82d7d55 #1539: clarify fallback visibility and benchmark correction rounds 2026-10-30 08:53:17 +01:00
Kristian Myram baa1ca31b3 #1539: preserve stroke corrections and current main APIs 2026-10-30 08:49:47 +01:00
Kristian MyramandClaude Sonnet 5.5 08bf6e43fe S2.69: several objects in one Roto Brush instance, tracked in one SAM 2 pass
Strokes carry an object (0 for older projects, nothing written for 0). The
tracker follows every object in one pass and the mattes are united; the
confidence of a frame is the least sure object's. Object picker in the Layer
panel's bar; roto.options/stroke/clearStrokes/status take or report objects.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 08:43:32 +01:00
Kristian MyramandClaude Sonnet 5.5 65c5eda39a S2.53: bench --roto takes the user's own clips and reports peak memory
--clip FRAMES_DIR --truth MASKS_DIR runs the trackers on image sequences with true
mattes (strokes made from the truth; nothing is bundled or copied), tested end to end.
Trackers report the most memory their banks held (peakMB column).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 08:43:31 +01:00
Kristian MyramandClaude Sonnet 5.5 a39cee8104 S2.51: bench --roto --fixes counts the corrections each tracker needs
Simulated user paints a foreground stroke through the true object and a background
stroke on the biggest false positive on the first frame under IoU 0.9, up to 6
rounds. SAM 2 needs none on every clip; classical and MobileSAM need more than 6 on
occlusion and re-entry. All trackers now take strokes on any frame.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 08:43:31 +01:00
Kristian MyramandClaude Sonnet 5.5 7eb91ca44c S2.43: track several objects in one SAM 2 pass
TrackRequest takes a list of objects (each with its prompts on its frames) and
the tracker reports (object, frame, result); frame encodings are shared, objects
may start on different frames. VideoTracker::propagate_objects runs a subset.
Limits: 32 objects. Test: two discs, one prompted on frame 0 and one on frame 2.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 08:43:31 +01:00
Kristian MyramandClaude Sonnet 5.5 1fb51600d5 S2.65: prompt SAM 2 with a box from the classic matte on stroke frames
On real footage the stroke frame came out partial (clicks make SAM 2 pick a
part of the object). Measured on a multi-part figure: clicks only IoU 0.41,
with a box around the figure IoU 1.00. Chain::track now adds the box of the
classic engine's matte of the strokes to each prompt; a box stroke wins.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 08:43:31 +01:00
Kristian MyramandClaude Sonnet 5.5 4655425d01 S2.50: bench --roto adds the SAM 2 tracker column
run_tracker follows the object with the model's video tracker on the same
synthetic clips (--sam2 FILE or the installed weights). 12 frames, dev build:
re-entry clip mean IoU 0.632 classical vs 0.975 SAM 2 (0.000 vs 0.967 after
the object returns); the other clips 0.98 vs 0.99.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 08:43:30 +01:00
Kristian MyramandClaude Sonnet 5.5 c1f5ff9f7d S2.41: Roto Brush follows the object with SAM 2
When the chosen model has a tracker, roto.propagate runs one tracking pass over
the span: prompts from the strokes (a handful of points, which SAM 2 trusts),
the clip tracked both ways, each frame's probability map refined by the same
graph cut with the strokes as hard constraints. Results are cached under their
own keys with a per-frame confidence and an occluded flag; roto.status reports
them (source: tracker|classical). Without a tracker nothing changes.
Real weights: IoU 0.98 on all 21 frames, confidence 0.99.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 08:43:30 +01:00
Kristian MyramandClaude Sonnet 5.5 71e44deb84 S2.50: effectcraft-cli bench --roto on synthetic clips
Synthetic Roto Brush clips with known mattes (movement, lighting change,
occlusion, leaving and re-entering) and a runner that compares the classical
engine with MobileSAM when installed. Needs no weights; SAM 2 plugs in later.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 08:43:29 +01:00
vangel76andClaude Sonnet 5.5 06d5a6fc80 Merge upstream/main into camtrack-matrix-free-schur
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-29 20:32:17 +01:00
BFlat 7175a20f63 Merge pull request #1804 from tylerjenningsw/fix/roto-stroke-order
Roto Brush: apply correction strokes in drawing order (#1646)
2026-10-30 01:21:32 +07:00
BFlat 844e8899be Merge pull request #2351 from vangel76/point-two-stage-search
Point tracker: refine in a 3x3 neighbourhood when the motion was small
2026-10-30 01:17:52 +07:00
BFlat ec4b275e38 Merge pull request #2331 from vangel76/trkx-klt-window-weights
Tracker: Lucas-Kanade resolves its bilinear taps once per window
2026-10-30 01:13:38 +07:00
BFlat 1f9ebe3927 Merge pull request #2342 from vangel76/camtrack-banded-cholesky
Camera tracking: factor narrow camera systems within their band
2026-10-30 01:13:23 +07:00
BFlat e0009222d1 Merge pull request #2350 from vangel76/warp-share-luma-pyramid
Share the Warp Stabilizer luma pyramid with trajectory tracking
2026-10-30 00:11:42 +07:00
BFlat 77a8b1254f Merge pull request #2337 from vangel76/trkx-mask-crop-frames
Mask tracker: keep only the cropped previous frame
2026-10-30 00:11:26 +07:00
BFlat 61c3285ea3 Merge pull request #2340 from vangel76/camtrack-stack-jacobian
Camera tracking: keep bundle-adjustment Jacobians on the stack
2026-10-30 00:11:11 +07:00
BFlat ab084be82a Merge pull request #2345 from vangel76/camtrack-null-vector-svd
Camera tracking: skip unused SVD output work in null-vector queries
2026-10-30 00:10:58 +07:00
BFlat 77b4d76455 Merge pull request #2338 from vangel76/camtrack-triangulate-stack
Camera tracking: avoid per-view triangulation allocations
2026-10-30 00:05:56 +07:00
BFlat b771f171d0 Merge pull request #2341 from vangel76/camtrack-validate-input
Camera tracking: validate solver input and bound workspaces
2026-10-29 10:08:05 +07:00
vangel76andClaude Sonnet 5.5 b48798e1fb Merge upstream/main into camtrack-matrix-free-schur
Conflict in crates/track/src/camtrack/bundle.rs: kept both the branch's
PtSys/preconditioner/iterative_schur block and upstream's new
add_focal_prior helper. Adapted to upstream's explicit linalg imports
(conjugate_gradient, and I3/log_rot/mt/norm in the tests) and moved the
explicit point elimination into reduce_points so adjust_impl stays under the
cognitive-complexity lint.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 15:31:43 +01:00
vangel76andClaude Sonnet 5.5 1ec9947efb Merge upstream/main into camtrack-validate-input
Conflict in crates/track/src/camtrack/bundle.rs (imports): upstream replaced
the linalg glob import with an explicit list; kept that list and added the
branch's SolveError import (use super::{Distortion, SolveError}). Input
validation, size budget and Result-returning adjust/cost are unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 15:28:34 +01:00
vangel76andClaude Sonnet 5.5 130298ef82 Merge upstream/main into trkx-face-polygon-rows
Conflict in crates/track/src/face.rs: upstream moved the feature-blob search
into FaceTracker::feature_blobs. Re-applied the branch there: the per-pixel
point-in-polygon loop is replaced by non_skin_inside (one crossing pass per
window row) and the roll rotation is hoisted with face_mapper.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 15:24:18 +01:00
Dylan M. Taylor f26f30871c Refactor track for strict Clippy checks 2026-10-28 06:09:21 +00:00
tylerjenningsw b5460f653b Roto Brush: a correction keeps the model prompted with what is left of a stroke (#1646)
Dropping the points a later stroke of the other kind painted over could leave
a stroke with none, even though most of it was still painted: a small Alt tap
in the middle of a large foreground dot removed its only point, and the
selected model was skipped for the classical cut. Points are now kept by the
resolved ownership under them, and a stroke that loses every sampled point
but still owns pixels is prompted from the one deepest inside them. A stroke
painted over completely still prompts nothing.
2026-10-27 14:13:40 -04:00
tylerjenningsw 818ce2ab42 Roto Brush: model prompts follow the latest stroke (#1646)
A trained model is no longer prompted with both labels at one spot: points
along a stroke that a later stroke of the other kind painted over are
dropped, and the propagated matte's points, box and mask take this frame's
strokes over it.
2026-10-27 14:13:40 -04:00
tylerjenningsw af995ea26a Roto Brush: Refine Edge strokes apply in drawing order (#1646)
A Refine Edge stroke over an earlier Alt (erase) stroke now restores the band
there; the band carried from the previous frame stays under this frame's
strokes.
2026-10-27 14:13:40 -04:00
tylerjenningsw aae936e9bd Roto Brush: foreground and background strokes apply in drawing order (#1646)
A green stroke over an earlier Alt (red) stroke now restores the area: where
strokes overlap, the one painted last sets the hard constraint, for the cut,
the colour samples and the cleanup seeds alike.
2026-10-27 14:13:39 -04:00
vangel76andClaude Sonnet 5.5 6418c8c0a4 Merge upstream/main into camtrack-validate-input
Upstream split lib.rs files into modules and moved engine commands/ to cmd/; this branch's change merges without textual conflicts.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 17:51:50 +01:00
aiongg 9e246e3b9c refactor(track): move src/camtrack/mod.rs to src/camtrack.rs 2026-10-26 21:49:10 +00:00
aiongg bca13987d9 refactor(track): move src/roto/mod.rs to src/roto.rs 2026-10-26 21:49:10 +00:00
vangel76andClaude Sonnet 5.5 4b31e21a1d Point tracker: refine in a 3x3 neighbourhood when the motion was small
The fine stage searched a 5x5 neighbourhood per pyramid level and seed.
When the best coarse match is reliable (NCC score >= 0.8) and lies within
one top-level pixel of the motion prediction, a 3x3 neighbourhood is
enough; otherwise the 5x5 search stays.

Fixes #2349

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 00:51:00 +02:00
vangel76 247a0f14eb Share the Warp Stabilizer luma pyramid with feature tracking
Reuse consecutive caller-owned pyramids for regular Warp motion and trajectory tracking. Preserve the original three-level motion search by setting aside the trajectory-only extra level, without cloning planes. Keep detailed analysis at its existing distinct resolutions and test bitwise motion and complete JSON equality against separate pyramids.

Fixes #2322
2026-10-25 00:29:15 +02:00
vangel76 b813294fc8 Avoid quadratic Schur assembly for long tracks
Solve expensive camera systems with matrix-free Schur products and a block-preconditioned iterative solver. Check the true linear residual and fall back to the direct solve when convergence fails. Keep short systems on the existing path and compare reprojections, camera parameters and outlier decisions against direct solves.

Fixes #2328
2026-10-24 23:59:36 +02:00
vangel76 8dbb0f55af Skip unused SVD output work for camera null-space queries
Share the unchanged Jacobi factors between full SVD and null-vector callers. Select the same right singular vector directly instead of normalizing U and sorting copies that the caller discards.

Fixes #2329
2026-10-24 23:40:00 +02:00
vangel76 e5afbccbc7 Limit camera-system Cholesky work to its matrix band
Detect narrow lower-triangle bandwidth and skip structural zeros while preserving dot-product lanes and signed-zero arithmetic. Keep a dense fallback for wide systems and compare factors and solutions against the original algorithm.

Fixes #2325
2026-10-24 23:33:09 +02:00
vangel76 97b178f764 Validate camera solver inputs before indexing and allocation
Return errors for invalid bundle observations and oversized workspaces, reject non-finite projections and mismatched correspondence slices, and prevent track frame overflow. Cover the reported failures with synthetic regression tests.

Fixes #2330
2026-10-24 23:24:52 +02:00
vangel76 84f8fd8f63 Keep camera Jacobians on the stack during bundle adjustment
Use a bounded inline array for the current camera parameters and preserve the existing accumulation order. Extra parameters spill safely if the parameter set grows.

Fixes #2327
2026-10-24 23:12:36 +02:00
vangel76andClaude Sonnet 5.5 9e68fc47f7 Point tracker: share one tap table across the candidates of a search
The normalized cross-correlation only had a fast path for an exactly
identity shape, which tracked footage never has after the first frame, so
every candidate went through Plane::sample. All candidates of a search are
the reference centre plus integer offsets, so each template pixel has the
same fractional offsets for all of them. Build one table of taps per
(level, seed, shape) and score each candidate with integer-indexed lerps,
with one bounding-box check up front (outside the plane the old path is
used).

lk_refine only reads the level-0 gradients around the match, so compute
them for that window (with an interior fast path in Plane::gradients_in)
and fall back to the full gradients if the iteration leaves it.

The results are unchanged: same lerp form and accumulation order.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 23:07:24 +02:00
vangel76andClaude Sonnet 5.5 1c871333b1 Mask tracker: keep only the cropped previous frame
step() cloned the whole RGBA frame to remember it (33 MB at 1080p,
133 MB at 4K) and then cropped that clone, although only the region
around the outline is ever read. The tracker now stores the previous
frame already cropped to the region the next step will use, computed
from the updated outline with the same margin and rounding as before,
so the crops, and therefore the tracking result, are unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 23:06:54 +02:00
vangel76 f8c622b6cd Avoid per-view allocations in camera triangulation
Store the two four-element DLT rows in arrays while preserving arithmetic and accumulation order. This removes two heap allocations for every triangulated view.

Fixes #2326
2026-10-24 23:06:47 +02:00
vangel76andClaude Sonnet 5.5 72710481ee Face tracker: find polygon crossings once per window row
The feature mask tested every non-skin window pixel against the 48-edge
face outline (about 25 M edge tests per frame). A scanline hits the same
edges for every pixel of a row, so the crossings are now computed once
per row with the same expression and comparisons as inside_polygon, and
a pixel's parity follows from how many lie to its right. The face-frame
rotation is also worked out once per frame instead of once per blob
pixel.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 23:02:52 +02:00
vangel76andClaude Sonnet 5.5 95721b8449 Tracker: Lucas-Kanade resolves its bilinear taps once per window
Every pixel of a (2r+1)^2 window shares one fractional offset per level
and iteration, but lk_point called Plane::sample (with a libm floor, a
bounds test and the clamp path) up to three times per pixel. The offset
and the clamped column/row index tables are now computed once per
window and the pixels run the same lerps on integer indices.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 23:00:12 +02:00
Dylan M. Taylor 09b9ebca34 roto: bound frozen matte decoding and serialization (#2194)
* roto: bound frozen matte decoding and serialization

* roto: address review (fallible RLE growth, pre-check plane bytes, saturate 32-bit limits)
2026-10-23 08:59:06 -04:00
Brandon ThomasandClaude Opus 5.5 f2d481ce20 Tracker: the 1080p timing test takes the fastest step, so a loaded FreeBSD VM doesn't fail it
The nightly FreeBSD run measured 119 ms/frame against a 100 ms limit: the mean included
Tracker::new and any scheduling stalls on the two-core VM. The best single step with a
250 ms bound still catches an order-of-magnitude regression.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:47:27 -04:00
vangel76andClaude Opus 5.5 4fc7b52351 #783: Object Matte passes its box to the model as a box prompt
Problem: with a trained model installed, Object Matte's optional box reached
MobileSAM only as background points along the box's edges (an approximation),
although the model's prompt encoder takes a box prompt directly.

Fix: a new Roto Brush stroke kind, Box (two opposite corners), that
stroke_prompt turns into the model prompt's bbox (scaled to the matte grid,
corners in any order, degenerate or non-finite boxes ignored). The graph cut
never rasterizes it. Object Matte emits it instead of the edge strokes when a
model segments; the classical fallback keeps the edge strokes. A prior matte's
box no longer replaces a box the user drew on that frame.

Tests: effects object_matte::the_box_reaches_the_model_as_a_box_prompt (a
stand-in model sees the box, at full and half resolution, and no edge points);
track roto::tests::box_stroke_is_the_model_box_prompt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:38:10 +02:00
Dexter 39e6907b5f G2: improve editing reliability and Windows rendering fidelity 2026-10-06 00:00:31 -05:00
bflatasticandClaude Opus 5.5 e43bf66775 M13.36: face tracking trained model — MediaPipe Face Landmarker on a pure-Rust TFLite interpreter
- effectcraft-segment: a FaceModel interface (find a face in a region, follow it; a Topology
  maps the model's points to the tracker's landmarks and outline), a TensorFlow Lite reader and
  interpreter (float ops, float16 weights folded; matches ai-edge-litert to ~1e-6), and
  MediaPipe Face Landmarker (Google, Apache-2.0: BlazeFace + Face Mesh V2, 3.8 MB, pinned
  SHA-256). The registry gains a task and authors per model; installed weights get a NOTICE.
- effectcraft-track: FaceTracker::new_with uses the model, falls back to the classical fitter
  when it finds no face; chin and jaw come from the outline either way so measurements agree.
- Engine: roto_models becomes models (both tasks); face.models / face.model.* commands,
  Settings ▸ Face Tracking, `wait` on select/install/download for scripts; track.mask reports
  faceModel.
- Credits: ATTRIBUTION.md lists the optional models and the Apache-2.0 specs the code follows.
- Docs: README, ROADMAP (G7), gaps, parity (TRK-3 score unchanged pending G1), agents,
  preferences, architecture, segment README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 20:39:45 +07:00
bflatasticandClaude Opus 5.5 7579de21c6 M13.35: Roto Brush trained model — swappable segment module, MobileSAM in pure Rust
- New L1 crate effectcraft-segment: the MaskModel interface (prompts → foreground probability),
  a registry of open-licensed models (licence must be MIT/Apache/BSD/…; URL, size, SHA-256),
  a PyTorch checkpoint reader (zip + pickle subset), dependency-free SHA-256, and MobileSAM
  (TinyViT-5M + SAM prompt encoder / two-way transformer / mask decoder) on rayon and ndarray's
  safe GEMM. Loads the official mobile_sam.pt as published; checked against candle
  (embedding 0.3% RMS, 99.9% equal mask pixels); ~0.7 s/frame encoder at 32 threads, cached
  per frame, ~0.1 s decoder.
- track::roto: segment_with / propagate_with prompt a model with the strokes or the flow-warped
  matte (box, core points, mask); its probability is a strong, unblurred prior for the same
  graph cut (strokes stay hard constraints); a failing model or one disagreeing with the flow
  (IoU < 0.5) is ignored. Prior gets a weight.
- effects::roto: Version 2.0 / 3.0 use the model chosen in Settings (set_model / model_for);
  the model id is part of the chain seed.
- engine: roto_models (roto.models, roto.model.select / install / download / remove), weights in
  the models folder (host::config_dir()/models, shared by the app, CLI and MCP), background
  loading, downloads through the system curl, verified; Settings ▸ Roto Brush page (prefs
  roto.model). host::config_dir moved from the desktop app.
- Tests: segment (kernels vs direct sums, checkpoint reader, SHA-256 vectors, registry), track
  (fake model: prior shapes the cut, failing / disagreeing models ignored; real weights with
  EFFECTCRAFT_MOBILESAM: base IoU 0.989, propagated ≥ 0.980 vs classic 0.973), engine (registry,
  verification, selection; real install + load), MCP.
- Docs: README, ROADMAP, parity (MSK-4 done: 90/2/0), preferences, agents, architecture,
  crates/segment/README.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 17:55:02 +07:00