@eyepop.ai/eyepop-render-2d 3.18.0 → 3.19.0

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/README.md CHANGED
@@ -219,6 +219,20 @@ Render2d.renderContour({
219
219
  })
220
220
  ```
221
221
 
222
+ #### Render Depth Maps
223
+
224
+ Renders the frame-level depth map produced by depth estimation abilities (e.g. `eyepop.depth.*`)
225
+ as a turbo-colormap heatmap blended over the frame: near = warm (red/yellow), far = cool (blue).
226
+ Sky pixels (+Infinity) leave the frame untouched unless `renderSky` is set.
227
+
228
+ ```typescript
229
+ Render2d.renderDepth({
230
+ target: '$',
231
+ opacity: 0.5, // overlay opacity over the underlying frame
232
+ renderSky: false, // also paint sky pixels
233
+ })
234
+ ```
235
+
222
236
  #### Blur an Object
223
237
 
224
238
  ```typescript
@@ -220,6 +220,29 @@ declare class RenderClasses implements Render {
220
220
  drawLabel(label: string, context: CanvasRenderingContext2D, xOffset: number, yOffset: number, style: Style, drawDisabled: boolean, xPadding: number, yPadding: number, labelWidth: number, labelHeight: number, borderRadius: number): void;
221
221
  }
222
222
 
