|
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}`); |
|
} |
|
} |
|
|