Skip to content

feat(freak): FREAK descriptor, bit-exact with OpenCV 4.10.0 (#80) - #258

Open
kalwalt wants to merge 11 commits into
devfrom
feat/80-freak
Open

kalwalt wants to merge 11 commits into
devfrom
feat/80-freak

Conversation

@kalwalt

@kalwalt kalwalt commented Oct 30, 2026

Copy link
Copy Markdown
Member

Closes #80

Adds jsfeatNext.freak, the FREAK binary descriptor (Alahi, Ortiz and Vandergheynst, CVPR 2012). It is ported from opencv_contrib 4.10.0 freak.cpp (FREAK_Impl). It is bit-exact with cv2.xfeatures2d.FREAK_create(...).compute on three outputs: the descriptor bytes, the kept keypoints and their order, and the angles. The comparison has no tolerance and drops no input. Bit-exactness is what lets the PureCV backend (webarkit/purecv#103) produce identical results.

Spec and plan: docs/superpowers/specs/2026-10-30-freak-design.md and docs/superpowers/plans/2026-10-30-freak.md (merged in #257).

API

const kept = jsfeatNext.freak.describe(src /* U8C1 */, corners, count, descriptors, {
    orientation_normalized: true, scale_normalized: true, pattern_scale: 22, n_octaves: 4, // OpenCV's defaults
});
// corners[0..kept) are the described keypoints; descriptors is 64 x kept, U8C1

Decisions (F1–F6, approved)

  • F1, pattern on demand, no 8.5 MB table. OpenCV's buildPattern stores 64 scales × 256 orientations × 43 points, about 8.5 MB. Here a point is recomputed from buildPattern's double expressions when it is needed. Resident memory:
    • 2266 B of module-level tables: the 512 pairs (Int16, plus two Uint8 index arrays), the 45 orientation pairs, and the ring radii and sigmas.
    • Per call, about 2 KB of constants and scratch: 1384 B of scaling factors, pattern sizes and weights, 688 B of scale-0 points, and the 43 means.
    • Per call, 4 B per keypoint.
    • The integral image, a Float64 buffer of (cols+1)·(rows+1) entries borrowed from the shared pool and returned in a finally.
  • F2, border keypoints are dropped as OpenCV drops them. corners is compacted in place: the order is stable, the objects are moved rather than copied, and corners[count..] is untouched. describe returns the kept count, and row i belongs to corners[i].
  • F3, all four OpenCV options are exposed, with OpenCV's defaults.
  • F4, the ground truth follows TEBLID's rules. Fixtures come from the pinned opencv-contrib-python==4.10.0.84 with IPP off, generated on this Windows x86-64 machine; meta.platform and meta.compiler are recorded.
  • F5, the angle is OpenCV's, written in radians as float32(deg) · 0.017453292519943295. It lies in (−180°, 180°], negative values included, and is never wrapped into [0, 360). FREAK followed by TEBLID diverges from OpenCV for negative angles. Both TSDocs say so, and teblid.ts's sentence claiming that OpenCV angles are never negative has been corrected.
  • F6, the licence. freak.cpp is BSD-3-Clause (© 2011-2012 EPFL), not Apache-2.0. Its notice ships verbatim as LICENSES/BSD-3-Clause-FREAK.txt. A new opencv-freak header variant applies to src/freak/. The bundle banner names the file and the holder. AGENTS.md, CLAUDE.md, the licence-header skill and the agent-instruction mirrors are updated.

Fixtures and parity

tests/fixtures/opencv/freak.json has 11 cases, all bit-exact:

  • On the committed scene: the defaults, orientation_normalized=false, scale_normalized=false, pattern_scale=8, and n_octaves = 3 and 8. A 90°-rotated copy of the scene, and a flat image (which pins atan2(0, 0)), are added.
  • Border thresholds: each side and corner at patternSizes[s] − 0.5, exactly at it, and + 0.5, for scales 0 and 40. The generator replicates the drop logic and exits non-zero if it disagrees with OpenCV.
  • Sizes: one per scale step from below 7 to above 112. Scale 63 is reached.
  • An integer-only procedural texture (320×240, rebuilt in the TS tests and checked against its sha256). It exists because the scene is low-contrast: 125 of 164 default angles there are 0. The texture gives 168 distinct thetaIdx values and 147 negative angles at the defaults, and its rotated copy provides the rotation property test, whose Hamming bound comes from OpenCV.
  • Floating-point findings: the fixtures confirm that MSVC's atan2 here is the float overload (atan2f); the double overload fails 9 of 11 cases. No maths-library ulp mismatch was found, so nothing was escalated.

The bilinear branch. meanIntensity takes it for radius < 0.5, which pattern_scale = 8 reaches. It is ported with OpenCV's bug as is: it adds 2·1024² and divides by 4·1024², so it returns about a quarter of the intensity. The pattern_scale=8 case matches only because of that, and the TSDoc says so.

Beyond OpenCV: if patternSizes would overflow int (UB in OpenCV, for an extreme n_octaves with a huge size), the keypoint is dropped instead of being described from out-of-buffer reads. The value is identical to OpenCV's wherever OpenCV is defined.

Size and tree-shaking

before after delta
UMD dist/jsfeatNext.js raw / gzip 88180 / 30724 95071 / 33645 +6891 / +2921
ESM dist/jsfeatNext.mjs raw / gzip 138182 / 35767 148013 / 39056 +9831 / +3289

A Vite bundle of { imgproc } is unchanged (23262 / 8198) and contains no FREAK code; tests/build/bundle.test.ts checks the 404,431,818,511,181 marker. A bundle of { freak, … } is 30087 / 11476.

Bench: committed, not yet measured

bench/freak.bench.ts is committed but not measured yet. The machine stayed above the 20% CPU-load gate: 59 gated attempts were discarded, with in-run peaks of 72–79% from other load. The gate stays strict, and the numbers and the bench/README.md section follow in a later commit.

The bench has two groups:

  • the plan's size-31 workload, where FREAK keeps 132 of 300 keypoints because its pattern does not fit around the rest, as in OpenCV;
  • a size-7 workload, where all 300 are kept and the per-keypoint ratio is like-for-like.

Example

examples/sample_freak.html shows two views of pinball.jpg (rotated 30°, scaled 0.8), FAST corners with size = 31, and no ic_angle: FREAK writes the angle, and the page draws it as a tick. It matches with knnMatch and the 0.75 ratio test.

Checked in a browser: 302 and 480 keypoints kept, 140 matches of which 133 agree with the known transform, and no console errors.

Checks

npm test (776 passed, 1 skipped), npm run typecheck, prettier --check ., check-license-headers.mjs and npm run build-ts are all green, and every commit is GPG-signed.

Note for the merge: commit fix(freak): drop keypoints whose pattern size overflows fixes code that was never released. Squash-merging, or rewording it, keeps a spurious "Bug Fixes" line out of the git-cliff release notes.

For webarkit #232 (adapter), recorded here, not done here

  • Describe on the full-resolution image, with size and coordinates in level-0 pixels.
  • describe drops keypoints, so use the returned count and the compacted array, never the input length.
  • FREAK writes the angle, so no orientation step is needed. corners[i].angle is radians, and can be negative (F5).

Follow-ups

🤖 Generated with Claude Code

kalwalt and others added 11 commits October 30, 2026 20:21
Add a `freak` group to gen-opencv-fixtures.py and the freak.json fixture:
eight cases (defaults, no orientation, no scale normalization,
pattern_scale 8, n_octaves 3 and 8, a 90 degree rotated scene, a flat
image), border keypoints placed at the exact patternSizes thresholds, and
the rotation pairs with OpenCV's max Hamming distance.

Refs #80

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The committed scene gives angle 0 for most keypoints. Add an integer-only
procedural texture (rebuildable bit for bit in TypeScript), the cases
texture-default, texture-pattern-scale-8 and texture-rot90-default, move
the rotation payload to the texture pair, and gate the generator on
thetaIdx and negative-angle coverage.

Refs #80

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add the 512 selected-pair table, its (i, j) expansion and the 45
orientation pairs from OpenCV 4.10.0 freak.cpp, plus the BSD-3-Clause
licence variant (header snippet, LICENSES file, check script, bundle banner).

Refs #80

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add src/freak/freak.ts: freak.describe ports FREAK_Impl's buildPattern,
computeDescriptors, meanIntensity and the generic extractDescriptor,
with pattern points computed on demand (no 8.5 MB lookup table). Kept
keypoints are compacted in place and their angle is written in radians.
Parity tests pin all 11 freak.json cases bit for bit; property tests
cover validation, compaction, a large-frame integral and rotation.
TEBLID's TSDoc now notes that FREAK produces negative angles (F5).

Refs #80

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep patternSizes in double: equal to OpenCV's int value wherever its
cast is defined, and a huge or infinite pattern now drops the keypoint
instead of wrapping into a small or negative border. Cast the
orientation sums to float before atan2, as OpenCV does. Pin the
validation messages in the property tests, qualify the TEBLID angle
note, and clarify the FREAK example's keypoint pool.

Refs #80

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Wire the freak singleton into the namespace, the named exports and the
core static typing, with FreakOptions exported as a type. Rewrite the
FREAK table and ring constants so a { imgproc } bundle carries no FREAK
code (no residual argument expressions or member reads after the pure
call is dropped). Add API-shape, named-export, bundle-marker and
bfmatcher round-trip tests.

Refs #80

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #80

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #80

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…olicy (#80)

Refs #80

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oreAll (#80)

Refs #80

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sured (#80)

Two intra-library groups: the plan's size-31 workload (132 of 300
keypoints kept by FREAK) and a size-7 one where all 300 are kept, for a
like-for-like per-keypoint ratio. FREAK gets a fresh keypoint copy per
iteration outside the timed region. Not measured yet: the machine stayed
over the 20% CPU-load gate; the numbers and the bench/README.md section
follow in a later commit.

Refs #80

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.73684% with 10 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/freak/freak.ts 94.28% 6 Missing and 4 partials ⚠️

📢 Thoughts on this report? Let us know!

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add OpenCV-compatible FREAK binary descriptors

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add a FREAK descriptor API matching OpenCV 4.10.0 bytes, retained keypoints, and angles.
• Compute pattern points on demand to avoid OpenCV’s large resident lookup table.
• Add parity fixtures, behavioral tests, a browser example, and BSD-3-Clause attribution.
Diagram

graph TD
  Caller["Caller"] --> API["Public exports"] --> Freak["FREAK descriptor"] --> Results["Kept points and bytes"]
  Freak --> Tables["Pair tables"]
  Freak --> Integral["Integral image"] --> Pool[("Shared pool")]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Precompute OpenCV’s full pattern table
  • ➕ Avoids recomputing pattern points during descriptor extraction.
  • ➕ More directly mirrors OpenCV’s lookup strategy.
  • ➖ Adds roughly 8.5 MB of resident pattern data.
  • ➖ Works against the library’s small, tree-shakeable bundle goals.

Recommendation: Keep on-demand pattern generation: the parity fixtures support exact output while avoiding a substantial memory cost. Measure the committed benchmark before considering a limited pattern cache or full precomputation.

Files changed (30) +2475 / -32

Enhancement (6) +726 / -0
core.tsType the FREAK namespace member +2/-0

Type the FREAK namespace member

• Adds the FREAK singleton to the core namespace’s static API declaration.

src/core/core.ts

freak.tsImplement the OpenCV-compatible FREAK descriptor +569/-0

Implement the OpenCV-compatible FREAK descriptor

• Adds configurable 64-byte descriptor extraction with on-demand pattern points, orientation estimation, stable keypoint compaction, and a pooled Float64 integral image. It validates inputs and drops keypoints whose pattern does not fit.

src/freak/freak.ts

freak_tables.tsPort FREAK comparison and orientation pairs +150/-0

Port FREAK comparison and orientation pairs

• Adds OpenCV’s 512 selected comparisons and 45 orientation pairs, expanding comparison indices into point-index arrays for extraction.

src/freak/freak_tables.ts

index.tsExport the FREAK singleton and options type +2/-0

Export the FREAK singleton and options type

• Makes FREAK available as a named ESM export and exposes its configuration interface.

src/index.ts

jsfeatNext.tsAttach FREAK to the public namespace +1/-0

Attach FREAK to the public namespace

• Adds the shared FREAK singleton to the tree-shakeable 'jsfeatNext' namespace.

src/jsfeatNext.ts

singletons.tsInstantiate the shared FREAK singleton +2/-0

Instantiate the shared FREAK singleton

• Creates a pure-annotated FREAK instance shared by namespace and named exports.

src/singletons.ts

Documentation (12) +444 / -26
instructions.mdDocument FREAK’s license-header variant +1/-1

Document FREAK’s license-header variant

• Adds 'src/freak/' to the OpenCV-derived header guidance and distinguishes its BSD-3-Clause notice from the Apache-2.0 ports.

.agents/instructions.md

SKILL.mdExplain FREAK attribution and packaging +20/-12

Explain FREAK attribution and packaging

• Documents the FREAK attribution resource, path-based header selection, shipped license text, and bundle notice.

.agents/skills/license-header-adder/SKILL.md

ATTRIBUTION-opencv-freak.txtAdd the FREAK source attribution snippet +38/-0

Add the FREAK source attribution snippet

• Provides the OpenCV source reference, EPFL copyright, and BSD-3-Clause terms used in FREAK source headers.

.agents/skills/license-header-adder/resources/ATTRIBUTION-opencv-freak.txt

copilot-instructions.mdMirror FREAK licensing guidance for Copilot +1/-1

Mirror FREAK licensing guidance for Copilot

• Updates agent instructions to identify FREAK as an OpenCV-derived, BSD-3-Clause port.

.github/copilot-instructions.md

AGENTS.mdRecord the FREAK singleton and license policy +3/-3

Record the FREAK singleton and license policy

• Adds FREAK to the algorithm inventory, documents its distinct attribution, and marks its milestone work as implemented.

AGENTS.md

CLAUDE.mdMirror FREAK header requirements +1/-1

Mirror FREAK header requirements

• Clarifies that files under 'src/freak/' receive BSD-3-Clause OpenCV attribution rather than jsfeat or Apache-2.0 attribution.

CLAUDE.md

BSD-3-Clause-FREAK.txtShip the FREAK upstream license notice +34/-0

Ship the FREAK upstream license notice

• Adds the EPFL copyright and BSD-3-Clause terms associated with the ported 'freak.cpp' source.

LICENSES/BSD-3-Clause-FREAK.txt

README.mdList FREAK, its example, and its license +4/-1

List FREAK, its example, and its license

• Adds FREAK to the public namespace list, links the browser demonstration, and distinguishes its license from other OpenCV-derived modules.

README.md

2026-10-27-milestone-1.2.0.mdUpdate FREAK milestone status +2/-1

Update FREAK milestone status

• Records the implemented FREAK task and removes it from the plan’s still-open list.

docs/superpowers/plans/2026-10-27-milestone-1.2.0.md

sample_freak.htmlDemonstrate oriented FREAK matching +232/-0

Demonstrate oriented FREAK matching

• Adds a browser example that detects corners in two transformed views, describes retained points, matches descriptors, and draws orientations and match consistency.

examples/sample_freak.html

teblid.tsClarify TEBLID behavior for negative FREAK angles +6/-5

Clarify TEBLID behavior for negative FREAK angles

• Corrects the angle documentation: OpenCV FREAK can produce negative angles, for which subsequent TEBLID behavior differs between the libraries.

src/teblid/teblid.ts

README.mdDocument FREAK fixture generation and coverage +102/-1

Document FREAK fixture generation and coverage

• Explains the eleven fixture cases, reproducible texture, exact-output fields, border thresholds, rotation pairs, and generation command.

tests/fixtures/opencv/README.md

Other (12) +1305 / -6
freak.bench.tsAdd comparative descriptor workloads +157/-0

Add comparative descriptor workloads

• Defines size-31 and size-7 FREAK workloads alongside ORB and TEBLID, with assertions on retained keypoint counts. It adds the benchmark without reporting measurements.

bench/freak.bench.ts

check-license-headers.mjsSelect the FREAK license-header variant +5/-2

Select the FREAK license-header variant

• Maps 'src/freak/' to its attribution snippet and classifies the new example as original work.

scripts/check-license-headers.mjs

gen-opencv-fixtures.pyGenerate OpenCV FREAK ground truth +379/-3

Generate OpenCV FREAK ground truth

• Adds deterministic scene, border, scale, flat-image, and procedural-texture cases with retained indices, angles, and descriptor bytes. The generator cross-checks its border predictions against OpenCV and gates orientation coverage.

scripts/gen-opencv-fixtures.py

api-shape.test.tsAssert the namespace exposes FREAK +1/-0

Assert the namespace exposes FREAK

• Checks that 'jsfeatNext.freak.describe' exists on the singleton API.

tests/api-shape.test.ts

bundle.test.tsGuard grayscale bundles against FREAK inclusion +2/-0

Guard grayscale bundles against FREAK inclusion

• Adds a recognizable FREAK pair-table marker to the unused-module tree-shaking checks.

tests/build/bundle.test.ts

freak_images.tsRebuild and verify FREAK fixture images +144/-0

Rebuild and verify FREAK fixture images

• Recreates the procedural texture and rotated images in TypeScript, verifies recorded image hashes, and supplies grayscale matrices to tests.

tests/fixtures/opencv/freak_images.ts

named-exports.test.tsAssert the named FREAK export +1/-0

Assert the named FREAK export

• Includes FREAK in the expected ESM export surface.

tests/named-exports.test.ts

api-surface.test.tsClassify FREAK as an intentional API addition +1/-0

Classify FREAK as an intentional API addition

• Records that the OpenCV-derived descriptor has no counterpart in the original jsfeat API.

tests/parity/api-surface.test.ts

freak.test.tsAssert exact OpenCV FREAK output +140/-0

Assert exact OpenCV FREAK output

• Compares retained keypoint identities and order, converted angles, and every descriptor byte across the fixture cases without tolerance.

tests/parity/freak.test.ts

freak-tables.test.tsVerify FREAK pair-table structure +89/-0

Verify FREAK pair-table structure

• Checks comparison-table length and bounds, triangular-index expansion, and orientation-pair endpoints.

tests/properties/freak-tables.test.ts

freak.test.tsExercise FREAK contracts and integration +383/-0

Exercise FREAK contracts and integration

• Tests validation, compaction, angle handling, overflow-safe drops, large integral images, rotation behavior, pool balance, and BFMatcher compatibility.

tests/properties/freak.test.ts

vite.config.mtsInclude the FREAK license in bundle banners +3/-1

Include the FREAK license in bundle banners

• Adds the FREAK source, EPFL copyright, and BSD-3-Clause license location to generated bundle notices.

vite.config.mts

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Using the image as output corrupts descriptors 🐞 Bug ≡ Correctness
Description
freak.describe resizes descriptors before computing the integral image, without rejecting
descriptors === src. If a caller passes the source matrix as the output, resizing changes its
dimensions or reallocates its pixels before the integral and descriptor loops read them.
Code

src/freak/freak.ts[R482-484]

+        } else {
+            descriptors.resize(64, kept, 1);
+        }
Evidence
resize updates matrix dimensions and may replace its backing storage; the subsequent integral
computation reads the matrix passed as src.

src/freak/freak.ts[475-495]
src/matrix_t/matrix_t.ts[203-234]
src/imgproc/imgproc.ts[639-650]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Using the same matrix for `src` and `descriptors` mutates the image before FREAK reads it.
## Fix Focus Areas
- src/freak/freak.ts[408-450]
- src/freak/freak.ts[475-495]
## Recommended Fix
Reject an aliased source and output before compacting keypoints or resizing the matrix. Document the restriction and test that rejection leaves the source unchanged.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Scaled-view features use the wrong size 🐞 Bug ≡ Correctness
Description
detect assigns size = 31 to keypoints in both example views, although the right-hand image is
drawn at 0.8 times the source scale. Because FREAK selects its sampling pattern from each keypoint's
size, corresponding right-hand features are sampled at the unscaled size and can fail the example's
ratio test.
Code

examples/sample_freak.html[120]

+                corners[i].size = 31; // required by freak.describe; one level, so pixels of this image
Evidence
Both views call the same size-setting function, while FREAK derives its sampling scale from that
size and the second view is explicitly scaled.

examples/sample_freak.html[73-76]
examples/sample_freak.html[119-122]
examples/sample_freak.html[173-186]
src/freak/freak.ts[458-466]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The scaled view assigns its keypoints the same feature size as the original view.
## Fix Focus Areas
- examples/sample_freak.html[102-122]
- examples/sample_freak.html[171-186]
## Recommended Fix
Pass each view's feature size into `detect`, using 31 for the original and `31 * SCALE` for the scaled view.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. Example's 'detected' count shows the 500 cap, not what FAST found 🐞 Bug ◔ Observability
Description
In detect(), count is capped at MAX_KEYPOINTS before it is returned as detected, so the stat
does not retain FAST's actual result. When FAST finds more than 500 corners, the page displays
detected: 500, obscuring how many corners were found versus how many were removed by the cap or
dropped by freak.describe.
Code

examples/sample_freak.html[R114-122]

+            let count = jsfeatNext.fast_corners.detect(smooth, corners, BORDER);
+            if (count > MAX_KEYPOINTS) {
+                jsfeatNext.math.qsort(corners, 0, count - 1, (a, b) => b.score < a.score);
+                count = MAX_KEYPOINTS;
+            }
+            for (let i = 0; i < count; i++) {
+                corners[i].size = 31; // required by freak.describe; one level, so pixels of this image
+            }
+            return { smooth, corners, count, detected: count };
Evidence
In examples/sample_freak.html, count is reassigned to MAX_KEYPOINTS at line 117 before
detected: count is returned at line 122; line 221 then prints that value as the detected count.

examples/sample_freak.html[114-122]
examples/sample_freak.html[220-224]
examples/sample_freak.html[113-122]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The sample's `detected` stat reports the capped selection count rather than the number of corners FAST found.

## Fix Focus Areas
- examples/sample_freak.html[113-122]

## Recommended Fix
Save the result of `jsfeatNext.fast_corners.detect(...)` as `const detected` before limiting the selected keypoints. Set `let count = Math.min(detected, MAX_KEYPOINTS)`, sorting first when the result exceeds the cap, and return `{ smooth, corners, count, detected }`. Optionally add a separate stats line showing the capped count.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 27 rules
Review mode: Auto: 🧠 Deep: Complex new descriptor spans algorithm, tables, APIs, fixtures, and integration paths.

Grey Divider

Tip of the day
💡 Did you know, you can route each severity your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/freak/freak.ts
Comment on lines +482 to +484
} else {
descriptors.resize(64, kept, 1);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. Using the image as output corrupts descriptors 🐞 Bug ≡ Correctness

freak.describe resizes descriptors before computing the integral image, without rejecting
descriptors === src. If a caller passes the source matrix as the output, resizing changes its
dimensions or reallocates its pixels before the integral and descriptor loops read them.
Agent Prompt
## Issue description
Using the same matrix for `src` and `descriptors` mutates the image before FREAK reads it.
## Fix Focus Areas
- src/freak/freak.ts[408-450]
- src/freak/freak.ts[475-495]
## Recommended Fix
Reject an aliased source and output before compacting keypoints or resizing the matrix. Document the restriction and test that rejection leaves the source unchanged.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

count = MAX_KEYPOINTS;
}
for (let i = 0; i < count; i++) {
corners[i].size = 31; // required by freak.describe; one level, so pixels of this image

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. Scaled-view features use the wrong size 🐞 Bug ≡ Correctness

detect assigns size = 31 to keypoints in both example views, although the right-hand image is
drawn at 0.8 times the source scale. Because FREAK selects its sampling pattern from each keypoint's
size, corresponding right-hand features are sampled at the unscaled size and can fail the example's
ratio test.
Agent Prompt
## Issue description
The scaled view assigns its keypoints the same feature size as the original view.
## Fix Focus Areas
- examples/sample_freak.html[102-122]
- examples/sample_freak.html[171-186]
## Recommended Fix
Pass each view's feature size into `detect`, using 31 for the original and `31 * SCALE` for the scaled view.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +114 to +122
let count = jsfeatNext.fast_corners.detect(smooth, corners, BORDER);
if (count > MAX_KEYPOINTS) {
jsfeatNext.math.qsort(corners, 0, count - 1, (a, b) => b.score < a.score);
count = MAX_KEYPOINTS;
}
for (let i = 0; i < count; i++) {
corners[i].size = 31; // required by freak.describe; one level, so pixels of this image
}
return { smooth, corners, count, detected: count };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Informational

3. Example's 'detected' count shows the 500 cap, not what fast found 🐞 Bug ◔ Observability

In detect(), count is capped at MAX_KEYPOINTS before it is returned as detected, so the stat
does not retain FAST's actual result. When FAST finds more than 500 corners, the page displays
detected: 500, obscuring how many corners were found versus how many were removed by the cap or
dropped by freak.describe.
Agent Prompt
## Issue description
The sample's `detected` stat reports the capped selection count rather than the number of corners FAST found.

## Fix Focus Areas
- examples/sample_freak.html[113-122]

## Recommended Fix
Save the result of `jsfeatNext.fast_corners.detect(...)` as `const detected` before limiting the selected keypoints. Set `let count = Math.min(detected, MAX_KEYPOINTS)`, sorting first when the result exceeds the cap, and return `{ smooth, corners, count, detected }`. Optionally add a separate stats line showing the capped count.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant