{"version":3,"file":"segmentation.cjs","names":[],"sources":["../../../src/vision/postprocess/segmentation.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Segmentation head postprocessing: YOLO instance-segmentation decoding.\n *\n * Compatible with YOLOv8-seg / YOLOv11-seg exports (and any later seg head\n * sharing the layout). The model produces two output tensors:\n *\n * - `output0` of shape `(1, 4 + numClasses + numMaskCoefs, numAnchors)` — the\n *   same per-anchor predictions as plain YOLO detection plus an extra\n *   `numMaskCoefs` (typically 32) channels of mask coefficients.\n * - `output1` of shape `(1, numMaskCoefs, maskH, maskW)` — a set of \"prototype\"\n *   masks shared across all anchors.\n *\n * The per-anchor decode (xywh→xyxy, undo letterbox, per-class NMS, sort & cap)\n * is delegated to {@link decodeYoloAnchors}; this module only handles the\n * mask-specific work: matmul against prototypes, sigmoid, bilinear resize and\n * thresholding.\n */\n\nimport { decodeYoloAnchors } from \"./detection\";\nimport { BoundingBox, Mask } from \"../types\";\n\nexport interface DecodeYoloSegOptions {\n    readonly numClasses: number;\n    /** Model input `[width, height]` (post-letterbox). */\n    readonly inputWidth: number;\n    readonly inputHeight: number;\n    /** Original image `[width, height]`. */\n    readonly originalWidth: number;\n    readonly originalHeight: number;\n    /** Letterbox horizontal padding in input-tensor pixels. */\n    readonly padLeft: number;\n    /** Letterbox vertical padding in input-tensor pixels. */\n    readonly padTop: number;\n    /** Letterbox scale factor. */\n    readonly scale: number;\n    readonly confThreshold: number;\n    readonly iouThreshold: number;\n    readonly maxDetections: number;\n    /** Probability cutoff applied to the soft mask. Defaults to `0.5`. */\n    readonly maskThreshold?: number;\n}\n\nexport interface DecodedSegmentation {\n    readonly bbox: BoundingBox;\n    readonly classId: number;\n    readonly confidence: number;\n    /** Binary mask cropped to `bbox`. Width/height match `bbox.asIntXyxy()` extents. */\n    readonly mask: Mask;\n}\n\n/**\n * Decode YOLO segmentation raw outputs into a list of segmented instances.\n *\n * Compatible with YOLOv8-seg / YOLOv11-seg.\n *\n * @param perAnchorData Flat `output0`, length `(4 + numClasses + numMaskCoefs) * numAnchors`.\n * @param perAnchorDims Dims as reported by ORT, e.g. `[1, 116, 8400]`.\n * @param prototypeData Flat `output1`, length `numMaskCoefs * maskH * maskW`.\n * @param prototypeDims Dims as reported by ORT, e.g. `[1, 32, 160, 160]`.\n */\nexport function decodeYoloSeg(\n    perAnchorData: Float32Array,\n    perAnchorDims: readonly number[],\n    prototypeData: Float32Array,\n    prototypeDims: readonly number[],\n    options: DecodeYoloSegOptions,\n): DecodedSegmentation[] {\n    // Strip batch dim from prototypes; perAnchor batch is validated by the helper.\n    let pDims = prototypeDims;\n    if (pDims.length === 4) {\n        if (pDims[0] !== 1) {\n            throw new Error(`decodeYoloSeg: expected batch size 1 in prototypes, got ${pDims[0]}.`);\n        }\n        pDims = [pDims[1] as number, pDims[2] as number, pDims[3] as number];\n    }\n    if (pDims.length !== 3) {\n        throw new Error(\n            `decodeYoloSeg: expected 3-D prototypes after batch removal, got dims=${JSON.stringify(prototypeDims)}.`,\n        );\n    }\n    const numMaskCoefs = pDims[0] as number;\n    const maskH = pDims[1] as number;\n    const maskW = pDims[2] as number;\n\n    const channels = perAnchorDims.length === 3 ? perAnchorDims[1] : perAnchorDims[0];\n    const numAnchors = perAnchorDims.length === 3 ? perAnchorDims[2] : perAnchorDims[1];\n    if (channels === undefined || numAnchors === undefined) {\n        throw new Error(\n            `decodeYoloSeg: cannot read channels/numAnchors from dims=${JSON.stringify(perAnchorDims)}.`,\n        );\n    }\n\n    const expectedChannels = 4 + options.numClasses + numMaskCoefs;\n    if (channels !== expectedChannels) {\n        throw new Error(\n            `decodeYoloSeg: channels=${channels} does not match 4 + numClasses(${options.numClasses}) + numMaskCoefs(${numMaskCoefs}) = ${expectedChannels}.`,\n        );\n    }\n    if (prototypeData.length !== numMaskCoefs * maskH * maskW) {\n        throw new Error(\n            `decodeYoloSeg: prototype length ${prototypeData.length} does not match dims=${JSON.stringify(prototypeDims)}.`,\n        );\n    }\n\n    const decoded = decodeYoloAnchors(perAnchorData, perAnchorDims, {\n        numClasses: options.numClasses,\n        originalWidth: options.originalWidth,\n        originalHeight: options.originalHeight,\n        padLeft: options.padLeft,\n        padTop: options.padTop,\n        scale: options.scale,\n        confThreshold: options.confThreshold,\n        iouThreshold: options.iouThreshold,\n        maxDetections: options.maxDetections,\n    });\n\n    if (decoded.anchorIndices.length === 0) return [];\n\n    const maskThreshold = options.maskThreshold ?? 0.5;\n    const scaleX = maskW / options.inputWidth;\n    const scaleY = maskH / options.inputHeight;\n    const protoPlane = maskH * maskW;\n    const coefBase = (4 + options.numClasses) * numAnchors;\n\n    const results: DecodedSegmentation[] = [];\n\n    for (let i = 0; i < decoded.anchorIndices.length; i++) {\n        const a = decoded.anchorIndices[i] as number;\n        const x1 = decoded.boxesXyxy[i * 4] as number;\n        const y1 = decoded.boxesXyxy[i * 4 + 1] as number;\n        const x2 = decoded.boxesXyxy[i * 4 + 2] as number;\n        const y2 = decoded.boxesXyxy[i * 4 + 3] as number;\n        const bbox = new BoundingBox(x1, y1, x2, y2);\n        const classId = decoded.classIds[i] as number;\n        const confidence = decoded.confidences[i] as number;\n\n        const bboxW = Math.max(0, Math.trunc(x2) - Math.trunc(x1));\n        const bboxH = Math.max(0, Math.trunc(y2) - Math.trunc(y1));\n\n        if (bboxW === 0 || bboxH === 0) {\n            results.push({ bbox, classId, confidence, mask: new Mask(new Uint8Array(0), 0, 0) });\n            continue;\n        }\n\n        // Bbox in input-tensor coords, then in low-res mask coords.\n        const ibx1 = x1 * options.scale + options.padLeft;\n        const iby1 = y1 * options.scale + options.padTop;\n        const ibx2 = x2 * options.scale + options.padLeft;\n        const iby2 = y2 * options.scale + options.padTop;\n\n        const mbx1 = Math.max(0, Math.floor(ibx1 * scaleX));\n        const mby1 = Math.max(0, Math.floor(iby1 * scaleY));\n        const mbx2 = Math.min(maskW, Math.ceil(ibx2 * scaleX));\n        const mby2 = Math.min(maskH, Math.ceil(iby2 * scaleY));\n\n        if (mbx2 <= mbx1 || mby2 <= mby1) {\n            results.push({\n                bbox,\n                classId,\n                confidence,\n                mask: new Mask(new Uint8Array(bboxW * bboxH), bboxW, bboxH),\n            });\n            continue;\n        }\n\n        // Compute soft mask only within the prototype region under this bbox.\n        const cropW = mbx2 - mbx1;\n        const cropH = mby2 - mby1;\n        const softCrop = new Float32Array(cropW * cropH);\n        for (let y = 0; y < cropH; y++) {\n            const py = mby1 + y;\n            for (let x = 0; x < cropW; x++) {\n                const px = mbx1 + x;\n                let sum = 0;\n                for (let kk = 0; kk < numMaskCoefs; kk++) {\n                    const coef = perAnchorData[coefBase + kk * numAnchors + a];\n                    const proto = prototypeData[kk * protoPlane + py * maskW + px];\n                    sum += coef * proto;\n                }\n                softCrop[y * cropW + x] = sigmoid(sum);\n            }\n        }\n\n        const resized = resizeBilinear(softCrop, cropW, cropH, bboxW, bboxH);\n        const binary = new Uint8Array(bboxW * bboxH);\n        for (let j = 0; j < binary.length; j++) {\n            binary[j] = resized[j] >= maskThreshold ? 255 : 0;\n        }\n\n        results.push({ bbox, classId, confidence, mask: new Mask(binary, bboxW, bboxH) });\n    }\n\n    return results;\n}\n\nfunction sigmoid(x: number): number {\n    if (x >= 0) {\n        return 1 / (1 + Math.exp(-x));\n    }\n    const e = Math.exp(x);\n    return e / (1 + e);\n}\n\nfunction resizeBilinear(\n    src: Float32Array,\n    srcWidth: number,\n    srcHeight: number,\n    targetWidth: number,\n    targetHeight: number,\n): Float32Array {\n    const out = new Float32Array(targetWidth * targetHeight);\n    if (targetWidth === 0 || targetHeight === 0 || srcWidth === 0 || srcHeight === 0) {\n        return out;\n    }\n    if (targetWidth === srcWidth && targetHeight === srcHeight) {\n        out.set(src);\n        return out;\n    }\n    const sx = srcWidth / targetWidth;\n    const sy = srcHeight / targetHeight;\n    for (let y = 0; y < targetHeight; y++) {\n        const yy = (y + 0.5) * sy - 0.5;\n        const y0 = Math.max(0, Math.floor(yy));\n        const y1 = Math.min(srcHeight - 1, y0 + 1);\n        const wy = Math.max(0, Math.min(1, yy - y0));\n        for (let x = 0; x < targetWidth; x++) {\n            const xx = (x + 0.5) * sx - 0.5;\n            const x0 = Math.max(0, Math.floor(xx));\n            const x1 = Math.min(srcWidth - 1, x0 + 1);\n            const wx = Math.max(0, Math.min(1, xx - x0));\n            const v00 = src[y0 * srcWidth + x0];\n            const v01 = src[y0 * srcWidth + x1];\n            const v10 = src[y1 * srcWidth + x0];\n            const v11 = src[y1 * srcWidth + x1];\n            const top = v00 * (1 - wx) + v01 * wx;\n            const bot = v10 * (1 - wx) + v11 * wx;\n            out[y * targetWidth + x] = top * (1 - wy) + bot * wy;\n        }\n    }\n    return out;\n}\n"],"mappings":"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"}