| 182 | * fed into `ImageData` and mapped to a canvas. |
| 183 | */ |
| 184 | export async function toSegmentationImage( |
| 185 | colormap: Color[], |
| 186 | labelNames: string[], |
| 187 | rawSegmentationMap: tf.Tensor2D, |
| 188 | canvas?: HTMLCanvasElement, |
| 189 | ): Promise<SegmentationData> { |
| 190 | if (colormap.length < labelNames.length) { |
| 191 | throw new Error( |
| 192 | 'The colormap must be expansive enough to encode each label. ' + |
| 193 | `Aborting, since the given colormap has length ${colormap.length}, ` + |
| 194 | `but there are ${labelNames.length} labels.`); |
| 195 | } |
| 196 | const [height, width] = rawSegmentationMap.shape; |
| 197 | const segmentationImageBuffer = tf.buffer([height, width, 3], 'int32'); |
| 198 | const mapData = await rawSegmentationMap.array(); |
| 199 | const labels = new Set<Label>(); |
| 200 | for (let columnIndex = 0; columnIndex < height; ++columnIndex) { |
| 201 | for (let rowIndex = 0; rowIndex < width; ++rowIndex) { |
| 202 | const label: Label = mapData[columnIndex][rowIndex]; |
| 203 | labels.add(label); |
| 204 | segmentationImageBuffer.set(colormap[label][0], columnIndex, rowIndex, 0); |
| 205 | segmentationImageBuffer.set(colormap[label][1], columnIndex, rowIndex, 1); |
| 206 | segmentationImageBuffer.set(colormap[label][2], columnIndex, rowIndex, 2); |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | const segmentationImageTensor = |
| 211 | segmentationImageBuffer.toTensor() as tf.Tensor3D; |
| 212 | |
| 213 | const segmentationMap = |
| 214 | await tf.browser.toPixels(segmentationImageTensor, canvas); |
| 215 | |
| 216 | tf.dispose(segmentationImageTensor); |
| 217 | |
| 218 | const legend: Legend = {}; |
| 219 | for (const label of Array.from(labels)) { |
| 220 | legend[labelNames[label]] = colormap[label]; |
| 221 | } |
| 222 | return {legend, segmentationMap}; |
| 223 | } |