| import { env, SamModel, AutoProcessor, RawImage, Tensor } from 'https://cdn.jsdelivr.net/npm/@xenova/transformers@2.14.0'; |
|
|
| |
| env.allowLocalModels = false; |
|
|
| |
| export class SegmentAnythingSingleton { |
| static model_id = 'Xenova/slimsam-77-uniform'; |
| static model; |
| static processor; |
| static quantized = true; |
|
|
| static getInstance() { |
| if (!this.model) { |
| this.model = SamModel.from_pretrained(this.model_id, { |
| quantized: this.quantized, |
| }); |
| } |
| if (!this.processor) { |
| this.processor = AutoProcessor.from_pretrained(this.model_id); |
| } |
|
|
| return Promise.all([this.model, this.processor]); |
| } |
| } |
|
|
|
|
| |
| let image_embeddings = null; |
| let image_inputs = null; |
| let ready = false; |
|
|
| self.onmessage = async (e) => { |
| const [model, processor] = await SegmentAnythingSingleton.getInstance(); |
| if (!ready) { |
| |
| ready = true; |
| self.postMessage({ |
| type: 'ready', |
| }); |
| } |
|
|
| const { type, data } = e.data; |
| if (type === 'reset') { |
| image_inputs = null; |
| image_embeddings = null; |
|
|
| } else if (type === 'segment') { |
| |
| self.postMessage({ |
| type: 'segment_result', |
| data: 'start', |
| }); |
|
|
| |
| const image = await RawImage.read(e.data.data); |
| image_inputs = await processor(image); |
| image_embeddings = await model.get_image_embeddings(image_inputs) |
|
|
| |
| self.postMessage({ |
| type: 'segment_result', |
| data: 'done', |
| }); |
|
|
| } else if (type === 'decode') { |
| |
| const reshaped = image_inputs.reshaped_input_sizes[0]; |
| const points = data.map(x => [x.point[0] * reshaped[1], x.point[1] * reshaped[0]]) |
| const labels = data.map(x => BigInt(x.label)); |
|
|
| const input_points = new Tensor( |
| 'float32', |
| points.flat(Infinity), |
| [1, 1, points.length, 2], |
| ) |
| const input_labels = new Tensor( |
| 'int64', |
| labels.flat(Infinity), |
| [1, 1, labels.length], |
| ) |
|
|
| |
| const outputs = await model({ |
| ...image_embeddings, |
| input_points, |
| input_labels, |
| }) |
|
|
| |
| const masks = await processor.post_process_masks( |
| outputs.pred_masks, |
| image_inputs.original_sizes, |
| image_inputs.reshaped_input_sizes, |
| ); |
|
|
| |
| self.postMessage({ |
| type: 'decode_result', |
| data: { |
| mask: RawImage.fromTensor(masks[0][0]), |
| scores: outputs.iou_scores.data, |
| }, |
| }); |
|
|
| } else { |
| throw new Error(`Unknown message type: ${type}`); |
| } |
| } |
|
|