2026-06-26 07:23:52 +00:00
|
|
|
|
import { type WrappedMat } from './opencvAdapter';
|
|
|
|
|
|
import { type SkPath } from '@shopify/react-native-skia';
|
|
|
|
|
|
export type RegionPickMap = {
|
|
|
|
|
|
buffer: Uint8Array;
|
|
|
|
|
|
cols: number;
|
|
|
|
|
|
rows: number;
|
|
|
|
|
|
};
|
|
|
|
|
|
export type SegmentMaskResult = {
|
|
|
|
|
|
regions: SegmentRegion[];
|
|
|
|
|
|
pickMap: RegionPickMap;
|
|
|
|
|
|
labels: Uint8Array;
|
|
|
|
|
|
baseboardBinary: Uint8Array;
|
|
|
|
|
|
segCols: number;
|
|
|
|
|
|
segRows: number;
|
2026-07-02 02:07:32 +00:00
|
|
|
|
/** splitWalls only: wall pixels → sub-region index 0..N-1, non-wall is WALL_SUB_LABEL_NONE */
|
2026-07-01 05:41:17 +00:00
|
|
|
|
wallSubLabels?: Uint8Array;
|
2026-06-26 07:23:52 +00:00
|
|
|
|
};
|
|
|
|
|
|
export type SegmentRegion = {
|
|
|
|
|
|
id: number;
|
2026-07-02 02:07:32 +00:00
|
|
|
|
/** semantic partition name (door / cabinet / baseboard ...) */
|
2026-06-26 07:23:52 +00:00
|
|
|
|
name: string;
|
2026-07-02 02:07:32 +00:00
|
|
|
|
/** reference color hex */
|
2026-06-26 07:23:52 +00:00
|
|
|
|
hex: string;
|
2026-07-02 02:07:32 +00:00
|
|
|
|
/** reference color (BGR) */
|
2026-06-26 07:23:52 +00:00
|
|
|
|
color: {
|
|
|
|
|
|
b: number;
|
|
|
|
|
|
g: number;
|
|
|
|
|
|
r: number;
|
|
|
|
|
|
};
|
|
|
|
|
|
polygons: {
|
|
|
|
|
|
x: number;
|
|
|
|
|
|
y: number;
|
|
|
|
|
|
}[][];
|
2026-07-02 02:07:32 +00:00
|
|
|
|
/** paint/highlight mask: strict pixel strip, no black hole filling */
|
2026-06-26 07:23:52 +00:00
|
|
|
|
maskPolygons?: {
|
|
|
|
|
|
x: number;
|
|
|
|
|
|
y: number;
|
|
|
|
|
|
}[][];
|
|
|
|
|
|
hitPolygons?: {
|
|
|
|
|
|
x: number;
|
|
|
|
|
|
y: number;
|
|
|
|
|
|
}[][];
|
|
|
|
|
|
outlinePolygons?: {
|
|
|
|
|
|
x: number;
|
|
|
|
|
|
y: number;
|
|
|
|
|
|
}[][];
|
|
|
|
|
|
bbox: {
|
|
|
|
|
|
x: number;
|
|
|
|
|
|
y: number;
|
|
|
|
|
|
w: number;
|
|
|
|
|
|
h: number;
|
|
|
|
|
|
};
|
|
|
|
|
|
area: number;
|
2026-07-02 02:07:32 +00:00
|
|
|
|
/** baseboard etc. thin strip areas, click detection needs tolerance */
|
2026-06-26 07:23:52 +00:00
|
|
|
|
thinStrip?: boolean;
|
|
|
|
|
|
};
|
|
|
|
|
|
export declare function buildRegionOutlinePolygons(reg: SegmentRegion): NormPoint[][];
|
2026-07-01 09:13:38 +00:00
|
|
|
|
import { buildAllRegionOutlinePaths, buildRegionOutlinePathForRegion } from './maskOutlinePaths';
|
|
|
|
|
|
export { buildAllRegionOutlinePaths, buildRegionOutlinePathForRegion };
|
2026-07-02 02:07:32 +00:00
|
|
|
|
/** build mask from binary mask row by row (for Skia PathBuilder) */
|
2026-06-26 07:23:52 +00:00
|
|
|
|
export declare function appendMaskBinaryToPathBuilder(binary: Uint8Array, cols: number, rows: number, rect: {
|
|
|
|
|
|
x: number;
|
|
|
|
|
|
y: number;
|
|
|
|
|
|
w: number;
|
|
|
|
|
|
h: number;
|
|
|
|
|
|
}, builder: {
|
|
|
|
|
|
moveTo: (x: number, y: number) => unknown;
|
|
|
|
|
|
lineTo: (x: number, y: number) => unknown;
|
|
|
|
|
|
close: () => unknown;
|
|
|
|
|
|
}, minRunPx?: number): void;
|
2026-07-02 02:07:32 +00:00
|
|
|
|
/** build mask from semantic labels row by row (avoid maintaining multiple binary masks) */
|
2026-06-26 07:23:52 +00:00
|
|
|
|
export declare function appendLabelMaskToPathBuilder(labels: Uint8Array, semanticIndex: number, cols: number, rows: number, rect: {
|
|
|
|
|
|
x: number;
|
|
|
|
|
|
y: number;
|
|
|
|
|
|
w: number;
|
|
|
|
|
|
h: number;
|
|
|
|
|
|
}, builder: {
|
|
|
|
|
|
moveTo: (x: number, y: number) => unknown;
|
|
|
|
|
|
lineTo: (x: number, y: number) => unknown;
|
|
|
|
|
|
close: () => unknown;
|
|
|
|
|
|
}, minRunPx?: number): void;
|
|
|
|
|
|
export type RegionMaskData = {
|
|
|
|
|
|
labels: Uint8Array;
|
|
|
|
|
|
baseboardBinary: Uint8Array;
|
|
|
|
|
|
cols: number;
|
|
|
|
|
|
rows: number;
|
2026-07-01 05:41:17 +00:00
|
|
|
|
wallSubLabels?: Uint8Array;
|
feat: add manual lasso wall splitting with magnetic edge-snapping and active contour refinement
- New magneticLasso module: Sobel energy map + Dijkstra shortest-path + Douglas-Peucker
- New activeContour module: greedy snake + balloon force for polygon-to-edge refinement
- wallTextureSplit: edge barrier mask, morphological mask hole closing, Moore boundary tracing, simplified polygon contours, manual pick map patching, gap absorption
- MaskSegmentCanvas: full lasso gesture pipeline (tap vertices, drag, magnetic paths, close polygon, endLasso/cancelLasso/deleteLasso)
- New maskConfig options: splitWallsEdgeBarrierThreshold, splitWallsCloseMaskRadius, manualSplitWalls, manualSplitWallsMaxCount, manualSplitWallsGapAbsorbDilatePx, magneticLasso, activeContourRefine
- New ref methods: startLasso, endLasso, cancelLasso, getManualRegions, deleteLasso
- New exported types: LassoPolygon, ManualWallPartition
- RegionMaskData carries indexToName and wallSemanticIdx through downsample
- Simplify README to point to documentation site
- Update documentation site (EN + ZH-CN) with all new APIs and interaction guide
- Example app: lasso mode toggles and operation buttons
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 03:23:57 +00:00
|
|
|
|
/** Semantic index → name table captured at segmentation time (must match labels buffer). */
|
|
|
|
|
|
indexToName?: string[];
|
|
|
|
|
|
/** Wall semantic index in labels buffer (captured at segmentation time). */
|
|
|
|
|
|
wallSemanticIdx?: number;
|
2026-06-26 07:23:52 +00:00
|
|
|
|
};
|
2026-07-02 02:07:32 +00:00
|
|
|
|
/** downsample mask path building (screen display does not need segmentation resolution, click still uses full resolution pickMap) */
|
2026-06-26 07:23:52 +00:00
|
|
|
|
export declare function downsampleMaskDataForPaths(maskData: RegionMaskData, maxLongSide: number): RegionMaskData;
|
2026-07-02 02:07:32 +00:00
|
|
|
|
/** single pass build all partition Skia mask paths (single label pass, avoid per pixel × semantic count loop) */
|
2026-06-26 07:23:52 +00:00
|
|
|
|
export declare function buildAllRegionMaskPaths(regions: SegmentRegion[], maskData: RegionMaskData, rect: {
|
|
|
|
|
|
x: number;
|
|
|
|
|
|
y: number;
|
|
|
|
|
|
w: number;
|
|
|
|
|
|
h: number;
|
|
|
|
|
|
}): Map<number, SkPath>;
|
|
|
|
|
|
type NormPoint = {
|
|
|
|
|
|
x: number;
|
|
|
|
|
|
y: number;
|
|
|
|
|
|
};
|
|
|
|
|
|
export declare function buildBaseboardBinaryFromMask(buffer: Uint8Array, cols: number, rows: number): Uint8Array;
|
2026-07-02 02:07:32 +00:00
|
|
|
|
/** Upscale segmentation-resolution baseboard binary to tap-lookup resolution via nearest-neighbor (avoids full-image junction recomputation) */
|
2026-06-26 07:23:52 +00:00
|
|
|
|
export declare function upscaleBinaryMask(src: Uint8Array, srcCols: number, srcRows: number, dstCols: number, dstRows: number): Uint8Array;
|
|
|
|
|
|
export declare function isBaseboardMaskPixel(buffer: Uint8Array, cols: number, rows: number, x: number, y: number, baseboardBinary?: Uint8Array | null): boolean;
|
|
|
|
|
|
export { isStrictBaseboardPixel as isBaseboardPixel } from './maskSemanticPalette';
|
|
|
|
|
|
export declare function getMaskQuantKey(b: number, g: number, r: number): string;
|
2026-07-02 02:07:32 +00:00
|
|
|
|
/** @deprecated Use isBaseboardMaskPixel */
|
2026-06-26 07:23:52 +00:00
|
|
|
|
export declare function isKickPlatePixel(b: number, g: number, r: number): boolean;
|
|
|
|
|
|
export declare function extractRegionsFromMaskBuffer(buffer: Uint8Array, cols: number, rows: number, _options: {
|
|
|
|
|
|
minArea: number;
|
|
|
|
|
|
approxEpsilon: number;
|
|
|
|
|
|
}): Promise<SegmentMaskResult>;
|
|
|
|
|
|
export declare function extractRegionsFromMaskBufferSync(buffer: Uint8Array, cols: number, rows: number, _options: {
|
|
|
|
|
|
minArea: number;
|
|
|
|
|
|
approxEpsilon: number;
|
|
|
|
|
|
}): SegmentMaskResult;
|
2026-07-02 02:07:32 +00:00
|
|
|
|
/** @deprecated Use extractRegionsFromMaskBuffer */
|
2026-06-26 07:23:52 +00:00
|
|
|
|
export declare function extractRegionsFromMask(maskMat: WrappedMat, options: {
|
|
|
|
|
|
minArea: number;
|
|
|
|
|
|
approxEpsilon: number;
|
|
|
|
|
|
}): Promise<SegmentRegion[]>;
|