223
+ type RenderDepthOptions = {
224
+ opacity?: number;
225
+ renderSky?: boolean;
226
+ } & RenderTarget;
227
+ /**
228
+ * Renders a frame-level depth map (Prediction.depth) as a turbo-colormap
229
+ * heatmap blended over the frame: near = warm (red/yellow), far = cool (blue).
230
+ * Sky pixels (+Infinity) leave the frame untouched unless renderSky is set.
231
+ *
232
+ * Uses getImageData/putImageData only, so it works with node-canvas as well
233
+ * as browser and react-native canvases.
234
+ */
235
+ declare class RenderDepth implements Render {
236
+ target: string;
237
+ private context;
238
+ private style;
239
+ private readonly opacity;
240
+ private readonly renderSky;
241
+ constructor(options?: Partial<RenderDepthOptions>);
242
+ start(context: CanvasRenderingContext2D, style: Style): void;
243
+ draw(element: Prediction, xOffset: number, yOffset: number, xScale: number, yScale: number, streamTime: StreamTime, color?: string): void;
244
+ }
245
+
223
246
  type Renderer2dOptions = {
224
247
  context: CanvasRenderingContext2D;
225
248
  rules?: Render[] | Render | undefined;
@@ -244,6 +267,7 @@ declare namespace Render2d {
244
267
  function renderClasses(options?: Partial<RenderClassesOptions>): Render;
245
268
  function renderMask(options?: Partial<RenderMaskOptions>): Render;
246
269
  function renderContour(options?: Partial<RenderContourOptions>): Render;
270
+ function renderDepth(options?: Partial<RenderDepthOptions>): Render;
247
271
  function renderFace(options?: Partial<RenderFaceOptions>): Render;
248
272
  function renderKeypoints(options?: Partial<RenderKeyPointsOptions>): Render;
249
273
  function renderHand(options?: Partial<RenderHandOptions>): Render;
@@ -252,4 +276,4 @@ declare namespace Render2d {
252
276
  function renderTrail(options?: Partial<RenderTrailOptions>): Render;
253
277
  }
254
278
 
255
- export { BoxType, type ClassificationProperties, DEFAULT_TARGET, type Render, Render2d, RenderBlur, type RenderBlurOptions, RenderBox, type RenderBoxOptions, RenderClasses, type RenderClassesOptions, RenderContour, type RenderContourOptions, RenderFace, type RenderFaceOptions, RenderHand, type RenderHandOptions, RenderKeyPoints, type RenderKeyPointsOptions, RenderMask, type RenderMaskOptions, RenderPose, type RenderPoseOptions, type RenderTarget, RenderText, type RenderTextOptions, RenderTrail, type RenderTrailOptions, type Renderer, Renderer2d, type Renderer2dOptions, Render2d as default };
279
+ export { BoxType, type ClassificationProperties, DEFAULT_TARGET, type Render, Render2d, RenderBlur, type RenderBlurOptions, RenderBox, type RenderBoxOptions, RenderClasses, type RenderClassesOptions, RenderContour, type RenderContourOptions, RenderDepth, type RenderDepthOptions, RenderFace, type RenderFaceOptions, RenderHand, type RenderHandOptions, RenderKeyPoints, type RenderKeyPointsOptions, RenderMask, type RenderMaskOptions, RenderPose, type RenderPoseOptions, type RenderTarget, RenderText, type RenderTextOptions, RenderTrail, type RenderTrailOptions, type Renderer, Renderer2d, type Renderer2dOptions, Render2d as default };
@@ -220,6 +220,29 @@ declare class RenderClasses implements Render {
220
220
  drawLabel(label: string, context: CanvasRenderingContext2D, xOffset: number, yOffset: number, style: Style, drawDisabled: boolean, xPadding: number, yPadding: number, labelWidth: number, labelHeight: number, borderRadius: number): void;
221
221
  }
222
222
 
223
+ type RenderDepthOptions = {
224
+ opacity?: number;
225
+ renderSky?: boolean;
226
+ } & RenderTarget;
227
+ /**
228
+ * Renders a frame-level depth map (Prediction.depth) as a turbo-colormap
229
+ * heatmap blended over the frame: near = warm (red/yellow), far = cool (blue).
230
+ * Sky pixels (+Infinity) leave the frame untouched unless renderSky is set.
231
+ *
232
+ * Uses getImageData/putImageData only, so it works with node-canvas as well
233
+ * as browser and react-native canvases.
234
+ */
235
+ declare class RenderDepth implements Render {
236
+ target: string;
237
+ private context;
238
+ private style;
239
+ private readonly opacity;
240
+ private readonly renderSky;
241
+ constructor(options?: Partial<RenderDepthOptions>);
242
+ start(context: CanvasRenderingContext2D, style: Style): void;
243
+ draw(element: Prediction, xOffset: number, yOffset: number, xScale: number, yScale: number, streamTime: StreamTime, color?: string): void;
244
+ }
245
+
223
246
  type Renderer2dOptions = {
224
247
  context: CanvasRenderingContext2D;
225
248
  rules?: Render[] | Render | undefined;
@@ -244,6 +267,7 @@ declare namespace Render2d {
244
267
  function renderClasses(options?: Partial<RenderClassesOptions>): Render;
245
268
  function renderMask(options?: Partial<RenderMaskOptions>): Render;
246
269
  function renderContour(options?: Partial<RenderContourOptions>): Render;
270
+ function renderDepth(options?: Partial<RenderDepthOptions>): Render;
247
271
  function renderFace(options?: Partial<RenderFaceOptions>): Render;
248
272
  function renderKeypoints(options?: Partial<RenderKeyPointsOptions>): Render;
249
273
  function renderHand(options?: Partial<RenderHandOptions>): Render;
@@ -252,4 +276,4 @@ declare namespace Render2d {
252
276
  function renderTrail(options?: Partial<RenderTrailOptions>): Render;
253
277
  }
254
278
 
255
- export { BoxType, type ClassificationProperties, DEFAULT_TARGET, type Render, Render2d, RenderBlur, type RenderBlurOptions, RenderBox, type RenderBoxOptions, RenderClasses, type RenderClassesOptions, RenderContour, type RenderContourOptions, RenderFace, type RenderFaceOptions, RenderHand, type RenderHandOptions, RenderKeyPoints, type RenderKeyPointsOptions, RenderMask, type RenderMaskOptions, RenderPose, type RenderPoseOptions, type RenderTarget, RenderText, type RenderTextOptions, RenderTrail, type RenderTrailOptions, type Renderer, Renderer2d, type Renderer2dOptions, Render2d as default };
279
+ export { BoxType, type ClassificationProperties, DEFAULT_TARGET, type Render, Render2d, RenderBlur, type RenderBlurOptions, RenderBox, type RenderBoxOptions, RenderClasses, type RenderClassesOptions, RenderContour, type RenderContourOptions, RenderDepth, type RenderDepthOptions, RenderFace, type RenderFaceOptions, RenderHand, type RenderHandOptions, RenderKeyPoints, type RenderKeyPointsOptions, RenderMask, type RenderMaskOptions, RenderPose, type RenderPoseOptions, type RenderTarget, RenderText, type RenderTextOptions, RenderTrail, type RenderTrailOptions, type Renderer, Renderer2d, type Renderer2dOptions, Render2d as default };
@@ -37,6 +37,7 @@ __export(index_exports, {
37
37
  RenderBox: () => RenderBox,
38
38
  RenderClasses: () => RenderClasses,
39
39
  RenderContour: () => RenderContour,
40
+ RenderDepth: () => RenderDepth,
40
41
  RenderFace: () => RenderFace,
41
42
  RenderHand: () => RenderHand,
42
43
  RenderKeyPoints: () => RenderKeyPoints,
@@ -4201,6 +4202,121 @@ var RenderClasses = class {
4201
4202
  }
4202
4203
  };
4203
4204
 
4205
+ // render-depth.ts
4206
+ var TURBO_ANCHORS = [
4207
+ [48, 18, 59],
4208
+ [62, 86, 196],
4209
+ [33, 145, 237],
4210
+ [26, 192, 181],
4211
+ [94, 223, 105],
4212
+ [181, 229, 54],
4213
+ [243, 192, 52],
4214
+ [246, 117, 26],
4215
+ [122, 4, 3]
4216
+ ];
4217
+ var SKY_COLOR = [48, 18, 59];
4218
+ var isLittleEndianPlatform = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
4219
+ function decodeDepthValues(base64, width, height) {
4220
+ if (!Number.isSafeInteger(width) || width <= 0 || !Number.isSafeInteger(height) || height <= 0 || !Number.isSafeInteger(width * height * 4)) {
4221
+ throw new Error(`invalid depth dimensions: ${width}x${height}`);
4222
+ }
4223
+ const count = width * height;
4224
+ const buffer = Buffer.from(base64, "base64");
4225
+ if (buffer.byteLength !== count * 4) {
4226
+ throw new Error(`depth values hold ${buffer.byteLength} bytes, expected ${count * 4} float32 bytes`);
4227
+ }
4228
+ if (isLittleEndianPlatform) {
4229
+ const aligned = new Uint8Array(buffer);
4230
+ return new Float32Array(aligned.buffer, 0, count);
4231
+ }
4232
+ const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
4233
+ const values = new Float32Array(count);
4234
+ for (let i = 0; i < count; i++) {
4235
+ values[i] = view.getFloat32(i * 4, true);
4236
+ }
4237
+ return values;
4238
+ }
4239
+ function turboColor(position) {
4240
+ const scaled = Math.min(Math.max(position, 0), 1) * (TURBO_ANCHORS.length - 1);
4241
+ const lower = Math.floor(scaled);
4242
+ const upper = Math.min(lower + 1, TURBO_ANCHORS.length - 1);
4243
+ const fraction = scaled - lower;
4244
+ return [
4245
+ TURBO_ANCHORS[lower][0] * (1 - fraction) + TURBO_ANCHORS[upper][0] * fraction,
4246
+ TURBO_ANCHORS[lower][1] * (1 - fraction) + TURBO_ANCHORS[upper][1] * fraction,
4247
+ TURBO_ANCHORS[lower][2] * (1 - fraction) + TURBO_ANCHORS[upper][2] * fraction
4248
+ ];
4249
+ }
4250
+ var RenderDepth = class {
4251
+ constructor(options = {}) {
4252
+ this.target = "$";
4253
+ const { target = "$", opacity = 0.5, renderSky = false } = options;
4254
+ this.target = target;
4255
+ this.opacity = Math.min(Math.max(opacity, 0), 1);
4256
+ this.renderSky = renderSky;
4257
+ }
4258
+ start(context, style) {
4259
+ this.context = context;
4260
+ this.style = style;
4261
+ }
4262
+ draw(element, xOffset, yOffset, xScale, yScale, streamTime, color) {
4263
+ const context = this.context;
4264
+ if (!context || !this.style) {
4265
+ throw new Error("render() called before start()");
4266
+ }
4267
+ if (!element.depth) {
4268
+ return;
4269
+ }
4270
+ const depthWidth = element.depth.width;
4271
+ const depthHeight = element.depth.height;
4272
+ const values = decodeDepthValues(element.depth.values, depthWidth, depthHeight);
4273
+ const destWidth = Math.round(element.source_width * xScale);
4274
+ const destHeight = Math.round(element.source_height * yScale);
4275
+ if (destWidth <= 0 || destHeight <= 0) {
4276
+ return;
4277
+ }
4278
+ let finiteMin = Number.POSITIVE_INFINITY;
4279
+ let finiteMax = Number.NEGATIVE_INFINITY;
4280
+ for (let i = 0; i < values.length; i++) {
4281
+ const value = values[i];
4282
+ if (Number.isFinite(value)) {
4283
+ if (value < finiteMin) finiteMin = value;
4284
+ if (value > finiteMax) finiteMax = value;
4285
+ }
4286
+ }
4287
+ const span = finiteMax > finiteMin ? finiteMax - finiteMin : 1;
4288
+ const dest = context.getImageData(xOffset, yOffset, destWidth, destHeight);
4289
+ const pixels = dest.data;
4290
+ for (let y = 0; y < destHeight; y++) {
4291
+ const mapY = Math.min(Math.floor(y * depthHeight / destHeight), depthHeight - 1);
4292
+ const mapRow = mapY * depthWidth;
4293
+ for (let x = 0; x < destWidth; x++) {
4294
+ const mapX = Math.min(Math.floor(x * depthWidth / destWidth), depthWidth - 1);
4295
+ const value = values[mapRow + mapX];
4296
+ let heat;
4297
+ if (Number.isFinite(value)) {
4298
+ const normalized = Number.isFinite(finiteMin) ? (value - finiteMin) / span : 0;
4299
+ heat = turboColor(1 - normalized);
4300
+ } else if (this.renderSky) {
4301
+ heat = SKY_COLOR;
4302
+ } else {
4303
+ continue;
4304
+ }
4305
+ const index = (y * destWidth + x) * 4;
4306
+ const destinationAlpha = pixels[index + 3] / 255 * (1 - this.opacity);
4307
+ const outAlpha = this.opacity + destinationAlpha;
4308
+ if (outAlpha > 0) {
4309
+ pixels[index] = Math.round((heat[0] * this.opacity + pixels[index] * destinationAlpha) / outAlpha);
4310
+ pixels[index + 1] = Math.round((heat[1] * this.opacity + pixels[index + 1] * destinationAlpha) / outAlpha);
4311
+ pixels[index + 2] = Math.round((heat[2] * this.opacity + pixels[index + 2] * destinationAlpha) / outAlpha);
4312
+ }
4313
+ pixels[index + 3] = Math.round(outAlpha * 255);
4314
+ }
4315
+ }
4316
+ context.putImageData(dest, xOffset, yOffset);
4317
+ }
4318
+ };
4319
+
4204
4320
  // index.ts
4205
4321
  var Render2d;
4206
4322
  ((Render2d2) => {
@@ -4228,6 +4344,10 @@ var Render2d;
4228
4344
  return new RenderContour(options);
4229
4345
  }
4230
4346
  Render2d2.renderContour = renderContour;
4347
+ function renderDepth(options = {}) {
4348
+ return new RenderDepth(options);
4349
+ }
4350
+ Render2d2.renderDepth = renderDepth;
4231
4351
  function renderFace(options = {}) {
4232
4352
  return new RenderFace(options);
4233
4353
  }
@@ -4263,6 +4383,7 @@ var index_default = Render2d;
4263
4383
  RenderBox,
4264
4384
  RenderClasses,
4265
4385
  RenderContour,
4386
+ RenderDepth,
4266
4387
  RenderFace,
4267
4388
  RenderHand,
4268
4389
  RenderKeyPoints,