Skip to content

feat(#44): detect features on downsampled frame (part A) - #52

Merged
kalwalt merged 1 commit into
webarkit:devfrom
kalwalt:feat/detection-downsampling-44
Jun 18, 2026
Merged

feat(#44): detect features on downsampled frame (part A)#52
kalwalt merged 1 commit into
webarkit:devfrom
kalwalt:feat/detection-downsampling-44

Conversation

@kalwalt

@kalwalt kalwalt commented Jun 18, 2026

Copy link
Copy Markdown
Member

What

Restore ArtoolkitX-style detection-side pyramid downsampling (part A of #44). Feature detection now runs on a pyrDown'd copy of the live frame (detectionFrame); matched frame keypoints are scaled back to full-frame coordinates before the homography fit.

Why

Detection previously ran at full resolution every frame — expensive on HD inputs. Downsampling cuts that cost on frames larger than featureImageMinSize (640×480). This also makes the keypoint rescale from #43 correct by construction (detection is genuinely downsampled), instead of the _featureDetectScaleFactor = 1 workaround.

Changes (WebARKitTracker.cpp)

  • initialize() — compute _featureDetectPyrLevel from featureImageMinSize (clamped ≥ 0) and the exact cv::pyrDown scale factor via the iterative (x+1)/2 rounding (sub-pixel-accurate rescale).
  • processFrame() — build detectionFrame via _featureDetectPyrLevel pyrDown steps; run createFeatureMask/extractFeatures on it.
  • MatchFeatures() — rescale matched frame keypoints by _featureDetectScaleFactor before getHomographyInliers.
  • createFeatureMask() — divide the warped bbox by the scale factor so the tracked-marker exclusion lands in downsampled coordinates.

Compatibility

  • Level 0 (frame ≤ featureImageMinSize, e.g. 640×480) ⇒ detectionFrame == frame, factor 1.0byte-identical to full-res detection.
  • The reference image stays detected at full resolution (initTracker); only the live frame is downsampled — matches ArtoolkitX OCVT.

Testing

Verified on the Teblid static-image example at 1920×1440 (pyrLevel 1, scale factor 2.0): Marker tracked! Num. matches: 1000, content correctly centered (#38) and right-handed (#42/#46), no #43-style doubling.

ℹ️ Downsampling only acquires when the marker fills the frame at HD; a small marker in a large frame can fall below the detector's threshold once downsampled.

Scope

Part A only. The "skip detection while tracking" guard is a separate follow-up (part B).

🤖 Generated with Claude Code

Restore ArtoolkitX-style detection-side pyramid downsampling: feature
detection now runs on a pyrDown'd copy of the live frame (the
"detectionFrame"), and matched frame keypoints are scaled back to
full-frame coordinates before the homography fit.

- initialize(): compute _featureDetectPyrLevel from featureImageMinSize
  (clamped >= 0) and the exact cv::pyrDown scale factor via the iterative
  (x+1)/2 rounding, so the keypoint rescale is sub-pixel accurate.
- processFrame(): build detectionFrame via _featureDetectPyrLevel pyrDown
  steps; run createFeatureMask/extractFeatures on it.
- MatchFeatures(): rescale matched frame keypoints by
  _featureDetectScaleFactor before getHomographyInliers.
- createFeatureMask(): divide the warped bbox by the scale factor so the
  tracked-marker exclusion lands in downsampled coordinates.

Level 0 (frame <= featureImageMinSize, e.g. 640x480) => detectionFrame ==
frame and factor 1.0, so that path is byte-identical to full-res detection.
The reference image stays detected at full resolution (initTracker), only
the live frame is downsampled, matching ArtoolkitX OCVT.

This is part A of webarkit#44. The "skip detection while tracking" guard is a
separate follow-up (part B).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kalwalt kalwalt self-assigned this Jun 18, 2026
@kalwalt kalwalt added enhancement New feature or request C/C++ code concerning the C/C++ code design and improvements Emscripten labels Jun 18, 2026
@kalwalt kalwalt moved this from To do to In progress in New markerless image tracking Jun 18, 2026
@kalwalt kalwalt moved this from In progress to Review in progress in New markerless image tracking Jun 18, 2026
@kalwalt kalwalt moved this from Review in progress to Reviewer approved in New markerless image tracking Jun 18, 2026
@kalwalt
kalwalt merged commit 4308af6 into webarkit:dev Jun 18, 2026
@github-project-automation github-project-automation Bot moved this from Reviewer approved to Done in New markerless image tracking Jun 18, 2026
kalwalt added a commit to webarkit/webarkit-testing that referenced this pull request Jun 18, 2026
…xample

Bump WebARKitLib to the part-A downsampling change (webarkit/WebARKitLib#52)
and rebuild build/ + dist/. Feature detection now runs on a pyrDown'd copy
of the live frame; matched keypoints are rescaled to full-frame coords.

- examples: point the Teblid static-image example at a marker-fills-frame
  1920x1440 demo image (pinball-demo-big.jpg) so HD downsampling is
  exercised (pyrLevel 1, scale 2.0) and the marker still acquires. The old
  pinball-demo.jpg (small marker in a large frame) falls below the detector
  threshold once downsampled.
- docs: add docs/design-detection-downsampling.md (understanding, ArtoolkitX
  reference, decision log, the four edits, testing, risks, non-goals).

Verified: Marker tracked, 1000 matches, content centered (#38) and
right-handed (#42/#46), no #43-style doubling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
kalwalt added a commit that referenced this pull request Jun 19, 2026
Guard the per-frame feature detection (extractFeatures + descriptor
matching) with `if (!_isTracking)`. Once optical flow holds a lock,
detection is skipped and the pose is maintained by optical flow + template
matching; when the marker is lost (_isTracking cleared in runOpticalFlow /
RunTemplateMatching), detection resumes on the next frame to re-acquire.

Detection is the dominant per-frame cost, so skipping it in the steady
tracking state is a large win: at 640x480 the webcam example goes from
~10-15 fps (detecting every frame) to ~45 fps while tracking. This is
part B of #44; part A (detection-side pyramid downsampling) landed in #52.

The guard is on _isTracking rather than ArtoolkitX's
`_currentlyTrackedMarkers < _maxNumberOfMarkersToTrack`: _isDetected is
reset to false every frame, and optical flow is skipped on the first
detection frame (_frameCount == 0), so a counter-based guard would skip
both detection and optical flow on the following frame and freeze (this
bites the static-image example, which feeds the same frame repeatedly).
Gating on _isTracking re-detects until optical flow actually holds a lock.

The optical-flow/template/pose paths (gated on _isDetected || _isTracking)
and #46 tracking-loss are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
kalwalt added a commit to webarkit/webarkit-testing that referenced this pull request Jun 21, 2026
…xample

Bump WebARKitLib to the part-A downsampling change (webarkit/WebARKitLib#52)
and rebuild build/ + dist/. Feature detection now runs on a pyrDown'd copy
of the live frame; matched keypoints are rescaled to full-frame coords.

- examples: point the Teblid static-image example at a marker-fills-frame
  1920x1440 demo image (pinball-demo-big.jpg) so HD downsampling is
  exercised (pyrLevel 1, scale 2.0) and the marker still acquires. The old
  pinball-demo.jpg (small marker in a large frame) falls below the detector
  threshold once downsampled.
- docs: add docs/design-detection-downsampling.md (understanding, ArtoolkitX
  reference, decision log, the four edits, testing, risks, non-goals).

Verified: Marker tracked, 1000 matches, content centered (#38) and
right-handed (#42/#46), no #43-style doubling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C/C++ code concerning the C/C++ code design and improvements Emscripten enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant