@annotorious/plugin-segment-anything 0.1.13 → 0.1.14

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/dist/index.js CHANGED
@@ -1,45 +1,45 @@
1
1
  import { m as R, c as r, a as k, O as C, G as O, g as T, W as H, b as W, v as V } from "./get-image-bounds-B0QYmG5-.js";
2
- const L = (s, a, d = {}) => {
2
+ const L = (n, a, d = {}) => {
3
3
  if (!Number.isFinite(a))
4
4
  throw new TypeError("Expected `wait` to be a finite number");
5
- let t, e, n = [];
5
+ let t, e, s = [];
6
6
  return function(...o) {
7
7
  return new Promise((i) => {
8
8
  const l = d.before && !e;
9
9
  clearTimeout(e), e = setTimeout(() => {
10
10
  e = null;
11
- const u = d.before ? t : s.apply(this, o);
12
- for (i of n)
11
+ const u = d.before ? t : n.apply(this, o);
12
+ for (i of s)
13
13
  i(u);
14
- n = [];
15
- }, a), l ? (t = s.apply(this, o), i(t)) : n.push(i);
14
+ s = [];
15
+ }, a), l ? (t = n.apply(this, o), i(t)) : s.push(i);
16
16
  });
17
17
  };
18
18
  };
19
- L.promise = (s) => {
19
+ L.promise = (n) => {
20
20
  let a;
21
21
  return async function(...d) {
22
22
  if (a)
23
23
  return a;
24
24
  try {
25
- return a = s.apply(this, d), await a;
25
+ return a = n.apply(this, d), await a;
26
26
  } finally {
27
27
  a = void 0;
28
28
  }
29
29
  };
30
30
  };
31
- const z = (s, a, d) => {
31
+ const z = (n, a, d) => {
32
32
  const { canvas: t } = R(
33
- s,
33
+ n,
34
34
  a,
35
35
  [255, 255, 255, 255],
36
36
  [0, 0, 0, 255]
37
- ), e = r.imread(t), n = new r.Mat(), o = new r.MatVector(), i = new r.Mat();
38
- r.cvtColor(e, n, r.COLOR_RGBA2GRAY);
37
+ ), e = r.imread(t), s = new r.Mat(), o = new r.MatVector(), i = new r.Mat();
38
+ r.cvtColor(e, s, r.COLOR_RGBA2GRAY);
39
39
  const l = new r.Size(9, 9);
40
- r.GaussianBlur(n, n, l, 0), r.threshold(n, n, 80, 255, r.THRESH_BINARY);
40
+ r.GaussianBlur(s, s, l, 0), r.threshold(s, s, 80, 255, r.THRESH_BINARY);
41
41
  const u = r.Mat.ones(3, 3, r.CV_8U);
42
- r.morphologyEx(n, n, r.MORPH_CLOSE, u), r.findContours(n, o, i, r.RETR_EXTERNAL, r.CHAIN_APPROX_SIMPLE);
42
+ r.morphologyEx(s, s, r.MORPH_CLOSE, u), r.findContours(s, o, i, r.RETR_EXTERNAL, r.CHAIN_APPROX_SIMPLE);
43
43
  const y = [];
44
44
  if (o.size() > 0) {
45
45
  let c = 0, v = 0;
@@ -64,11 +64,11 @@ const z = (s, a, d) => {
64
64
  };
65
65
  y.push(E), x.delete();
66
66
  }
67
- return e.delete(), n.delete(), o.delete(), i.delete(), y[0];
68
- }, N = (s) => new Promise((a, d) => {
67
+ return e.delete(), s.delete(), o.delete(), i.delete(), y[0];
68
+ }, N = (n) => new Promise((a, d) => {
69
69
  const t = new Image();
70
70
  t.crossOrigin = "anonymous", t.onload = () => {
71
- const { bounds: e, scale: n } = T(
71
+ const { bounds: e, scale: s } = T(
72
72
  { h: t.naturalHeight, w: t.naturalWidth },
73
73
  { h: 1024, w: 1024 }
74
74
  ), o = document.createElement("canvas");
@@ -82,30 +82,30 @@ const z = (s, a, d) => {
82
82
  e.y,
83
83
  e.w,
84
84
  e.h
85
- ), a({ canvas: o, bounds: e, scale: n });
85
+ ), a({ canvas: o, bounds: e, scale: s });
86
86
  }, t.onerror = (e) => {
87
87
  d(e);
88
- }, t.src = s.src;
89
- }), P = window.devicePixelRatio || 1, G = (s, a, d) => {
88
+ }, t.src = n.src;
89
+ }), P = window.devicePixelRatio || 1, G = (n, a, d) => {
90
90
  const t = document.createElement("canvas");
91
- t.setAttribute("class", "a9s-sam-input-markers"), t.width = P * s.offsetWidth, t.height = P * s.offsetHeight;
91
+ t.setAttribute("class", "a9s-sam-input-markers"), t.width = P * n.offsetWidth, t.height = P * n.offsetHeight;
92
92
  const e = t.getContext("2d");
93
93
  if (!e) throw "Error initializing canvas";
94
- s.appendChild(t);
95
- const n = () => {
94
+ n.appendChild(t);
95
+ const s = () => {
96
96
  e.clearRect(0, 0, t.width, t.height);
97
97
  }, o = (l, u) => {
98
98
  const y = P * (l.x - a.x) * d, c = P * (l.y - a.y) * d;
99
99
  e.beginPath(), e.arc(y, c, 5 * P, 0, 2 * Math.PI, !1), e.fillStyle = u, e.fill(), e.lineWidth = 1 * P, e.strokeStyle = "#000", e.stroke();
100
100
  };
101
101
  return {
102
- clear: n,
102
+ clear: s,
103
103
  setInput: (l) => {
104
- n(), l.include.forEach((u) => o(u, "#33ff33")), l.exclude.forEach((u) => o(u, "#ff3333"));
104
+ s(), l.include.forEach((u) => o(u, "#33ff33")), l.exclude.forEach((u) => o(u, "#ff3333"));
105
105
  }
106
106
  };
107
- }, Y = (s, a) => {
108
- if (!s.querySelector("img")) return;
107
+ }, Y = (n, a) => {
108
+ if (!(n == null ? void 0 : n.querySelector("img"))) return;
109
109
  let t = !0;
110
110
  return {
111
111
  renderMask: (o) => {
@@ -117,17 +117,17 @@ const z = (s, a, d) => {
117
117
  [0, 114, 189, 255],
118
118
  [0, 0, 0, 0]
119
119
  );
120
- (l = s.querySelector(".a9s-sam-preview")) == null || l.remove(), s.appendChild(i);
120
+ (l = n.querySelector(".a9s-sam-preview")) == null || l.remove(), n.appendChild(i);
121
121
  },
122
122
  setVisible: (o) => {
123
123
  var i;
124
- t = o, o || (i = s.querySelector(".a9s-sam-preview")) == null || i.remove();
124
+ t = o, o || (i = n.querySelector(".a9s-sam-preview")) == null || i.remove();
125
125
  }
126
126
  };
127
- }, B = (s, a = {}) => {
127
+ }, B = (n, a = {}) => {
128
128
  let d = !1, t;
129
- const e = s.element;
130
- let n = {
129
+ const e = n.element;
130
+ let s = {
131
131
  include: [],
132
132
  exclude: []
133
133
  };
@@ -146,13 +146,13 @@ const z = (s, a, d) => {
146
146
  return { x: _, y: I };
147
147
  };
148
148
  l = (f) => {
149
- if (n.include.length + n.exclude.length > 0) return;
149
+ if (s.include.length + s.exclude.length > 0) return;
150
150
  const { x: m, y: g } = h(f);
151
151
  M({ x: m, y: g });
152
152
  }, u = (f) => {
153
153
  const { x: m, y: g } = h(f);
154
- f.shiftKey ? n.exclude.push({ x: m, y: g }) : n.include.push({ x: m, y: g }), c == null || c.setVisible(!1), y == null || y.setInput(n), i.postMessage({ type: "decode", input: n });
155
- }, c = Y(s.element, w), y = G(s.element, w, E), i.onmessage = (f) => {
154
+ f.shiftKey ? s.exclude.push({ x: m, y: g }) : s.include.push({ x: m, y: g }), c == null || c.setVisible(!1), y == null || y.setInput(s), i.postMessage({ type: "decode", input: s });
155
+ }, c = Y(n.element, w), y = G(n.element, w, E), i.onmessage = (f) => {
156
156
  const { type: m } = f.data;
157
157
  if (m === "init_success") {
158
158
  console.log("[annotorious-sam] Encoding image...");
@@ -172,7 +172,7 @@ const z = (s, a, d) => {
172
172
  creator: { id: "rainer" },
173
173
  created: /* @__PURE__ */ new Date()
174
174
  }
175
- }, { store: S, selection: _ } = s.state;
175
+ }, { store: S, selection: _ } = n.state;
176
176
  S.getAnnotation(t) ? S.updateAnnotation(t, b) : S.addAnnotation(b);
177
177
  }
178
178
  }, i.postMessage({ type: "init" });
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/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]}
@@ -2,6 +2,7 @@ import { OpenSeadragonAnnotator } from '@annotorious/openseadragon';
2
2
  import { SAMPluginEvents, SAMPluginOpts } from '../types';
3
3
  export declare const mountOpenSeadragonPlugin: (anno: OpenSeadragonAnnotator, opts?: SAMPluginOpts) => {
4
4
  destroy: () => void;
5
+ init: () => void;
5
6
  reset: () => void;
6
7
  restart: () => void;
7
8
  setQueryMode: (mode: "add" | "remove") => "add" | "remove";