Repository navigation
Conversation
* docs(plan): add the milestone 1.1.0 design (GMS only) Scope 1.1.0 to the GMS match filter the webarkit planar tracker needs for a higher inlier ratio: #130 (Apache-2.0 OpenCV licence variant), #132 (OpenCV fixtures), #134 (GMS), #136 (adapter wiring, tracked here, built in webarkit/webarkit), plus #219 and #225. TEBLID, FREAK, tree-shaking and the imgproc bench coverage move to a new 1.2.0 milestone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(plan): pin the OpenCV fixture toolchain in a gitignored .venv Replace the session-scratchpad venv with a repository .venv/ (to be gitignored), a committed requirements file with exact pins, and a generator that refuses to run on a different cv2 version, so fixtures generated in different sessions cannot drift silently. Mark the design approved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(plan): add the milestone 1.1.0 implementation plan Eleven tasks: docs PR and decision D12, milestone and issue housekeeping, the GitHub project, then #225, #130, #132, #219, #134 (three tasks, one PR) and the release preparation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(plan): record decision D12 (1.1.0 = GMS only) in the expansion plan Add D12 to the decision log, replace the section 7 milestone allocation table with the current state (#132 and #130 move to 1.1.0; #135, #80, #137 and #168 move to 1.2.0; #136 is tracked here but built in webarkit/webarkit), and note on section 3.3 that the CvBackend contract and adapter live in webarkit/webarkit by design. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * docs(plan): mark pre-D12 milestone lines as superseded Add a note under section 5 (and a pointer from D12) saying the milestone lines in D3/D3a, section 5 and section 9 record the 2026-08-17 plan and are superseded by D12 and the section 7 table, flag the #136 entry as re-scoped to GMS, and mark the open item about #130 being milestone-less as resolved by D12. The historical entries themselves are untouched. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * docs(plan): fix the probe cleanup and record the GMS scale-fixture correction Address the Copilot review on #231: - Task 5 Step 2 deleted the licence probe with `git checkout -- .` and a directory-wide `git clean`, which would also discard unrelated work. Delete only src/gms/probe.ts. - Task 8 Step 1's whole-image resizes are no scale change for GMS, which normalises by each image's size. Record the correction (Ruling R11): scale coverage comes from same-canvas zoom fixtures and gms-coverage, with numbers checked against OpenCV 4.14.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…cribe()'s margin (#233) The two ORB samples and the ic_angle TSDoc example detected YAPE06 keypoints with a 17 px border, below the 20 px edge margin orb.describe() requires (#110/#146). Keypoints 17-19 px from an edge got descriptors partly built from rectify_patch's constant fill of 128 instead of image content. Use 20 in all three places and note why in the samples. Closes #225 Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
…and licence file (#234) * chore(license): add an OpenCV/Apache-2.0 header variant, banner line and licence file The GMS matcher (#134) is ported from OpenCV's opencv_contrib gms.cpp, which is Apache-2.0, not from jsfeat. With only the derived/original variants, check-license-headers --fix would stamp it with the jsfeat MIT credit to Eugene Zatepyakin (a false credit) and drop the Apache-2.0 notice. - scripts/check-license-headers.mjs: new OPENCV_SRC map (path prefix -> attribution snippet). Files under src/gms/ get HEADER.txt with ATTRIBUTION-opencv-gms.txt in the {{ATTRIBUTION}} slot instead of the jsfeat block, and the check verifies it byte-for-byte. EXTENDED and ORIGINAL_SRC behave as before. - ATTRIBUTION-opencv-gms.txt: the per-file Apache-2.0 attribution (source file, repo, licence, "modified version", GMS paper). - LICENSES/Apache-2.0.txt: verbatim from opencv_contrib's LICENSE, added to the package.json "files" so it is in the npm tarball. - vite.config.mts: the bundle banner now also credits OpenCV (Apache License 2.0) and points at LICENSES/Apache-2.0.txt. - SKILL.md, AGENTS.md, CLAUDE.md, .github/copilot-instructions.md: document the third variant and the per-file "verify the upstream licence" rule. Closes #130 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * docs(license): describe the three header variants consistently in agent docs .agents/instructions.md still described two templates; it now lists the jsfeat-derived, OpenCV-derived (src/gms/) and original variants. AGENTS.md now names the OpenCV variant as a family (opencv-<file>, currently opencv-gms) to match scripts/check-license-headers.mjs and SKILL.md. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
…egral_image (#235) * test(fixtures): OpenCV ground-truth harness, validated on compute_integral_image Adds a reproducible harness for OpenCV ground-truth fixtures, for the algorithms the vendored jsfeat oracle cannot cover (GMS next, #134), and validates it on compute_integral_image vs cv2.integral2. - scripts/gen-opencv-fixtures.py: run by hand from a gitignored .venv, never by CI or npm ci. Parses the opencv-contrib-python pin from scripts/requirements-fixtures.txt and exits non-zero unless cv2.__version__ matches it (numpy is checked too), so a wrong version is an explicit error. Output is deterministic: sorted keys, indent 1, LF. - Generic fixture envelope: a common meta block (opencv_version, algorithm, params, image + sha256) plus an algorithm-specific payload. Neither 1.1.0 consumer is a descriptor. - tests/fixtures/opencv/loader.ts: loadFixture throws unless sha256(image) matches meta.sha256, so a stale fixture fails loudly; loadScene parses the committed binary PGM. node:fs and node:crypto only. - scene-640x480.pgm: cornerScene(640, 480) dumped once from TypeScript (dump-scene.test.ts, skipped unless JSFEAT_DUMP_SCENE=1), so no RNG is reimplemented in Python and no image-encoder dependency is needed. - integral-scene.json + tests/reference/opencv-integral.test.ts: sum and squared-sum tables bit-exact on a dirty destination, first row and column included (the #131 failure mode). - .gitignore: .venv/ and __pycache__/. .gitattributes: the PGM is binary. No npm dependency is added and CI is unchanged. Closes #132 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * docs(fixtures): require Python 3.12+ and point divergences at the registry The pinned numpy==2.5.4 declares Requires-Python >=3.12, so "Python 3 is all that is needed" was wrong; state the floor in the fixtures README and in the requirements file header. The README also cited #102 as the policy for unreachable bit-exactness, but #102 introduced the divergence registry in tests/divergences.test.ts; say that deliberate divergences, from OpenCV as well as from jsfeat, are registered there. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
) Upgrade vitest and @vitest/coverage-v8 to ^5.0.2 (supersedes #226) and port the eight bench files, the ratio script, the scripts and the workflow to the Vitest 5 benchmark API. Vitest 5 removed the top-level bench(), --outputJson and benchmark.outputFile. Bench files: each case keeps its describe (its name is the key in bench/history.jsonl) and its setup, which still runs at collection time so that `npm run bench:smoke` keeps checking it; the describe now holds one test whose `bench` fixture runs the "jsfeatNext" and "jsfeat (reference)" cases back to back with `.run()`. Workloads, case names and the setup outside the timed region are unchanged. The setup/teardown options become the per-case beforeAll/afterAll hooks. scripts/bench-ratios.mjs reads the JSON reporter's per-test `benchmarks` instead of files[].groups[].benchmarks[]. The ratio is defined as before (jsfeatNext hz / jsfeat hz, hz = 1000 / mean latency, which is what Vitest 4 reported; Vitest 5's console "hz" column is a different estimator). It now refuses input that is not Vitest 5 JSON or holds no results, so a stale or wrong file can no longer append an empty record to history.jsonl. vitest.config.mts sets benchmark.suppressExportGetterWarnings. This is not cosmetic: while a benchmark runs, Vitest 5 otherwise instruments every export of every transformed module, inside the timed region and only on the jsfeatNext side, which inflates every module-crossing ratio (cache steady state 2.49x instead of 1.07x; geomean 0.73 instead of 0.92). Closes #219 Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
* feat(gms): grid-based motion statistics match filter (default path) Port cv::xfeatures2d::matchGMS (opencv_contrib modules/xfeatures2d/src/gms.cpp, 4.5.0, unchanged through 4.14.0; Apache-2.0) as the jsfeatNext.gms singleton. gms.filter(size1, size2, keypoints1, keypoints2, matches, with_rotation, with_scale, threshold_factor) returns the kept matches as a subset of the input, same objects, input order. This commit implements the default path; with_rotation / with_scale throw until the next commit. The grid arithmetic mirrors gms.cpp's float/double mix (Math.fround on the Point2f normalisation and the float * int products, the + 0.5 in double). Each pass costs O(matches): per-left-cell linked lists replace the dense 400 x N motion-statistics matrix, and the best right cell is kept incrementally with OpenCV's lowest-index tie-break. Keypoints outside the image are ignored (registered as an OpenCV divergence) and out-of-range match indices throw RangeError. Fixtures (scripts/gen-opencv-fixtures.py --only gms): the four search paths from ORB matches on the committed scene, with the planned view-2 transforms moved to the nearest values that keep a proper subset (matchGMS keeps nothing for the planned ones on this scene; see the fixture README), plus gms-boundaries, hand-placed points that pin the float arithmetic, the tie rule and the threshold comparison, which the ORB fixtures barely constrain. Refs #134 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(fixtures): synthetic-geometry GMS fixtures for all four search paths The ORB fixtures keep only 6-8 coincidental matches on the rotation and scale paths, so they pin those searches weakly. Add four OpenCV 4.14.0 fixtures on dense, exact geometry instead, one per getInlierMask branch: 800 random points in 640x480 (float32, a fixed numpy seed each), an inlier share mapped by the path's exact transform (shift (18, -11), 40 deg about the centre, x0.7 into 448x336, or both) and matched (i, i), the rest outliers with random view-2 points and random trainIdx (many-to-one included). thresholdFactor 6, no image. Kept / matches: synth-default 296/780, synth-rotation 196/679, synth-scale 373/800, synth-rotation-scale 265/689. The 60 % share keeps only 45 on the rotation path (101 on the combined one), so both rotation paths use 80 %; the README records this and which pass wins in each. New generator key: --only gms-synthetic (gen_gms_synthetic). Output is deterministic; regenerating everything leaves git status clean. Refs #134 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(gms): rotation and scale search paths, bit-exact on all four OpenCV fixtures with_rotation and with_scale no longer throw. filter() now mirrors getInlierMask: scale outer (right grids 20, 10, 14, 28, 40, from cvRound(20 * mScaleRatios)), rotation inner (mRotationPatterns copied verbatim); a run replaces the best mask only when it keeps strictly more matches, from 0, so the first of tied runs wins and all-zero runs give []. The best mask is swapped with the working one, never copied; right cells are computed once per scale. Each pass stays O(matches). Hardening from the Task 8 review: sizes (finite, > 0) and every keypoint slot a match references are validated before the first get_buffer, so a malformed size or a hole throws (RangeError / TypeError) with the pool balanced, and the comment no longer overclaims. Tests: the reference test is an it.each over the 4 ORB + 4 synthetic fixtures (gms-boundaries keeps its own it) plus a flags-vs-name check. New property tests: [] when no pass keeps anything (all paths), the hole and size throws, a non-float32-exact coordinate whose double and float32 readings fall in different cells, no state leak between calls (vs a fresh new gms()), and a higher inlier ratio on a translated cornerScene. Refs #134 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(fixtures): gms-coverage pins every rotation pattern and right grid The fixtures so far let only patterns 1-2 and grids 20/14 win, so wrong values in the other patterns or grids, ">=" for the best pass and a swapped loop order all passed. Ruling R11: - gms-synth-scale and gms-synth-rotation-scale zoom about the centre on the same 640x480 canvas instead of resizing view 2, which GMS normalises away. Zoom x0.7 makes the 28x28 grid win (248/800 kept); 40 deg then zoom x sqrt 2 makes the 10x10 grid win with pattern 2 (137/477). - New gms-coverage fixture (--only gms-coverage, gen_gms_coverage): 33 cases, 72-199 matches each. 45 deg rotation steps make patterns 1-8 win in turn. Zooms 2, sqrt 2, 1, 1/sqrt 2 and 1/2 make grids 10, 14, 20, 28 and 40 win. Two combined cases, two hand-placed ties (pattern 1 vs 90 deg; scale 0 x 90 deg vs 10x10 x pattern 1) and 16 random configurations (sizes, flags, thresholdFactor in [2, 8], shares). Every case keeps at least 1 match and fewer than all. - Synthetic coordinates are quarter pixels, and synthetic fixtures put each numeric array on one line. The four gms-synth-* files go from ~117 KB to ~33 KB each; gms-coverage is 211 KB. - The reference test adds an it.each over the coverage cases. All 32 mutants tried fail at least one fixture. These include a swap in each of the 8 patterns, each right grid off by one either way, ">=" and rotation-outer order. Regenerating is byte-identical, and the ORB, boundary and integral fixtures are unchanged. Refs #134 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(bench): time gms.filter against the matching step it follows (#134) bench/gms.bench.ts runs the four GMS paths and the knnMatch k=2 + ratio_test 0.75 baseline on one workload, the tracker's: the 300 strongest FAST corners of two 640x480 views (second view translated by (16, 8)), ORB-described. jsfeat has no GMS, so there is no jsfeat side; the result is the intra-library "gms: <path> costs N x matching". cornerScene gives only 36 corners and 24 matches, too little for GMS to do anything, so the views are two crops of one seeded noise canvas (300 + 300 keypoints, 289 matches). Collection throws below 300 keypoints, 100 matches, or if a path keeps nothing. scripts/bench-ratios.mjs reports a group with neither implementation name on its own, relative to the group's first task, instead of as an error row; the 36 A/B rows and the history record are unchanged and the intra-library group is never recorded. bench/README.md gets the numbers and the conditions they were taken under. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * docs(gms): list gms in the README and AGENTS.md (#134) README: gms in the module list and GMS filtering in the pipeline sentence, after bfmatcher; the benchmarks note names the one bench file that has no jsfeat side. AGENTS.md: 15 algorithm singletons, gms included, and the roadmap pointer now reads 1.1.0 = GMS (#134) with TEBLID, FREAK and tree-shaking in 1.2.0. The pose_estimator TSDoc that counted the singletons says 15 too. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(gms): return every borrowed buffer on any exit; fix the filter example (#134) gms.filter validated its input before borrowing, but anything that threw afterwards (a keypoint accessor, a non-numeric threshold_factor such as a BigInt, a failed buffer growth) skipped the put_buffer calls and drained the pool every module shares. Record each borrow as it is made and return them all in a finally, and correct the comment that claimed only a throwing accessor could escape. The new property test throws after the borrows through both a hostile keypoint accessor and a BigInt threshold_factor and relies on tests/setup/pool-balance.ts; it fails (pool -24) if the buffers are only returned on the normal path, and when the put_buffer calls are removed. The TSDoc example allocated 500-entry keypoint pools, so fast_corners.detect throws "corners pool is full" on a realistic frame (17,250 corners on a blurred 640x480 textured one). It now sizes the pool to the image as examples/sample_orb.html does, keeps the 300 strongest by score as the tracker does, and guards find_homography on at least 4 kept matches. The example was type-checked and run end to end against such a frame. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * docs: refresh the test count and note the gms.bench.ts exception (#134) README said 350+ tests across 28 files; the suite is now 441 passing tests in 33 files. bench/README's "Read the ratio" section said every case runs through both jsfeatNext and jsfeat, which gms.bench.ts does not (jsfeat has no GMS), as the top-level README already says. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * test(fixtures): pin OpenCV 4.10.0, the reference build PureCV measures against Align the fixture toolchain with PureCV's cpp_ref (opencv-contrib-python 4.10.0.84 built from opencv_contrib 1ed3dd2c, numpy 2.4.6), so both links of the PureCV -> jsfeatNext -> OpenCV validation chain use one OpenCV. Regenerating every fixture with 4.10.0 changed nothing but meta.opencv_version: gms.cpp is byte-identical (blob c13ffe4) in 4.10.0 and 4.14.0, and the ORB, synthetic, coverage, boundary and integral inputs and outputs are unchanged. The divergence probe in tests/divergences.test.ts was re-checked: OpenCV 4.10.0 keeps it, as 4.14.0 did. numpy 2.4.6 needs Python >= 3.11, so the README and requirements header now say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(agents): require OpenCV 4.10.0 for every OpenCV comparison and port Add an "OpenCV reference version" rule to AGENTS.md: comparisons with OpenCV, ports from it, fixtures and "OpenCV does X" claims all use OpenCV 4.10.0 (opencv-contrib-python 4.10.0.84, opencv 71d3237a / opencv_contrib 1ed3dd2c), the build PureCV measures against. The exact build lives in scripts/requirements-fixtures.txt; changing it takes its own issue (plus the matching one in webarkit/purecv) and a PR that regenerates every fixture and reports what changed. CLAUDE.md, README.md, .github/copilot-instructions.md and .agents/instructions.md state the rule with the version spelled out and point at AGENTS.md; SKILL.md and the gms TSDoc cite the reference release. tests/fixtures/opencv/pinned-version.test.ts enforces it: every committed fixture's meta.opencv_version must equal the pin, AGENTS.md must name the pinned wheel, and each entry-point file must state the pinned version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(fixtures): pin the generic CPU path, record build info, enforce pinned citations Adopt three practices from PureCV's OpenCV reference policy: - The generator switches Intel IPP off (cv2.ipp.setUseIPP(False)) and fails if it cannot, so fixtures pin OpenCV's generic CPU path. Regenerating with IPP off changed no fixture payload. - Every fixture records the "Version control" lines of cv2.getBuildInformation() (opencv_build, opencv_contrib_build) and "ipp": false. - OpenCV sources and docs are cited with links pinned to the release (blob/4.10.0/..., docs.opencv.org/4.10.0/...), never 4.x/master or a bare file.cpp:NN; the gms TSDoc now links gms.cpp at 4.10.0. AGENTS.md names PureCV's CONTRIBUTING policy as the shared one and adds the generic-CPU-path, build-info and citation rules. pinned-version.test.ts now also checks every fixture's build lines and ipp flag, and that src/, tests/, bench/, scripts/ and the entry-point docs cite OpenCV only at the pinned version (docs/ is exempt: dated analyses name their version). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(bench): never append a history record without a successful A/B row bench-ratios.mjs guarded --append with `rows.length === 0`, but `rows` also holds error rows, so a run whose only results were failed or unpaired tests passed the guard and appended `{"cases": {}, "geomean": null}` to bench/history.jsonl. Require at least one successful A/B row and name the error and intra-library counts in the message. Reproduced with a failed-only Vitest JSON (appended an empty record, exit 0; now exit 2, nothing written). A mixed input still appends its valid rows, and the output on the saved full bench run is unchanged. Reported by Copilot review on #237. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(gms): cover the right-grid bound guard with a fractional image size The guard in right_cells (x < grid_right && y < grid_right, else -1) was the one branch no test reached, as Codecov reported on #237: with an integer image size it cannot trigger. With a fractional one it can: x = 1000 inside a 1000 + 1e-9 wide image normalises to exactly 1 in float32, so the column equals the grid size and OpenCV's unguarded `x + y * 20` would wrap into the next row. The test puts the cluster's right side in the very cell the wrap would hit, so without the guard the probe match is kept (verified: removing the guard fails the test with 17 kept); with it, the probe is dropped on all four paths and nothing throws. gms.ts now has no uncovered branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#242) Supersede the open Dependabot PRs with one lockfile regeneration (npm 11): - vite ^8.3.4 (#239), vite-plugin-dts ^5.1.2 (#229), prettier ~3.9.10 (#238) - transitive: brace-expansion 5.0.12 (#241), markdown-it 14.3.2 (#240), source-map-js 1.2.2 -- `npm audit` goes from 3 findings (2 high, 1 moderate, all dev-only) to 0. TypeScript stays on 6.0.x: typedoc 0.28.20, the latest, declares `typescript` peer support only up to 6.0.x, so 7.x would fail to install and break `npm run docs`. dependabot.yml now ignores typescript major updates, with the reason and when to drop the entry, so no PR is opened that cannot pass. GitHub Actions are already on their latest majors. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1.1.0 ships the GMS match filter (#134, PR #237), bit-exact against OpenCV 4.10.0 on all four search paths, with its prerequisites: the OpenCV/Apache-2.0 licence variant (#130, PR #234), the OpenCV ground-truth fixture harness (#132, PR #235), the vitest 5 bench API (#219, PR #236), the ORB border fix (#225, PR #233), and the dev-dependency upgrade (PR #242). Changelog generated with git-cliff. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
PR Summary by QodoRelease 1.1.0 with OpenCV-compatible GMS match filtering
AI Description
Diagram
High-Level Assessment
Files changed (63)
|
Code Review by Qodo
1. Fixture tool rejects valid OpenCV PGM headers
|
|
Qodo review outcome for the 1.1.0 release PR (no change to this PR, which only promotes
The minor findings deferred from the earlier 1.1.0 task reviews are collected in #246 (milestone 1.2.0). |
Acknowledged. For this PR, finding 1 (PGM parsing) is intentional and finding 2 (OpenCV build pinning) is deferred to #245; the remaining minor items are tracked in #246. No changes or further Qodo action are needed here. |
Promotes
devtomainfor 1.1.0 (MAINTAINERS.md§2, step 6). Milestone: 1.1.0.1.1.0 is scoped to one consumer: the planar tracker in webarkit/webarkit needs a higher inlier ratio, and GMS is what raises it. TEBLID, FREAK and the tree-shakeable bundle moved to 1.2.0 (decision D12 in
docs/features2d-expansion-plan.md).What 1.1.0 ships
jsfeatNext.gms.filter(...)— the grid-based motion statistics match filter (Bian et al., CVPR 2017), ported from OpenCV'scv::xfeatures2d::matchGMS. It returns the kept matches as a subset of the input, in input order, and is bit-exact against OpenCV 4.10.0 on all four search paths (default, rotation, scale, both). Its cost scales with the matches: the default path costs about 0.07× theknnMatch+ ratio-test step it follows (feat(gms): grid-based motion statistics match filter #134, feat(gms): grid-based motion statistics match filter #237).LICENSES/Apache-2.0.txtshipped in the npm package (chore(license): add a third header variant for OpenCV-derived sources #130, chore(license): add an OpenCV/Apache-2.0 header variant, banner line and licence file #234).compute_integral_image. It uses one reference build, OpenCV 4.10.0, shared with PureCV, and the rule is now inAGENTS.mdand enforced by a test (test(fixtures): OpenCV ground-truth harness for algorithms jsfeat does not have #132, test(fixtures): OpenCV ground-truth harness, validated on compute_integral_image #235, feat(gms): grid-based motion statistics match filter #237).bench/history.jsonlstays comparable (test(bench): migrate the benchmark suite to the vitest 5 bench API #219, test(bench): migrate the benchmark suite to the vitest 5 bench API #236).ic_angleTSDoc detect with a 20 px border, matchingdescribe()'s edge margin (ORB samples and ic_angle TSDoc use detector border 17, below describe()'s 20 px edge margin #225, fix(examples): detect ORB keypoints with a 20 px border, matching describe()'s margin #233).npm auditis clean (chore(deps): upgrade dev dependencies and clear the npm audit findings #242).No public API is removed or changed;
gmsis a new singleton next to the existing ones.Commits
7635afechore(release): bump version to 1.1.033afeeechore(deps): upgrade dev dependencies and clear the npm audit findingsd8bf828feat(gms): grid-based motion statistics match filteref426e7test(bench): migrate the benchmark suite to the vitest 5 bench API290e176test(fixtures): OpenCV ground-truth harness, validated on compute_integral_imagecb6f03dchore(license): add an OpenCV/Apache-2.0 header variant, banner line and licence file6d33058fix(examples): detect ORB keypoints with a 20 px border, matching describe()'s margin75d21dedocs(plan): milestone 1.1.0 — GMS only (design, plan, D12)Issues closed by this release: #130, #132, #134, #219, #225.
Verification
On
devat7635afe(the release PR #243):npm test: 33 files passed, 1 skipped; 561 tests passed, 1 skippednpm run typecheck,npm run format-check,node scripts/check-license-headers.mjs: cleannpm run build-ts: both bundles carryjsfeatNext v1.1.0and the OpenCV / Apache-2.0 banner line;jsfeatNext.VERSION === "1.1.0"npm pack --dry-run:@webarkit/jsfeat-next@1.1.0, 45 files,LICENSES/Apache-2.0.txtincludeddevAfter merging
Tag
mainwith the bare version and push the tag (MAINTAINERS.mdstep 7):release.ymlthen checks the tag againstpackage.json, runs the tests and the build, creates the GitHub Release from the changelog and publishes to npm.Milestone 1.1.0 stays open after the release. #136 — the
filterMatcheswiring in the webarkit/webarkit adapter — can start once 1.1.0 is on npm, and its tracker inlier-ratio measurement closes the milestone.🤖 Generated with Claude Code