@annotorious/plugin-segment-anything 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Annotorious SegmentAnything Plugin
|
|
2
2
|
|
|
3
3
|
A fully browser-based smart polygon selection tool for Annotorious based on the [sam2-hiera-tiny](https://huggingface.co/g-ronimo/sam2-tiny) SegmentAnything model. The basic approach is inspired by this [blog post](https://medium.com/@geronimo7/in-browser-image-segmentation-with-segment-anything-model-2-c72680170d92) and [demo code](https://github.com/geronimi73/next-sam).
|
|
4
4
|
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
> **Important:** this plugin only supports `@annotorious/openseadragon` at this time. Support for
|
|
8
|
+
> plain (JPEG, PNG,...) images is not yet implemented. [Get in touch via the forum](https://github.com/orgs/annotorious/discussions) if you are interested in
|
|
9
|
+
> using this with the `@annotorious/annotorious` or `@annotorious/react` packages.
|
|
10
|
+
|
|
11
|
+
## Using with OpenSeadragon
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
npm install @annotorious/plugin-segment-anything
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import OpenSeadragon from 'openseadragon';
|
|
19
|
+
import { createOSDAnnotator } from '@annotorious/openseadragon';
|
|
20
|
+
import { mountOpenSeadragonPlugin } from '@annotorious/plugin-segment-anything/openseadragon';
|
|
21
|
+
|
|
22
|
+
import '@annotorious/openseadragon/annotorious-openseadragon.css';
|
|
23
|
+
|
|
24
|
+
const viewer = OpenSeadragon({
|
|
25
|
+
/** init your viewer **/
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const anno = createOSDAnnotator(viewer, { /* options */ });
|
|
29
|
+
|
|
30
|
+
// Initialize the plugin
|
|
31
|
+
const plugin = mountOpenSeadragonPlugin(anno);
|
|
32
|
+
|
|
33
|
+
// This will start initializing the plugin, incl.
|
|
34
|
+
// download of the model (this may take a while).
|
|
35
|
+
plugin.init();
|
|
36
|
+
|
|
37
|
+
plugin.on('downloadStart', () => {
|
|
38
|
+
console.log('downloading the model - this may take a while');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
plugin.on('downloadProgress', progress => {
|
|
42
|
+
if (progress.complete)
|
|
43
|
+
console.log('downloading complete');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
plugin.on('initialized', () => {
|
|
47
|
+
console.log('plugin ready');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
plugin.on('encodingStart', () => {
|
|
51
|
+
console.log('busy - encoding viewport');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
plugin.on('encodingFinished', () => {
|
|
55
|
+
console.log('ready - click to create annotation!');
|
|
56
|
+
});
|
|
57
|
+
```
|
|
5
58
|
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { m as
|
|
1
|
+
import { m as I, c as r, a as k, M as C, j as T, g as H, W, b as O, v as V } from "./get-image-bounds-sysVJFVF.js";
|
|
2
2
|
const L = (n, a, d = {}) => {
|
|
3
3
|
if (!Number.isFinite(a))
|
|
4
4
|
throw new TypeError("Expected `wait` to be a finite number");
|
|
@@ -29,7 +29,7 @@ L.promise = (n) => {
|
|
|
29
29
|
};
|
|
30
30
|
};
|
|
31
31
|
const z = (n, a, d) => {
|
|
32
|
-
const { canvas: t } =
|
|
32
|
+
const { canvas: t } = I(
|
|
33
33
|
n,
|
|
34
34
|
a,
|
|
35
35
|
[255, 255, 255, 255],
|
|
@@ -111,7 +111,7 @@ const z = (n, a, d) => {
|
|
|
111
111
|
renderMask: (o) => {
|
|
112
112
|
var l;
|
|
113
113
|
if (!t) return;
|
|
114
|
-
const { canvas: i } =
|
|
114
|
+
const { canvas: i } = I(
|
|
115
115
|
o,
|
|
116
116
|
a,
|
|
117
117
|
[0, 114, 189, 255],
|
|
@@ -142,8 +142,8 @@ const z = (n, a, d) => {
|
|
|
142
142
|
}, 1);
|
|
143
143
|
return N(o).then(({ canvas: p, bounds: w, scale: E }) => {
|
|
144
144
|
const h = (f) => {
|
|
145
|
-
const m = o.naturalWidth / (E * o.offsetWidth), g = o.naturalHeight / (E * o.offsetHeight), { offsetX: b, offsetY: M } = f, _ = b * m + w.x,
|
|
146
|
-
return { x: _, y:
|
|
145
|
+
const m = o.naturalWidth / (E * o.offsetWidth), g = o.naturalHeight / (E * o.offsetHeight), { offsetX: b, offsetY: M } = f, _ = b * m + w.x, R = M * g + w.y;
|
|
146
|
+
return { x: _, y: R };
|
|
147
147
|
};
|
|
148
148
|
l = (f) => {
|
|
149
149
|
if (s.include.length + s.exclude.length > 0) return;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../node_modules/p-debounce/index.js","../src/utils/mask-to-polygon.ts","../src/utils/prepare-sam2-canvas.ts","../src/input-marker-canvas.ts","../src/preview-canvas.ts","../src/index.ts"],"sourcesContent":["const pDebounce = (fn, wait, options = {}) => {\n\tif (!Number.isFinite(wait)) {\n\t\tthrow new TypeError('Expected `wait` to be a finite number');\n\t}\n\n\tlet leadingValue;\n\tlet timeout;\n\tlet resolveList = [];\n\n\treturn function (...arguments_) {\n\t\treturn new Promise(resolve => {\n\t\t\tconst shouldCallNow = options.before && !timeout;\n\n\t\t\tclearTimeout(timeout);\n\n\t\t\ttimeout = setTimeout(() => {\n\t\t\t\ttimeout = null;\n\n\t\t\t\tconst result = options.before ? leadingValue : fn.apply(this, arguments_);\n\n\t\t\t\tfor (resolve of resolveList) {\n\t\t\t\t\tresolve(result);\n\t\t\t\t}\n\n\t\t\t\tresolveList = [];\n\t\t\t}, wait);\n\n\t\t\tif (shouldCallNow) {\n\t\t\t\tleadingValue = fn.apply(this, arguments_);\n\t\t\t\tresolve(leadingValue);\n\t\t\t} else {\n\t\t\t\tresolveList.push(resolve);\n\t\t\t}\n\t\t});\n\t};\n};\n\npDebounce.promise = function_ => {\n\tlet currentPromise;\n\n\treturn async function (...arguments_) {\n\t\tif (currentPromise) {\n\t\t\treturn currentPromise;\n\t\t}\n\n\t\ttry {\n\t\t\tcurrentPromise = function_.apply(this, arguments_);\n\t\t\treturn await currentPromise;\n\t\t} finally {\n\t\t\tcurrentPromise = undefined;\n\t\t}\n\t};\n};\n\nexport default pDebounce;\n","import cv from '@techstark/opencv-js';\nimport type { InferenceSession } from 'onnxruntime-web/all';\nimport type { Bounds } from '@/types';\nimport { maskToCanvas } from './mask-to-canvas';\nimport { boundsFromPoints, ShapeType, type Polygon } from '@annotorious/annotorious';\nimport { chaikinSmooth } from './chaikin-smooth';\n\nexport const maskToPolygon = (\n result: InferenceSession.ReturnType, \n bounds: Bounds,\n scale: number\n) => {\n const { canvas } = maskToCanvas(\n result, \n bounds,\n [255, 255, 255, 255],\n [0, 0, 0, 255]\n );\n\n const src = cv.imread(canvas);\n\n const dst = new cv.Mat();\n const contours = new cv.MatVector();\n const hierarchy = new cv.Mat();\n\n // To grayscale\n cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY);\n\n // Smoothing\n const size = new cv.Size(9, 9);\n cv.GaussianBlur(dst, dst, size, 0);\n cv.threshold(dst, dst, 80, 255, cv.THRESH_BINARY);\n\n // Fill small gaps\n const kernel = cv.Mat.ones(3, 3, cv.CV_8U);\n cv.morphologyEx(dst, dst, cv.MORPH_CLOSE, kernel);\n\n // Find countours\n cv.findContours(dst, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);\n\n // Collect polygons\n const polygons: Polygon[] = [];\n\n if (contours.size() > 0) {\n let largestContourIdx = 0;\n let largestContourSize = 0;\n \n for (let i = 0; i < contours.size(); i++) {\n let contourSize = contours.get(i).rows;\n if (contourSize > largestContourSize) {\n largestContourSize = contourSize;\n largestContourIdx = i;\n }\n }\n \n let contour = contours.get(largestContourIdx);\n \n let epsilon = 0.005 * cv.arcLength(contour, true);\n let simplifiedContour = new cv.Mat();\n\n cv.approxPolyDP(contour, simplifiedContour, epsilon, true);\n \n let points: [number, number][] = [];\n\n for (let i = 0; i < simplifiedContour.rows; i++) {\n points.push([\n simplifiedContour.data32S[i * 2] * scale,\n simplifiedContour.data32S[i * 2 + 1] * scale\n ]);\n }\n \n const smoothed = chaikinSmooth(points, 1);\n\n const polygon: Polygon = {\n type: ShapeType.POLYGON,\n geometry: {\n bounds: boundsFromPoints(smoothed),\n points: smoothed\n }\n }\n polygons.push(polygon);\n\n simplifiedContour.delete();\n }\n\n src.delete(); \n dst.delete(); \n contours.delete(); \n hierarchy.delete();\n\n return polygons[0];\n\n}","import type { Bounds } from '@/types';\nimport { getImageBounds } from './get-image-bounds';\n\n// Ported to TS from geronimi73 (MIT license)\n// https://github.com/geronimi73/next-sam/blob/main/lib/imageutils.js\nexport const prepareSAM2Canvas = (\n image: HTMLImageElement\n): Promise<{ canvas: HTMLCanvasElement, bounds: Bounds, scale: number }> => new Promise((resolve, reject) => {\n const copy = new Image();\n copy.crossOrigin = 'anonymous';\n\n copy.onload = () => {\n const { bounds, scale } = getImageBounds(\n { h: copy.naturalHeight, w: copy.naturalWidth },\n { h: 1024, w: 1024 }\n );\n\n const canvas = document.createElement('canvas');\n canvas.width = 1024;\n canvas.height = 1024;\n\n canvas\n .getContext('2d')!\n .drawImage(\n copy,\n 0,\n 0,\n copy.naturalWidth,\n copy.naturalHeight,\n bounds.x,\n bounds.y,\n bounds.w,\n bounds.h\n );\n \n resolve({ canvas, bounds, scale });\n }\n\n copy.onerror = error => {\n reject(error);\n }\n\n copy.src = image.src;\n});","import type { Bounds, Point, SAM2DecoderPrompt } from './types';\n\nconst R = window.devicePixelRatio || 1;\n\nexport const createInputMarkerCanvas = (container: HTMLDivElement, bounds: Bounds, scale: number) => {\n const canvas = document.createElement('canvas');\n canvas.setAttribute('class', 'a9s-sam-input-markers');\n canvas.width = R * container.offsetWidth;\n canvas.height = R * container.offsetHeight;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) throw 'Error initializing canvas'; // Should never happen\n\n container.appendChild(canvas);\n\n const clear = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n }\n\n const drawPoint = (pt: Point, color: string) => {\n const x = R * (pt.x - bounds.x) * scale;\n const y = R * (pt.y - bounds.y) * scale;\n\n ctx.beginPath();\n ctx.arc(x, y, 5 * R, 0, 2 * Math.PI, false);\n ctx.fillStyle = color;\n ctx.fill();\n ctx.lineWidth = 1 * R;\n ctx.strokeStyle = '#000';\n ctx.stroke();\n }\n\n const setInput = (input: SAM2DecoderPrompt) => {\n clear();\n input.include.forEach(pt => drawPoint(pt, '#33ff33'));\n input.exclude.forEach(pt => drawPoint(pt, '#ff3333'));\n }\n\n return {\n clear,\n setInput\n }\n}","import type { InferenceSession } from 'onnxruntime-web/all';\nimport { maskToCanvas } from './utils';\nimport type { Bounds } from './types';\n\nexport const createPreviewCanvas = (container: HTMLDivElement, bounds: Bounds) => {\n const image = container?.querySelector('img');\n if (!image) return;\n\n let _visible = true;\n\n const renderMask = (result: InferenceSession.ReturnType) => {\n if (!_visible) return;\n\n const { canvas } = maskToCanvas(\n result, \n bounds,\n [0, 114, 189, 255],\n [0, 0, 0, 0]\n );\n\n container.querySelector('.a9s-sam-preview')?.remove();\n container.appendChild(canvas);\n }\n\n const setVisible = (visible: boolean) => {\n _visible = visible;\n\n if (!visible)\n container.querySelector('.a9s-sam-preview')?.remove();\n }\n\n return {\n renderMask,\n setVisible\n }\n}","import pDebounce from 'p-debounce';\nimport { v4 as uuidv4 } from 'uuid';\nimport type { ImageAnnotation, ImageAnnotator } from '@annotorious/annotorious';\nimport SAM2Worker from './sam2/sam2-worker.ts?worker';\nimport type { SAM2WorkerResult } from './sam2';\nimport { canvasToFloat32Array, maskToPolygon, prepareSAM2Canvas } from './utils';\nimport { createInputMarkerCanvas } from './input-marker-canvas';\nimport { createPreviewCanvas } from './preview-canvas';\nimport type { Point, SAM2DecoderPrompt, SAMPluginOpts } from './types';\n\nimport './index.css';\n\nexport const mountPlugin = (anno: ImageAnnotator, opts: SAMPluginOpts = {}) => {\n let _enabled = false;\n \n let _showPreview = true;\n\n let currentAnnotationId: string;\n\n const container = anno.element;\n\n let input: SAM2DecoderPrompt = {\n\n include: [],\n \n exclude: []\n \n }; \n\n const image = container?.querySelector('img') as HTMLImageElement;\n if (!image) return;\n\n const SAM2 = new SAM2Worker();\n\n let onPointerMove: ((evt: PointerEvent) => void) | null = null;\n let onPointerDown: ((evt: PointerEvent) => void) | null = null;\n\n let inputMarkerCanvas: ReturnType<typeof createInputMarkerCanvas>;\n\n let previewCanvas: ReturnType<typeof createPreviewCanvas>;\n\n const updateEventListeners = () => {\n if (!onPointerMove || !onPointerDown) return;\n \n if (_enabled) {\n container.addEventListener('pointermove', onPointerMove);\n container.addEventListener('pointerdown', onPointerDown);\n } else {\n container.removeEventListener('pointermove', onPointerMove);\n container.removeEventListener('pointerdown', onPointerDown);\n }\n }\n\n const debouncedPreview = pDebounce((pt: Point) => {\n SAM2.postMessage({ type: 'decode_preview', point: pt });\n }, 1);\n\n // Off-screen copy, resized and padded to 1024x1024px.\n prepareSAM2Canvas(image).then(({ canvas: bufferedImage, bounds, scale }) => {\n const viewportToSAM2Coordinates = (evt: PointerEvent) => {\n const scaleX = image.naturalWidth / (scale * image.offsetWidth);\n const scaleY = image.naturalHeight / (scale * image.offsetHeight);\n \n const { offsetX, offsetY } = evt;\n \n const x = (offsetX * scaleX) + bounds.x;\n const y = (offsetY * scaleY) + bounds.y;\n\n return { x, y };\n }\n\n onPointerMove = (evt: PointerEvent) => {\n if (input.include.length + input.exclude.length > 0) return;\n \n const { x, y } = viewportToSAM2Coordinates(evt); \n debouncedPreview({ x, y });\n }\n\n onPointerDown = (evt: PointerEvent) => {\n const { x, y } = viewportToSAM2Coordinates(evt);\n\n if (evt.shiftKey) {\n input.exclude.push({ x, y });\n } else {\n input.include.push({ x, y });\n }\n\n previewCanvas?.setVisible(false);\n\n inputMarkerCanvas?.setInput(input);\n\n SAM2.postMessage({ type: 'decode', input });\n }\n\n previewCanvas = createPreviewCanvas(anno.element, bounds);\n\n inputMarkerCanvas = createInputMarkerCanvas(anno.element, bounds, scale);\n\n SAM2.onmessage = ((message: MessageEvent<SAM2WorkerResult>) => {\n const { type } = message.data;\n \n if (type === 'init_success') {\n // Models loaded - encode the image\n console.log('[annotorious-sam] Encoding image...');\n\n const data = canvasToFloat32Array(bufferedImage);\n SAM2.postMessage({ type: 'encode', data });\n } else if (type === 'encode_success') {\n console.log('[annotorious-sam] Encoding complete');\n\n // Image encoded – add pointer listeners\n updateEventListeners();\n } else if (type === 'decode_preview_success') {\n // Render mask every time the worker has decoded one\n previewCanvas?.renderMask(message.data.result);\n } else if (type === 'decode_success') {\n // Render mask every time the worker has decoded one\n const polygon = maskToPolygon(message.data.result, bounds, scale);\n\n const annotation: ImageAnnotation = {\n id: currentAnnotationId,\n bodies: [],\n target: {\n annotation: currentAnnotationId,\n selector: polygon,\n creator: { id: 'rainer' },\n created: new Date()\n }\n };\n\n const { store, selection } = anno.state;\n\n const exists = store.getAnnotation(currentAnnotationId);\n if (exists) {\n store.updateAnnotation(currentAnnotationId, annotation);\n } else {\n store.addAnnotation(annotation);\n }\n\n // selection.setSelected(currentAnnotationId);\n }\n });\n \n SAM2.postMessage({ type: 'init' });\n });\n\n const setEnabled = (enabled: boolean) => {\n _enabled = enabled;\n\n currentAnnotationId = uuidv4();\n\n updateEventListeners();\n\n previewCanvas?.setVisible(enabled);\n }\n\n const setShowPreview = (showPreview: boolean) => {\n _showPreview = showPreview;\n previewCanvas?.setVisible(showPreview);\n }\n\n return {\n setEnabled,\n setShowPreview\n }\n\n}\n\nexport * from './types';"],"names":["pDebounce","fn","wait","options","leadingValue","timeout","resolveList","arguments_","resolve","shouldCallNow","result","function_","currentPromise","maskToPolygon","bounds","scale","canvas","maskToCanvas","src","cv","dst","contours","hierarchy","size","kernel","polygons","largestContourIdx","largestContourSize","i","contourSize","contour","epsilon","simplifiedContour","points","smoothed","chaikinSmooth","polygon","ShapeType","boundsFromPoints","prepareSAM2Canvas","image","reject","copy","getImageBounds","error","R","createInputMarkerCanvas","container","ctx","clear","drawPoint","pt","color","x","y","input","createPreviewCanvas","_visible","_a","visible","mountPlugin","anno","opts","_enabled","currentAnnotationId","SAM2","SAM2Worker","onPointerMove","onPointerDown","inputMarkerCanvas","previewCanvas","updateEventListeners","debouncedPreview","bufferedImage","viewportToSAM2Coordinates","evt","scaleX","scaleY","offsetX","offsetY","message","type","data","canvasToFloat32Array","annotation","store","selection","enabled","uuidv4","showPreview"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../node_modules/p-debounce/index.js","../src/utils/mask-to-polygon.ts","../src/utils/prepare-sam2-canvas.ts","../src/prompt-marker-canvas.ts","../src/preview-canvas.ts","../src/index.ts"],"sourcesContent":["const pDebounce = (fn, wait, options = {}) => {\n\tif (!Number.isFinite(wait)) {\n\t\tthrow new TypeError('Expected `wait` to be a finite number');\n\t}\n\n\tlet leadingValue;\n\tlet timeout;\n\tlet resolveList = [];\n\n\treturn function (...arguments_) {\n\t\treturn new Promise(resolve => {\n\t\t\tconst shouldCallNow = options.before && !timeout;\n\n\t\t\tclearTimeout(timeout);\n\n\t\t\ttimeout = setTimeout(() => {\n\t\t\t\ttimeout = null;\n\n\t\t\t\tconst result = options.before ? leadingValue : fn.apply(this, arguments_);\n\n\t\t\t\tfor (resolve of resolveList) {\n\t\t\t\t\tresolve(result);\n\t\t\t\t}\n\n\t\t\t\tresolveList = [];\n\t\t\t}, wait);\n\n\t\t\tif (shouldCallNow) {\n\t\t\t\tleadingValue = fn.apply(this, arguments_);\n\t\t\t\tresolve(leadingValue);\n\t\t\t} else {\n\t\t\t\tresolveList.push(resolve);\n\t\t\t}\n\t\t});\n\t};\n};\n\npDebounce.promise = function_ => {\n\tlet currentPromise;\n\n\treturn async function (...arguments_) {\n\t\tif (currentPromise) {\n\t\t\treturn currentPromise;\n\t\t}\n\n\t\ttry {\n\t\t\tcurrentPromise = function_.apply(this, arguments_);\n\t\t\treturn await currentPromise;\n\t\t} finally {\n\t\t\tcurrentPromise = undefined;\n\t\t}\n\t};\n};\n\nexport default pDebounce;\n","import cv from '@techstark/opencv-js';\nimport type { InferenceSession } from 'onnxruntime-web/all';\nimport type { Bounds } from '@/types';\nimport { maskToCanvas } from './mask-to-canvas';\nimport { boundsFromPoints, ShapeType, type Polygon } from '@annotorious/annotorious';\nimport { chaikinSmooth } from './chaikin-smooth';\n\nexport const maskToPolygon = (\n result: InferenceSession.ReturnType, \n bounds: Bounds,\n scale: number\n) => {\n const { canvas } = maskToCanvas(\n result, \n bounds,\n [255, 255, 255, 255],\n [0, 0, 0, 255]\n );\n\n const src = cv.imread(canvas);\n\n const dst = new cv.Mat();\n const contours = new cv.MatVector();\n const hierarchy = new cv.Mat();\n\n // To grayscale\n cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY);\n\n // Smoothing\n const size = new cv.Size(9, 9);\n cv.GaussianBlur(dst, dst, size, 0);\n cv.threshold(dst, dst, 80, 255, cv.THRESH_BINARY);\n\n // Fill small gaps\n const kernel = cv.Mat.ones(3, 3, cv.CV_8U);\n cv.morphologyEx(dst, dst, cv.MORPH_CLOSE, kernel);\n\n // Find countours\n cv.findContours(dst, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);\n\n // Collect polygons\n const polygons: Polygon[] = [];\n\n if (contours.size() > 0) {\n let largestContourIdx = 0;\n let largestContourSize = 0;\n \n for (let i = 0; i < contours.size(); i++) {\n let contourSize = contours.get(i).rows;\n if (contourSize > largestContourSize) {\n largestContourSize = contourSize;\n largestContourIdx = i;\n }\n }\n \n let contour = contours.get(largestContourIdx);\n \n let epsilon = 0.005 * cv.arcLength(contour, true);\n let simplifiedContour = new cv.Mat();\n\n cv.approxPolyDP(contour, simplifiedContour, epsilon, true);\n \n let points: [number, number][] = [];\n\n for (let i = 0; i < simplifiedContour.rows; i++) {\n points.push([\n simplifiedContour.data32S[i * 2] * scale,\n simplifiedContour.data32S[i * 2 + 1] * scale\n ]);\n }\n \n const smoothed = chaikinSmooth(points, 1);\n\n const polygon: Polygon = {\n type: ShapeType.POLYGON,\n geometry: {\n bounds: boundsFromPoints(smoothed),\n points: smoothed\n }\n }\n polygons.push(polygon);\n\n simplifiedContour.delete();\n }\n\n src.delete(); \n dst.delete(); \n contours.delete(); \n hierarchy.delete();\n\n return polygons[0];\n\n}","import type { Bounds } from '@/types';\nimport { getImageBounds } from './get-image-bounds';\n\n// Ported to TS from geronimi73 (MIT license)\n// https://github.com/geronimi73/next-sam/blob/main/lib/imageutils.js\nexport const prepareSAM2Canvas = (\n image: HTMLImageElement\n): Promise<{ canvas: HTMLCanvasElement, bounds: Bounds, scale: number }> => new Promise((resolve, reject) => {\n const copy = new Image();\n copy.crossOrigin = 'anonymous';\n\n copy.onload = () => {\n const { bounds, scale } = getImageBounds(\n { h: copy.naturalHeight, w: copy.naturalWidth },\n { h: 1024, w: 1024 }\n );\n\n const canvas = document.createElement('canvas');\n canvas.width = 1024;\n canvas.height = 1024;\n\n canvas\n .getContext('2d')!\n .drawImage(\n copy,\n 0,\n 0,\n copy.naturalWidth,\n copy.naturalHeight,\n bounds.x,\n bounds.y,\n bounds.w,\n bounds.h\n );\n \n resolve({ canvas, bounds, scale });\n }\n\n copy.onerror = error => {\n reject(error);\n }\n\n copy.src = image.src;\n});","import type { Bounds, Point, SAM2DecoderPrompt } from './types';\n\nconst R = window.devicePixelRatio || 1;\n\nexport const createPromptMarkerCanvas = (container: HTMLDivElement, bounds: Bounds, scale: number) => {\n const canvas = document.createElement('canvas');\n canvas.setAttribute('class', 'a9s-sam-input-markers');\n canvas.width = R * container.offsetWidth;\n canvas.height = R * container.offsetHeight;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) throw 'Error initializing canvas'; // Should never happen\n\n container.appendChild(canvas);\n\n const clear = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n }\n\n const drawPoint = (pt: Point, color: string) => {\n const x = R * (pt.x - bounds.x) * scale;\n const y = R * (pt.y - bounds.y) * scale;\n\n ctx.beginPath();\n ctx.arc(x, y, 5 * R, 0, 2 * Math.PI, false);\n ctx.fillStyle = color;\n ctx.fill();\n ctx.lineWidth = 1 * R;\n ctx.strokeStyle = '#000';\n ctx.stroke();\n }\n\n const setInput = (input: SAM2DecoderPrompt) => {\n clear();\n input.include.forEach(pt => drawPoint(pt, '#33ff33'));\n input.exclude.forEach(pt => drawPoint(pt, '#ff3333'));\n }\n\n return {\n clear,\n setInput\n }\n}","import type { InferenceSession } from 'onnxruntime-web/all';\nimport { maskToCanvas } from './utils';\nimport type { Bounds } from './types';\n\nexport const createPreviewCanvas = (container: HTMLDivElement, bounds: Bounds) => {\n const image = container?.querySelector('img');\n if (!image) return;\n\n let _visible = true;\n\n const renderMask = (result: InferenceSession.ReturnType) => {\n if (!_visible) return;\n\n const { canvas } = maskToCanvas(\n result, \n bounds,\n [0, 114, 189, 255],\n [0, 0, 0, 0]\n );\n\n container.querySelector('.a9s-sam-preview')?.remove();\n container.appendChild(canvas);\n }\n\n const setVisible = (visible: boolean) => {\n _visible = visible;\n\n if (!visible)\n container.querySelector('.a9s-sam-preview')?.remove();\n }\n\n return {\n renderMask,\n setVisible\n }\n}","import pDebounce from 'p-debounce';\nimport { v4 as uuidv4 } from 'uuid';\nimport type { ImageAnnotation, ImageAnnotator } from '@annotorious/annotorious';\nimport SAM2Worker from './sam2/sam2-worker.ts?worker';\nimport type { SAM2WorkerResult } from './sam2';\nimport { canvasToFloat32Array, maskToPolygon, prepareSAM2Canvas } from './utils';\nimport { createPromptMarkerCanvas } from './prompt-marker-canvas';\nimport { createPreviewCanvas } from './preview-canvas';\nimport type { Point, SAM2DecoderPrompt, SAMPluginOpts } from './types';\n\nimport './index.css';\n\nexport const mountPlugin = (anno: ImageAnnotator, opts: SAMPluginOpts = {}) => {\n let _enabled = false;\n\n let currentAnnotationId: string;\n\n const container = anno.element;\n\n let input: SAM2DecoderPrompt = {\n\n include: [],\n \n exclude: []\n \n }; \n\n const image = container?.querySelector('img') as HTMLImageElement;\n if (!image) return;\n\n const SAM2 = new SAM2Worker();\n\n let onPointerMove: ((evt: PointerEvent) => void) | null = null;\n let onPointerDown: ((evt: PointerEvent) => void) | null = null;\n\n let promptMarkerCanvas: ReturnType<typeof createPromptMarkerCanvas>;\n\n let previewCanvas: ReturnType<typeof createPreviewCanvas>;\n\n const updateEventListeners = () => {\n if (!onPointerMove || !onPointerDown) return;\n \n if (_enabled) {\n container.addEventListener('pointermove', onPointerMove);\n container.addEventListener('pointerdown', onPointerDown);\n } else {\n container.removeEventListener('pointermove', onPointerMove);\n container.removeEventListener('pointerdown', onPointerDown);\n }\n }\n\n const debouncedPreview = pDebounce((pt: Point) => {\n SAM2.postMessage({ type: 'decode_preview', point: pt });\n }, 1);\n\n // Off-screen copy, resized and padded to 1024x1024px.\n prepareSAM2Canvas(image).then(({ canvas: bufferedImage, bounds, scale }) => {\n const viewportToSAM2Coordinates = (evt: PointerEvent) => {\n const scaleX = image.naturalWidth / (scale * image.offsetWidth);\n const scaleY = image.naturalHeight / (scale * image.offsetHeight);\n \n const { offsetX, offsetY } = evt;\n \n const x = (offsetX * scaleX) + bounds.x;\n const y = (offsetY * scaleY) + bounds.y;\n\n return { x, y };\n }\n\n onPointerMove = (evt: PointerEvent) => {\n if (input.include.length + input.exclude.length > 0) return;\n \n const { x, y } = viewportToSAM2Coordinates(evt); \n debouncedPreview({ x, y });\n }\n\n onPointerDown = (evt: PointerEvent) => {\n const { x, y } = viewportToSAM2Coordinates(evt);\n\n if (evt.shiftKey) {\n input.exclude.push({ x, y });\n } else {\n input.include.push({ x, y });\n }\n\n previewCanvas?.setVisible(false);\n\n promptMarkerCanvas?.setInput(input);\n\n SAM2.postMessage({ type: 'decode', input });\n }\n\n previewCanvas = createPreviewCanvas(anno.element, bounds);\n\n promptMarkerCanvas = createPromptMarkerCanvas(anno.element, bounds, scale);\n\n SAM2.onmessage = ((message: MessageEvent<SAM2WorkerResult>) => {\n const { type } = message.data;\n \n if (type === 'init_success') {\n // Models loaded - encode the image\n console.log('[annotorious-sam] Encoding image...');\n\n const data = canvasToFloat32Array(bufferedImage);\n SAM2.postMessage({ type: 'encode', data });\n } else if (type === 'encode_success') {\n console.log('[annotorious-sam] Encoding complete');\n\n // Image encoded – add pointer listeners\n updateEventListeners();\n } else if (type === 'decode_preview_success') {\n // Render mask every time the worker has decoded one\n previewCanvas?.renderMask(message.data.result);\n } else if (type === 'decode_success') {\n // Render mask every time the worker has decoded one\n const polygon = maskToPolygon(message.data.result, bounds, scale);\n\n const annotation: ImageAnnotation = {\n id: currentAnnotationId,\n bodies: [],\n target: {\n annotation: currentAnnotationId,\n selector: polygon,\n creator: { id: 'rainer' },\n created: new Date()\n }\n };\n\n const { store, selection } = anno.state;\n\n const exists = store.getAnnotation(currentAnnotationId);\n if (exists) {\n store.updateAnnotation(currentAnnotationId, annotation);\n } else {\n store.addAnnotation(annotation);\n }\n\n // selection.setSelected(currentAnnotationId);\n }\n });\n \n SAM2.postMessage({ type: 'init' });\n });\n\n const setEnabled = (enabled: boolean) => {\n _enabled = enabled;\n\n currentAnnotationId = uuidv4();\n\n updateEventListeners();\n\n previewCanvas?.setVisible(enabled);\n }\n\n const setShowPreview = (showPreview: boolean) => {\n previewCanvas?.setVisible(showPreview);\n }\n\n return {\n setEnabled,\n setShowPreview\n }\n\n}\n\nexport * from './types';"],"names":["pDebounce","fn","wait","options","leadingValue","timeout","resolveList","arguments_","resolve","shouldCallNow","result","function_","currentPromise","maskToPolygon","bounds","scale","canvas","maskToCanvas","src","cv","dst","contours","hierarchy","size","kernel","polygons","largestContourIdx","largestContourSize","i","contourSize","contour","epsilon","simplifiedContour","points","smoothed","chaikinSmooth","polygon","ShapeType","boundsFromPoints","prepareSAM2Canvas","image","reject","copy","getImageBounds","error","R","createPromptMarkerCanvas","container","ctx","clear","drawPoint","pt","color","x","y","input","createPreviewCanvas","_visible","_a","visible","mountPlugin","anno","opts","_enabled","currentAnnotationId","SAM2","SAM2Worker","onPointerMove","onPointerDown","promptMarkerCanvas","previewCanvas","updateEventListeners","debouncedPreview","bufferedImage","viewportToSAM2Coordinates","evt","scaleX","scaleY","offsetX","offsetY","message","type","data","canvasToFloat32Array","annotation","store","selection","enabled","uuidv4","showPreview"],"mappings":"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","x_google_ignoreList":[0]}
|