perf: cache the detected piece so margin changes only re-trace it

Margin slider steps drop from ~800 ms to under 70 ms in the browser.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
immortaly007andClaude Opus 5.5 committed 2026-10-15 15:30:12 +02:00
1 parent e925ce66d5
commit 353577d5ec
3 files changed
+63 -10

No files matched your search

+24 -1
View File
@@ -1,5 +1,5 @@
import { beforeAll, describe, expect, it } from 'vitest';
import { detect, detectPrepared, disposePrepared, otsuThreshold, prepareImage, preparedThreshold } from '../src/lib/detect';
import { detect, detectPrepared, disposePrepared, otsuThreshold, prepareImage, preparedThreshold, segmentPiece, traceMask } from '../src/lib/detect';
import { bounds } from '../src/lib/geometry';
import { loadOpenCV, type CV } from '../src/lib/opencv-loader';
import type { DetectParams } from '../src/lib/types';
@@ -149,4 +149,27 @@ describe('detect', () => {
const b = bounds(detect(cv, plywood, params({ threshold: 140 }))!.outer);
near(b.minX, 150); near(b.maxX, 449); near(b.minY, 100); near(b.maxY, 299);
});
it('segments once and applies different margins to the same piece mask', () => {
const prepared = prepareImage(cv, plateScene);
const piece = segmentPiece(cv, prepared, { threshold: 128, seed: null, minHolePx: 0 })!;
try {
for (const marginPx of [0, -5, 3]) {
const direct = detectPrepared(cv, prepared, params({ marginPx }))!;
expect(bounds(traceMask(cv, piece, marginPx)!.outer)).toEqual(bounds(direct.outer));
}
} finally {
piece.delete();
disposePrepared(prepared);
}
});
it('segmentPiece returns null when nothing is found', () => {
const prepared = prepareImage(cv, grayImage(100, 100, () => 30));
try {
expect(segmentPiece(cv, prepared, { threshold: 128, seed: null, minHolePx: 0 })).toBeNull();
} finally {
disposePrepared(prepared);
}
});
});