Commit 716cbdf
feat(kpm): port FREAK descriptor + Keyframe to Rust (M8 step 4)
Port the C++ FREAKExtractor + Keyframe + FindFeatures orchestration to
two new Rust sibling modules under crates/core/src/kpm/freak/, and
replace the M7 find_features stub in hough.rs with a real
vision::FindFeatures-style orchestrator. This is the final step of
Milestone 8 — the FREAK pipeline is now end-to-end runnable in pure
Rust (pyramid -> DoG detector -> FREAK descriptor -> FeatureStore).
New: crates/core/src/kpm/freak/descriptor.rs (~390 lines)
- FREAK_DESCRIPTOR_BYTES = 96 const (storage layout: 84 data + 12 zero
padding, matches C++ BinaryFeatureStore and M7 hamming_distance_96)
- 7 sigma + 6 ring [f32; 12] constants ported verbatim from
matchers/freak84-inline.h (no rounding, no reorder)
- mExpansionFactor = 7.0 const
- extract_freak_descriptors(pyramid, keypoints, &mut Vec<u8>) free fn
- Private sample_pyramid_freak84 / sample_ring / sample_pyramid_at
helpers mirroring C++ SamplePyramidFREAK84 sample order
(ring5 -> ring4 -> ... -> ring0 -> center)
- LSB-first bit packing via `desc[pos/8] |= 1 << (pos%8)` matches
C++ bitstring_set_bit; 666 pairs (0 <= i < j < 37) with the
less-than comparison from CompareFREAK84
- 5 unit tests (length single/multiple, padding zero, empty input,
reproducibility) + 1 dual-mode FFI parity test
New: crates/core/src/kpm/freak/keyframe.rs (~110 lines)
- Passive container Keyframe { store, width, height } mirroring C++
vision::Keyframe<96>. No build() method — orchestration lives in
find_features (matches C++ FindFeatures architecture).
- 2 unit tests (constructor wiring; find_features populates the
store on found.jpg)
Replaces: crates/core/src/kpm/freak/hough.rs find_features stub
- Removes the Keyframe placeholder struct from M7
- Implements the real find_features(keyframe, pyramid, detector)
mirroring C++ vision::FindFeatures from visual_database.h:
1. detector.detect(pyramid)
2. project rich DoGFeaturePoint -> persistent FeaturePoint via
the M8-3 From<&DoGFeaturePoint> impl
3. extract_freak_descriptors(pyramid, &points, &mut buf)
4. populate keyframe.store via FeatureStore::add
Dual-mode FFI bridge (kpm_c_api.{h,cpp}):
- webarkit_cpp_extract_freak_descriptors: Rust supplies the keypoint
list (4 floats per keypoint: x, y, angle, scale), C++ builds the
pyramid + runs FREAKExtractor::extract, returns 96 bytes per
keypoint (84 data + 12 zero padding from BinaryFeatureStore layout).
- This factors out detection variance and tests the descriptor
algorithm in isolation.
Design choices (see docs/design/m8-4-freak-descriptor.md for full
decision log):
- Faithful C++ port (Option A): 96-byte storage with 84 data bytes
packed via < comparison and LSB-first bit packing
- Module split (orientation pattern from M8-2/M8-3): descriptor.rs
for the algorithm + keyframe.rs for the container
- M8-3 deferred OrientationAssignment items NOT absorbed in this PR —
YAGNI: the FREAK descriptor samples the Gaussian pyramid directly,
not gradient images. Tracking moved to issue #138.
- Free function `extract_freak_descriptors(... &mut Vec<u8>)` instead
of marker struct or stateful extractor — C++ "state" is all
constants (naturally `const` at module scope in Rust).
- Caller-owns orchestration model: find_features as a free function
in hough.rs (matches C++ vision::FindFeatures architecture).
Empirical result (Windows MSVC, clean rebuild): the dual-mode test
shows |diff| = 0 across all 10 top-keypoint descriptors (Hamming
distance = 0). The tolerance is kept at 2 in source to absorb
potential cross-platform variance; CI will reveal whether it can be
tightened to 0 across all platforms in a follow-up.
Tests (8 total, all passing):
- descriptor.rs: 5 unit tests + 1 dual-mode FFI parity test
- keyframe.rs: 2 unit tests
- Full dual-mode sweep: 391 passed, 0 failed, 2 ignored
Harris detector intentionally NOT ported (dead code from removed SURF
pipeline). M8-3-deferred OA items intentionally NOT absorbed (no real
consumer in M8-4; tracked in #138).
refs #125 #129
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>1 parent 6ec758c commit 716cbdf
7 files changed
Lines changed: 949 additions & 12 deletions
File tree
- crates/core/src/kpm
- freak
- docs/design
0 commit comments