radames commited on
Commit
2cfd6b4
1 Parent(s): 32df74a
Files changed (6) hide show
  1. index.html +98 -17
  2. sam/m.d.ts +59 -0
  3. sam/m.js +580 -0
  4. sam/m_bg.wasm +3 -0
  5. sam/m_bg.wasm.d.ts +14 -0
  6. samWorker.js +167 -0
index.html CHANGED
@@ -1,19 +1,100 @@
1
- <!DOCTYPE html>
2
  <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
 
1
  <html>
2
+ <head>
3
+ <script
4
+ type="module"
5
+ crossorigin
6
+ src="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.js"
7
+ ></script>
8
+ <link
9
+ rel="stylesheet"
10
+ href="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.css"
11
+ />
12
+ <script type="module">
13
+ const MODEL_URL =
14
+ "https://huggingface.co/lmz/candle-sam/resolve/main/mobile_sam-tiny-vitt.safetensors";
15
+
16
+ const samWorker = new Worker("./samWorker.js", { type: "module" });
17
+
18
+ async function segmentPoints(
19
+ imageURL, // URL to the image file
20
+ points, // {x, y} points to prompt image
21
+ modelURL = MODEL_URL, // URL to the weights file
22
+ modelID = "sam_mobile_tiny" // model ID
23
+ ) {
24
+ return new Promise((resolve, reject) => {
25
+ function messageHandler(event) {
26
+ console.log(event.data);
27
+ // if ("status" in event.data) {
28
+
29
+ // }
30
+ if ("error" in event.data) {
31
+ samWorker.removeEventListener("message", messageHandler);
32
+ reject(new Error(event.data.error));
33
+ }
34
+ if (event.data.status === "complete-embedding") {
35
+ samWorker.removeEventListener("message", messageHandler);
36
+ resolve();
37
+ }
38
+ if (event.data.status === "complete") {
39
+ samWorker.removeEventListener("message", messageHandler);
40
+ resolve(event.data.output);
41
+ }
42
+ }
43
+ samWorker.addEventListener("message", messageHandler);
44
+ samWorker.postMessage({
45
+ modelURL,
46
+ modelID,
47
+ imageURL,
48
+ points,
49
+ });
50
+ });
51
+ }
52
+ globalThis.segmentPoints = segmentPoints;
53
+ </script>
54
+ </head>
55
+
56
+ <body>
57
+ <!-- prettier-ignore -->
58
+ <gradio-lite>
59
+ import gradio as gr
60
+
61
+
62
+ get_point_mask = """
63
+ async function getPointMask(image, points) {
64
+ console.log("getting point mask");
65
+ console.log(points)
66
+ const { maskURL } = await segmentPoints(
67
+ image,
68
+ points
69
+ );
70
+ if(points.length == 0){
71
+ return [ null ];
72
+ }
73
+ return [ maskURL ];
74
+ }
75
+ """
76
+ def set_points(image, points_state, evt: gr.SelectData):
77
+ points_state.append([evt.index[0]/image.width, evt.index[1]/image.height, True])
78
+ return points_state, points_state
79
+
80
+ with gr.Blocks() as demo:
81
+ gr.Markdown("""## Segment Anything Model (SAM) with Gradio Lite
82
+ This demo uses [Gradio Lite](https://www.gradio.app/guides/gradio-lite) as UI for running the Segment Anything Model (SAM) with WASM build with [Candle](https://github.com/huggingface/candle).
83
+
84
+ **Note:** The model's first run may take a few seconds as it loads and caches the model in the browser, and then creates the image embeddings. Any subsequent clicks on points will be significantly faster.
85
+ """)
86
+ points_state = gr.State([])
87
+ with gr.Row():
88
+ with gr.Column():
89
+ image = gr.Image(label="Input Image", type="pil")
90
+ clear_points = gr.Button(value="Clear Points")
91
+ points = gr.JSON(label="Input Points", visible=False)
92
+ with gr.Column():
93
+ mask = gr.Image(label="Output Mask")
94
+ clear_points.click(lambda: ([], []), None, [points, points_state])
95
+ image.select(set_points, inputs=[image, points_state], outputs=[points, points_state])
96
+ points.change(None, inputs=[image, points], outputs=[mask], _js=get_point_mask)
97
+ demo.launch(show_api=False)
98
+ </gradio-lite>
99
+ </body>
100
  </html>
sam/m.d.ts ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ */
5
+ export class Model {
6
+ free(): void;
7
+ /**
8
+ * @param {Uint8Array} weights
9
+ * @param {boolean} use_tiny
10
+ */
11
+ constructor(weights: Uint8Array, use_tiny: boolean);
12
+ /**
13
+ * @param {Uint8Array} image_data
14
+ */
15
+ set_image_embeddings(image_data: Uint8Array): void;
16
+ /**
17
+ * @param {any} input
18
+ * @returns {any}
19
+ */
20
+ mask_for_point(input: any): any;
21
+ }
22
+
23
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
24
+
25
+ export interface InitOutput {
26
+ readonly memory: WebAssembly.Memory;
27
+ readonly __wbg_model_free: (a: number) => void;
28
+ readonly model_new: (a: number, b: number, c: number, d: number) => void;
29
+ readonly model_set_image_embeddings: (a: number, b: number, c: number, d: number) => void;
30
+ readonly model_mask_for_point: (a: number, b: number, c: number) => void;
31
+ readonly main: (a: number, b: number) => number;
32
+ readonly __wbindgen_malloc: (a: number, b: number) => number;
33
+ readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
34
+ readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
35
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
36
+ readonly __wbindgen_exn_store: (a: number) => void;
37
+ readonly __wbindgen_start: () => void;
38
+ }
39
+
40
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
41
+ /**
42
+ * Instantiates the given `module`, which can either be bytes or
43
+ * a precompiled `WebAssembly.Module`.
44
+ *
45
+ * @param {SyncInitInput} module
46
+ *
47
+ * @returns {InitOutput}
48
+ */
49
+ export function initSync(module: SyncInitInput): InitOutput;
50
+
51
+ /**
52
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
53
+ * for everything else, calls `WebAssembly.instantiate` directly.
54
+ *
55
+ * @param {InitInput | Promise<InitInput>} module_or_path
56
+ *
57
+ * @returns {Promise<InitOutput>}
58
+ */
59
+ export default function __wbg_init (module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>;
sam/m.js ADDED
@@ -0,0 +1,580 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ let wasm;
2
+
3
+ const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
4
+
5
+ if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
6
+
7
+ let cachedUint8Memory0 = null;
8
+
9
+ function getUint8Memory0() {
10
+ if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
11
+ cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
12
+ }
13
+ return cachedUint8Memory0;
14
+ }
15
+
16
+ function getStringFromWasm0(ptr, len) {
17
+ ptr = ptr >>> 0;
18
+ return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
19
+ }
20
+
21
+ const heap = new Array(128).fill(undefined);
22
+
23
+ heap.push(undefined, null, true, false);
24
+
25
+ let heap_next = heap.length;
26
+
27
+ function addHeapObject(obj) {
28
+ if (heap_next === heap.length) heap.push(heap.length + 1);
29
+ const idx = heap_next;
30
+ heap_next = heap[idx];
31
+
32
+ heap[idx] = obj;
33
+ return idx;
34
+ }
35
+
36
+ function getObject(idx) { return heap[idx]; }
37
+
38
+ function dropObject(idx) {
39
+ if (idx < 132) return;
40
+ heap[idx] = heap_next;
41
+ heap_next = idx;
42
+ }
43
+
44
+ function takeObject(idx) {
45
+ const ret = getObject(idx);
46
+ dropObject(idx);
47
+ return ret;
48
+ }
49
+
50
+ function isLikeNone(x) {
51
+ return x === undefined || x === null;
52
+ }
53
+
54
+ let cachedFloat64Memory0 = null;
55
+
56
+ function getFloat64Memory0() {
57
+ if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) {
58
+ cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer);
59
+ }
60
+ return cachedFloat64Memory0;
61
+ }
62
+
63
+ let cachedInt32Memory0 = null;
64
+
65
+ function getInt32Memory0() {
66
+ if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) {
67
+ cachedInt32Memory0 = new Int32Array(wasm.memory.buffer);
68
+ }
69
+ return cachedInt32Memory0;
70
+ }
71
+
72
+ let WASM_VECTOR_LEN = 0;
73
+
74
+ const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } );
75
+
76
+ const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
77
+ ? function (arg, view) {
78
+ return cachedTextEncoder.encodeInto(arg, view);
79
+ }
80
+ : function (arg, view) {
81
+ const buf = cachedTextEncoder.encode(arg);
82
+ view.set(buf);
83
+ return {
84
+ read: arg.length,
85
+ written: buf.length
86
+ };
87
+ });
88
+
89
+ function passStringToWasm0(arg, malloc, realloc) {
90
+
91
+ if (realloc === undefined) {
92
+ const buf = cachedTextEncoder.encode(arg);
93
+ const ptr = malloc(buf.length, 1) >>> 0;
94
+ getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
95
+ WASM_VECTOR_LEN = buf.length;
96
+ return ptr;
97
+ }
98
+
99
+ let len = arg.length;
100
+ let ptr = malloc(len, 1) >>> 0;
101
+
102
+ const mem = getUint8Memory0();
103
+
104
+ let offset = 0;
105
+
106
+ for (; offset < len; offset++) {
107
+ const code = arg.charCodeAt(offset);
108
+ if (code > 0x7F) break;
109
+ mem[ptr + offset] = code;
110
+ }
111
+
112
+ if (offset !== len) {
113
+ if (offset !== 0) {
114
+ arg = arg.slice(offset);
115
+ }
116
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
117
+ const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
118
+ const ret = encodeString(arg, view);
119
+
120
+ offset += ret.written;
121
+ }
122
+
123
+ WASM_VECTOR_LEN = offset;
124
+ return ptr;
125
+ }
126
+
127
+ function debugString(val) {
128
+ // primitive types
129
+ const type = typeof val;
130
+ if (type == 'number' || type == 'boolean' || val == null) {
131
+ return `${val}`;
132
+ }
133
+ if (type == 'string') {
134
+ return `"${val}"`;
135
+ }
136
+ if (type == 'symbol') {
137
+ const description = val.description;
138
+ if (description == null) {
139
+ return 'Symbol';
140
+ } else {
141
+ return `Symbol(${description})`;
142
+ }
143
+ }
144
+ if (type == 'function') {
145
+ const name = val.name;
146
+ if (typeof name == 'string' && name.length > 0) {
147
+ return `Function(${name})`;
148
+ } else {
149
+ return 'Function';
150
+ }
151
+ }
152
+ // objects
153
+ if (Array.isArray(val)) {
154
+ const length = val.length;
155
+ let debug = '[';
156
+ if (length > 0) {
157
+ debug += debugString(val[0]);
158
+ }
159
+ for(let i = 1; i < length; i++) {
160
+ debug += ', ' + debugString(val[i]);
161
+ }
162
+ debug += ']';
163
+ return debug;
164
+ }
165
+ // Test for built-in
166
+ const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
167
+ let className;
168
+ if (builtInMatches.length > 1) {
169
+ className = builtInMatches[1];
170
+ } else {
171
+ // Failed to match the standard '[object ClassName]'
172
+ return toString.call(val);
173
+ }
174
+ if (className == 'Object') {
175
+ // we're a user defined class or Object
176
+ // JSON.stringify avoids problems with cycles, and is generally much
177
+ // easier than looping through ownProperties of `val`.
178
+ try {
179
+ return 'Object(' + JSON.stringify(val) + ')';
180
+ } catch (_) {
181
+ return 'Object';
182
+ }
183
+ }
184
+ // errors
185
+ if (val instanceof Error) {
186
+ return `${val.name}: ${val.message}\n${val.stack}`;
187
+ }
188
+ // TODO we could test for more things here, like `Set`s and `Map`s.
189
+ return className;
190
+ }
191
+
192
+ function passArray8ToWasm0(arg, malloc) {
193
+ const ptr = malloc(arg.length * 1, 1) >>> 0;
194
+ getUint8Memory0().set(arg, ptr / 1);
195
+ WASM_VECTOR_LEN = arg.length;
196
+ return ptr;
197
+ }
198
+
199
+ function handleError(f, args) {
200
+ try {
201
+ return f.apply(this, args);
202
+ } catch (e) {
203
+ wasm.__wbindgen_exn_store(addHeapObject(e));
204
+ }
205
+ }
206
+ /**
207
+ */
208
+ export class Model {
209
+
210
+ static __wrap(ptr) {
211
+ ptr = ptr >>> 0;
212
+ const obj = Object.create(Model.prototype);
213
+ obj.__wbg_ptr = ptr;
214
+
215
+ return obj;
216
+ }
217
+
218
+ __destroy_into_raw() {
219
+ const ptr = this.__wbg_ptr;
220
+ this.__wbg_ptr = 0;
221
+
222
+ return ptr;
223
+ }
224
+
225
+ free() {
226
+ const ptr = this.__destroy_into_raw();
227
+ wasm.__wbg_model_free(ptr);
228
+ }
229
+ /**
230
+ * @param {Uint8Array} weights
231
+ * @param {boolean} use_tiny
232
+ */
233
+ constructor(weights, use_tiny) {
234
+ try {
235
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
236
+ const ptr0 = passArray8ToWasm0(weights, wasm.__wbindgen_malloc);
237
+ const len0 = WASM_VECTOR_LEN;
238
+ wasm.model_new(retptr, ptr0, len0, use_tiny);
239
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
240
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
241
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
242
+ if (r2) {
243
+ throw takeObject(r1);
244
+ }
245
+ return Model.__wrap(r0);
246
+ } finally {
247
+ wasm.__wbindgen_add_to_stack_pointer(16);
248
+ }
249
+ }
250
+ /**
251
+ * @param {Uint8Array} image_data
252
+ */
253
+ set_image_embeddings(image_data) {
254
+ try {
255
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
256
+ const ptr0 = passArray8ToWasm0(image_data, wasm.__wbindgen_malloc);
257
+ const len0 = WASM_VECTOR_LEN;
258
+ wasm.model_set_image_embeddings(retptr, this.__wbg_ptr, ptr0, len0);
259
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
260
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
261
+ if (r1) {
262
+ throw takeObject(r0);
263
+ }
264
+ } finally {
265
+ wasm.__wbindgen_add_to_stack_pointer(16);
266
+ }
267
+ }
268
+ /**
269
+ * @param {any} input
270
+ * @returns {any}
271
+ */
272
+ mask_for_point(input) {
273
+ try {
274
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
275
+ wasm.model_mask_for_point(retptr, this.__wbg_ptr, addHeapObject(input));
276
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
277
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
278
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
279
+ if (r2) {
280
+ throw takeObject(r1);
281
+ }
282
+ return takeObject(r0);
283
+ } finally {
284
+ wasm.__wbindgen_add_to_stack_pointer(16);
285
+ }
286
+ }
287
+ }
288
+
289
+ async function __wbg_load(module, imports) {
290
+ if (typeof Response === 'function' && module instanceof Response) {
291
+ if (typeof WebAssembly.instantiateStreaming === 'function') {
292
+ try {
293
+ return await WebAssembly.instantiateStreaming(module, imports);
294
+
295
+ } catch (e) {
296
+ if (module.headers.get('Content-Type') != 'application/wasm') {
297
+ console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
298
+
299
+ } else {
300
+ throw e;
301
+ }
302
+ }
303
+ }
304
+
305
+ const bytes = await module.arrayBuffer();
306
+ return await WebAssembly.instantiate(bytes, imports);
307
+
308
+ } else {
309
+ const instance = await WebAssembly.instantiate(module, imports);
310
+
311
+ if (instance instanceof WebAssembly.Instance) {
312
+ return { instance, module };
313
+
314
+ } else {
315
+ return instance;
316
+ }
317
+ }
318
+ }
319
+
320
+ function __wbg_get_imports() {
321
+ const imports = {};
322
+ imports.wbg = {};
323
+ imports.wbg.__wbindgen_error_new = function(arg0, arg1) {
324
+ const ret = new Error(getStringFromWasm0(arg0, arg1));
325
+ return addHeapObject(ret);
326
+ };
327
+ imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
328
+ takeObject(arg0);
329
+ };
330
+ imports.wbg.__wbindgen_boolean_get = function(arg0) {
331
+ const v = getObject(arg0);
332
+ const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
333
+ return ret;
334
+ };
335
+ imports.wbg.__wbindgen_number_get = function(arg0, arg1) {
336
+ const obj = getObject(arg1);
337
+ const ret = typeof(obj) === 'number' ? obj : undefined;
338
+ getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret;
339
+ getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret);
340
+ };
341
+ imports.wbg.__wbindgen_is_object = function(arg0) {
342
+ const val = getObject(arg0);
343
+ const ret = typeof(val) === 'object' && val !== null;
344
+ return ret;
345
+ };
346
+ imports.wbg.__wbindgen_is_undefined = function(arg0) {
347
+ const ret = getObject(arg0) === undefined;
348
+ return ret;
349
+ };
350
+ imports.wbg.__wbindgen_in = function(arg0, arg1) {
351
+ const ret = getObject(arg0) in getObject(arg1);
352
+ return ret;
353
+ };
354
+ imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
355
+ const ret = getObject(arg0);
356
+ return addHeapObject(ret);
357
+ };
358
+ imports.wbg.__wbindgen_jsval_loose_eq = function(arg0, arg1) {
359
+ const ret = getObject(arg0) == getObject(arg1);
360
+ return ret;
361
+ };
362
+ imports.wbg.__wbindgen_string_get = function(arg0, arg1) {
363
+ const obj = getObject(arg1);
364
+ const ret = typeof(obj) === 'string' ? obj : undefined;
365
+ var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
366
+ var len1 = WASM_VECTOR_LEN;
367
+ getInt32Memory0()[arg0 / 4 + 1] = len1;
368
+ getInt32Memory0()[arg0 / 4 + 0] = ptr1;
369
+ };
370
+ imports.wbg.__wbg_String_4370c5505c674d30 = function(arg0, arg1) {
371
+ const ret = String(getObject(arg1));
372
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
373
+ const len1 = WASM_VECTOR_LEN;
374
+ getInt32Memory0()[arg0 / 4 + 1] = len1;
375
+ getInt32Memory0()[arg0 / 4 + 0] = ptr1;
376
+ };
377
+ imports.wbg.__wbindgen_number_new = function(arg0) {
378
+ const ret = arg0;
379
+ return addHeapObject(ret);
380
+ };
381
+ imports.wbg.__wbindgen_bigint_from_u64 = function(arg0) {
382
+ const ret = BigInt.asUintN(64, arg0);
383
+ return addHeapObject(ret);
384
+ };
385
+ imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
386
+ const ret = getStringFromWasm0(arg0, arg1);
387
+ return addHeapObject(ret);
388
+ };
389
+ imports.wbg.__wbg_getwithrefkey_d1f0d12f1f1b63ea = function(arg0, arg1) {
390
+ const ret = getObject(arg0)[getObject(arg1)];
391
+ return addHeapObject(ret);
392
+ };
393
+ imports.wbg.__wbg_set_bd72c078edfa51ad = function(arg0, arg1, arg2) {
394
+ getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
395
+ };
396
+ imports.wbg.__wbg_new_abda76e883ba8a5f = function() {
397
+ const ret = new Error();
398
+ return addHeapObject(ret);
399
+ };
400
+ imports.wbg.__wbg_stack_658279fe44541cf6 = function(arg0, arg1) {
401
+ const ret = getObject(arg1).stack;
402
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
403
+ const len1 = WASM_VECTOR_LEN;
404
+ getInt32Memory0()[arg0 / 4 + 1] = len1;
405
+ getInt32Memory0()[arg0 / 4 + 0] = ptr1;
406
+ };
407
+ imports.wbg.__wbg_error_f851667af71bcfc6 = function(arg0, arg1) {
408
+ let deferred0_0;
409
+ let deferred0_1;
410
+ try {
411
+ deferred0_0 = arg0;
412
+ deferred0_1 = arg1;
413
+ console.error(getStringFromWasm0(arg0, arg1));
414
+ } finally {
415
+ wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
416
+ }
417
+ };
418
+ imports.wbg.__wbg_log_cfcb93115564df45 = function(arg0, arg1) {
419
+ console.log(getStringFromWasm0(arg0, arg1));
420
+ };
421
+ imports.wbg.__wbindgen_is_function = function(arg0) {
422
+ const ret = typeof(getObject(arg0)) === 'function';
423
+ return ret;
424
+ };
425
+ imports.wbg.__wbg_get_44be0491f933a435 = function(arg0, arg1) {
426
+ const ret = getObject(arg0)[arg1 >>> 0];
427
+ return addHeapObject(ret);
428
+ };
429
+ imports.wbg.__wbg_length_fff51ee6522a1a18 = function(arg0) {
430
+ const ret = getObject(arg0).length;
431
+ return ret;
432
+ };
433
+ imports.wbg.__wbg_new_898a68150f225f2e = function() {
434
+ const ret = new Array();
435
+ return addHeapObject(ret);
436
+ };
437
+ imports.wbg.__wbg_next_526fc47e980da008 = function(arg0) {
438
+ const ret = getObject(arg0).next;
439
+ return addHeapObject(ret);
440
+ };
441
+ imports.wbg.__wbg_next_ddb3312ca1c4e32a = function() { return handleError(function (arg0) {
442
+ const ret = getObject(arg0).next();
443
+ return addHeapObject(ret);
444
+ }, arguments) };
445
+ imports.wbg.__wbg_done_5c1f01fb660d73b5 = function(arg0) {
446
+ const ret = getObject(arg0).done;
447
+ return ret;
448
+ };
449
+ imports.wbg.__wbg_value_1695675138684bd5 = function(arg0) {
450
+ const ret = getObject(arg0).value;
451
+ return addHeapObject(ret);
452
+ };
453
+ imports.wbg.__wbg_iterator_97f0c81209c6c35a = function() {
454
+ const ret = Symbol.iterator;
455
+ return addHeapObject(ret);
456
+ };
457
+ imports.wbg.__wbg_get_97b561fb56f034b5 = function() { return handleError(function (arg0, arg1) {
458
+ const ret = Reflect.get(getObject(arg0), getObject(arg1));
459
+ return addHeapObject(ret);
460
+ }, arguments) };
461
+ imports.wbg.__wbg_call_cb65541d95d71282 = function() { return handleError(function (arg0, arg1) {
462
+ const ret = getObject(arg0).call(getObject(arg1));
463
+ return addHeapObject(ret);
464
+ }, arguments) };
465
+ imports.wbg.__wbg_new_b51585de1b234aff = function() {
466
+ const ret = new Object();
467
+ return addHeapObject(ret);
468
+ };
469
+ imports.wbg.__wbg_set_502d29070ea18557 = function(arg0, arg1, arg2) {
470
+ getObject(arg0)[arg1 >>> 0] = takeObject(arg2);
471
+ };
472
+ imports.wbg.__wbg_isArray_4c24b343cb13cfb1 = function(arg0) {
473
+ const ret = Array.isArray(getObject(arg0));
474
+ return ret;
475
+ };
476
+ imports.wbg.__wbg_instanceof_ArrayBuffer_39ac22089b74fddb = function(arg0) {
477
+ let result;
478
+ try {
479
+ result = getObject(arg0) instanceof ArrayBuffer;
480
+ } catch {
481
+ result = false;
482
+ }
483
+ const ret = result;
484
+ return ret;
485
+ };
486
+ imports.wbg.__wbg_buffer_085ec1f694018c4f = function(arg0) {
487
+ const ret = getObject(arg0).buffer;
488
+ return addHeapObject(ret);
489
+ };
490
+ imports.wbg.__wbg_new_8125e318e6245eed = function(arg0) {
491
+ const ret = new Uint8Array(getObject(arg0));
492
+ return addHeapObject(ret);
493
+ };
494
+ imports.wbg.__wbg_set_5cf90238115182c3 = function(arg0, arg1, arg2) {
495
+ getObject(arg0).set(getObject(arg1), arg2 >>> 0);
496
+ };
497
+ imports.wbg.__wbg_length_72e2208bbc0efc61 = function(arg0) {
498
+ const ret = getObject(arg0).length;
499
+ return ret;
500
+ };
501
+ imports.wbg.__wbg_instanceof_Uint8Array_d8d9cb2b8e8ac1d4 = function(arg0) {
502
+ let result;
503
+ try {
504
+ result = getObject(arg0) instanceof Uint8Array;
505
+ } catch {
506
+ result = false;
507
+ }
508
+ const ret = result;
509
+ return ret;
510
+ };
511
+ imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
512
+ const ret = debugString(getObject(arg1));
513
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
514
+ const len1 = WASM_VECTOR_LEN;
515
+ getInt32Memory0()[arg0 / 4 + 1] = len1;
516
+ getInt32Memory0()[arg0 / 4 + 0] = ptr1;
517
+ };
518
+ imports.wbg.__wbindgen_throw = function(arg0, arg1) {
519
+ throw new Error(getStringFromWasm0(arg0, arg1));
520
+ };
521
+ imports.wbg.__wbindgen_memory = function() {
522
+ const ret = wasm.memory;
523
+ return addHeapObject(ret);
524
+ };
525
+
526
+ return imports;
527
+ }
528
+
529
+ function __wbg_init_memory(imports, maybe_memory) {
530
+
531
+ }
532
+
533
+ function __wbg_finalize_init(instance, module) {
534
+ wasm = instance.exports;
535
+ __wbg_init.__wbindgen_wasm_module = module;
536
+ cachedFloat64Memory0 = null;
537
+ cachedInt32Memory0 = null;
538
+ cachedUint8Memory0 = null;
539
+
540
+ wasm.__wbindgen_start();
541
+ return wasm;
542
+ }
543
+
544
+ function initSync(module) {
545
+ if (wasm !== undefined) return wasm;
546
+
547
+ const imports = __wbg_get_imports();
548
+
549
+ __wbg_init_memory(imports);
550
+
551
+ if (!(module instanceof WebAssembly.Module)) {
552
+ module = new WebAssembly.Module(module);
553
+ }
554
+
555
+ const instance = new WebAssembly.Instance(module, imports);
556
+
557
+ return __wbg_finalize_init(instance, module);
558
+ }
559
+
560
+ async function __wbg_init(input) {
561
+ if (wasm !== undefined) return wasm;
562
+
563
+ if (typeof input === 'undefined') {
564
+ input = new URL('m_bg.wasm', import.meta.url);
565
+ }
566
+ const imports = __wbg_get_imports();
567
+
568
+ if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
569
+ input = fetch(input);
570
+ }
571
+
572
+ __wbg_init_memory(imports);
573
+
574
+ const { instance, module } = await __wbg_load(await input, imports);
575
+
576
+ return __wbg_finalize_init(instance, module);
577
+ }
578
+
579
+ export { initSync }
580
+ export default __wbg_init;
sam/m_bg.wasm ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e1b97ef5bb8d7dda5f0d1475e02b666119e883fec44bfaaac25c2e985c7d0af0
3
+ size 2667539
sam/m_bg.wasm.d.ts ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ export const memory: WebAssembly.Memory;
4
+ export function __wbg_model_free(a: number): void;
5
+ export function model_new(a: number, b: number, c: number, d: number): void;
6
+ export function model_set_image_embeddings(a: number, b: number, c: number, d: number): void;
7
+ export function model_mask_for_point(a: number, b: number, c: number): void;
8
+ export function main(a: number, b: number): number;
9
+ export function __wbindgen_malloc(a: number, b: number): number;
10
+ export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number;
11
+ export function __wbindgen_add_to_stack_pointer(a: number): number;
12
+ export function __wbindgen_free(a: number, b: number, c: number): void;
13
+ export function __wbindgen_exn_store(a: number): void;
14
+ export function __wbindgen_start(): void;
samWorker.js ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //load the candle SAM Model wasm module
2
+ import init, { Model } from "./sam/m.js";
3
+
4
+ async function fetchArrayBuffer(url, cacheModel = true) {
5
+ if (!cacheModel)
6
+ return new Uint8Array(await (await fetch(url)).arrayBuffer());
7
+ const cacheName = "sam-candle-cache";
8
+ const cache = await caches.open(cacheName);
9
+ const cachedResponse = await cache.match(url);
10
+ if (cachedResponse) {
11
+ const data = await cachedResponse.arrayBuffer();
12
+ return new Uint8Array(data);
13
+ }
14
+ const res = await fetch(url, { cache: "force-cache" });
15
+ cache.put(url, res.clone());
16
+ return new Uint8Array(await res.arrayBuffer());
17
+ }
18
+ class SAMModel {
19
+ static instance = {};
20
+ // keep current image embeddings state
21
+ static imageArrayHash = {};
22
+ // Add a new property to hold the current modelID
23
+ static currentModelID = null;
24
+
25
+ static async getInstance(modelURL, modelID) {
26
+ if (!this.instance[modelID]) {
27
+ await init();
28
+
29
+ self.postMessage({
30
+ status: "loading",
31
+ message: `Loading Model ${modelID}`,
32
+ });
33
+ const weightsArrayU8 = await fetchArrayBuffer(modelURL);
34
+ this.instance[modelID] = new Model(
35
+ weightsArrayU8,
36
+ /tiny|mobile/.test(modelID)
37
+ );
38
+ } else {
39
+ self.postMessage({ status: "loading", message: "Model Already Loaded" });
40
+ }
41
+ // Set the current modelID to the modelID that was passed in
42
+ this.currentModelID = modelID;
43
+ return this.instance[modelID];
44
+ }
45
+
46
+ // Remove the modelID parameter from setImageEmbeddings
47
+ static setImageEmbeddings(imageArrayU8) {
48
+ // check if image embeddings are already set for this image and model
49
+ const imageArrayHash = this.getSimpleHash(imageArrayU8);
50
+ if (
51
+ this.imageArrayHash[this.currentModelID] === imageArrayHash &&
52
+ this.instance[this.currentModelID]
53
+ ) {
54
+ self.postMessage({
55
+ status: "embedding",
56
+ message: "Embeddings Already Set",
57
+ });
58
+ return;
59
+ }
60
+ this.imageArrayHash[this.currentModelID] = imageArrayHash;
61
+ this.instance[this.currentModelID].set_image_embeddings(imageArrayU8);
62
+ self.postMessage({ status: "embedding", message: "Embeddings Set" });
63
+ }
64
+
65
+ static getSimpleHash(imageArrayU8) {
66
+ // get simple hash of imageArrayU8
67
+ let imageArrayHash = 0;
68
+ for (let i = 0; i < imageArrayU8.length; i += 100) {
69
+ imageArrayHash ^= imageArrayU8[i];
70
+ }
71
+ return imageArrayHash.toString(16);
72
+ }
73
+ }
74
+
75
+ async function createImageCanvas(
76
+ { mask_shape, mask_data }, // mask
77
+ { original_width, original_height, width, height }, // original image
78
+ imageURL
79
+ ) {
80
+ const [_, __, shape_width, shape_height] = mask_shape;
81
+ const maskCanvas = new OffscreenCanvas(shape_width, shape_height); // canvas for mask
82
+ const maskCtx = maskCanvas.getContext("2d");
83
+ const canvas = new OffscreenCanvas(original_width, original_height); // canvas for creating mask with original image size
84
+ const ctx = canvas.getContext("2d");
85
+
86
+ const imageData = maskCtx.createImageData(
87
+ maskCanvas.width,
88
+ maskCanvas.height
89
+ );
90
+ const data = imageData.data;
91
+
92
+ for (let p = 0; p < data.length; p += 4) {
93
+ data[p] = 0;
94
+ data[p + 1] = 0;
95
+ data[p + 2] = 0;
96
+ data[p + 3] = mask_data[p / 4] * 255;
97
+ }
98
+ maskCtx.putImageData(imageData, 0, 0);
99
+
100
+ let sx, sy;
101
+ if (original_height < original_width) {
102
+ sy = original_height / original_width;
103
+ sx = 1;
104
+ } else {
105
+ sy = 1;
106
+ sx = original_width / original_height;
107
+ }
108
+ ctx.drawImage(
109
+ maskCanvas,
110
+ 0,
111
+ 0,
112
+ maskCanvas.width * sx,
113
+ maskCanvas.height * sy,
114
+ 0,
115
+ 0,
116
+ original_width,
117
+ original_height
118
+ );
119
+
120
+ const canvasCut = new OffscreenCanvas(width, height); // canvas for cut image
121
+ const canvasCutctx = canvasCut.getContext("2d");
122
+ // draw imageURL on canvasCut
123
+ const originalImage = await createImageBitmap(await fetch(imageURL).then((r) => r.blob()));
124
+ canvasCut.width = originalImage.width;
125
+ canvasCut.height = originalImage.height;
126
+ canvasCutctx.drawImage(canvas, 0, 0);
127
+ canvasCutctx.globalCompositeOperation = "source-in";
128
+ canvasCutctx.drawImage(originalImage, 0, 0);
129
+
130
+
131
+ const blob = await canvasCut.convertToBlob();
132
+ return URL.createObjectURL(blob);
133
+ }
134
+
135
+ self.addEventListener("message", async (event) => {
136
+ const { modelURL, modelID, imageURL, points } = event.data;
137
+ try {
138
+ self.postMessage({ status: "loading", message: "Starting SAM" });
139
+ const sam = await SAMModel.getInstance(modelURL, modelID);
140
+
141
+ self.postMessage({ status: "loading", message: "Loading Image" });
142
+ const imageArrayU8 = await fetchArrayBuffer(imageURL, false);
143
+
144
+ self.postMessage({ status: "embedding", message: "Creating Embeddings" });
145
+ SAMModel.setImageEmbeddings(imageArrayU8);
146
+ if (!points) {
147
+ // no points only do the embeddings
148
+ self.postMessage({
149
+ status: "complete-embedding",
150
+ message: "Embeddings Complete",
151
+ });
152
+ return;
153
+ }
154
+
155
+ self.postMessage({ status: "segmenting", message: "Segmenting" });
156
+ const { mask, image } = sam.mask_for_point({ points });
157
+ const maskDataURL = await createImageCanvas(mask, image, imageURL);
158
+ // Send the segment back to the main thread as JSON
159
+ self.postMessage({
160
+ status: "complete",
161
+ message: "Segmentation Complete",
162
+ output: { maskURL: maskDataURL },
163
+ });
164
+ } catch (e) {
165
+ self.postMessage({ error: e });
166
+ }
167
+ });