@eyepop.ai/eyepop-render-2d 1.9.2 → 1.11.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
@@ -1,51 +1,61 @@
1
1
  # EyePop.ai Render 2d Node Module
2
- This EyePop.ai Node Module provides convenient 2d rendering functions for predictions returned by
2
+
3
+ This EyePop.ai Node Module provides convenient 2d rendering functions for predictions returned by
3
4
  to the EyePop.ai's inference API from applications written in the TypeScript or JavaScript language.
4
5
 
5
6
  The module requires the [EyePop Node SDK](https://www.npmjs.com/package/@eyepop.ai/eyepop)
7
+
6
8
  ## Installation
9
+
7
10
  ### Node
11
+
8
12
  ```shell
9
13
  npm install --save @eyepop.ai/eyepop @eyepop.ai/eyepop-render-2d
10
14
  ```
15
+
11
16
  ### Browser
17
+
12
18
  ```html
13
19
  <script src="https://cdn.jsdelivr.net/npm/@eyepop.ai/eyepop/dist/eyepop.min.js"></script>
14
20
  <script src="https://cdn.jsdelivr.net/npm/@eyepop.ai/eyepop-render-2d/dist/eyepop.render2d.min.js"></script>
15
21
  ```
22
+
16
23
  ## Usage example
24
+
17
25
  ### Node
26
+
18
27
  This EyePop Node Module provides 2d rendering for predictions using `canvas.CanvasRenderingContext2D`.
28
+
19
29
  ```typescript
20
- import { EyePop } from '@eyepop.ai/eyepop';
21
- import { Render2d } from '@eyepop.ai/eyepop-render-2d';
22
-
23
- import {createCanvas, loadImage} from "canvas";
24
- import {open} from 'openurl';
25
- import { mkdtempSync, writeFileSync } from 'node:fs';
26
- import { join } from 'node:path';
27
- import { tmpdir } from 'node:os';
28
-
29
- const example_image_path = 'examples/example.jpg';
30
-
31
- (async() => {
30
+ import { EyePop } from '@eyepop.ai/eyepop'
31
+ import { Render2d } from '@eyepop.ai/eyepop-render-2d'
32
+
33
+ import { createCanvas, loadImage } from 'canvas'
34
+ import { open } from 'openurl'
35
+ import { mkdtempSync, writeFileSync } from 'node:fs'
36
+ import { join } from 'node:path'
37
+ import { tmpdir } from 'node:os'
38
+
39
+ const example_image_path = 'examples/example.jpg'
40
+
41
+ ;(async () => {
32
42
  const image = await loadImage(example_image_path)
33
43
  const canvas = createCanvas(image.width, image.height)
34
- const context = canvas.getContext("2d")
44
+ const context = canvas.getContext('2d')
35
45
  const renderer = Render2d.renderer(context)
36
-
46
+
37
47
  context.drawImage(image, 0, 0)
38
48
 
39
49
  const endpoint = await EyePop.endpoint().connect()
40
50
  try {
41
- let results = await endpoint.process({path: example_image_path})
51
+ let results = await endpoint.process({ path: example_image_path })
42
52
  for await (let result of results) {
43
53
  renderer.draw(result)
44
- }
54
+ }
45
55
  } finally {
46
56
  await endpoint.disconnect()
47
57
  }
48
-
58
+
49
59
  const tmp_dir = mkdtempSync(join(tmpdir(), 'ep-demo-'))
50
60
  const temp_file = join(tmp_dir, 'out.png')
51
61
  console.log(`creating temp file: ${temp_file}`)
@@ -54,130 +64,159 @@ const example_image_path = 'examples/example.jpg';
54
64
  writeFileSync(temp_file, buffer)
55
65
 
56
66
  open(`file://${temp_file}`)
57
- })();
67
+ })()
58
68
  ```
69
+
59
70
  ### Browser
60
71
 
61
72
  ```html
62
- <!DOCTYPE html>
73
+ <!doctype html>
63
74
  <html lang="en">
64
- <head>
65
- <script src="https://cdn.jsdelivr.net/npm/@eyepop.ai/eyepop/dist/eyepop.min.js"></script>
66
- <script src="https://cdn.jsdelivr.net/npm/@eyepop.ai/eyepop-render-2d/dist/eyepop.render2d.min.js"></script>
67
- </head>
68
- <body>
69
- <!-- ... -->
70
- <input type="file" id="my-file-chooser">
71
- <!-- ... -->
72
- <canvas id="my-canvas"></canvas>
73
- <!-- ... -->
74
- <script>
75
- async
76
- uploadFile(event)
77
- {
78
- const fileChooser = document.getElementById('my-file-chooser');
79
- const context = document.getElementById('my-canvas').getContext("2d");
80
- const renderer = Render2d.renderer(context);
81
-
82
- const endpoint = await EyePop.workerEndpoint({auth: {oAuth2: true}, popId: '< Pop Id>'}).connect();
83
- endpoint.process({file: fileChooser.files[0]}).then(async (results) => {
84
- for await (let result of results) {
85
- renderer.draw(result);
75
+ <head>
76
+ <script src="https://cdn.jsdelivr.net/npm/@eyepop.ai/eyepop/dist/eyepop.min.js"></script>
77
+ <script src="https://cdn.jsdelivr.net/npm/@eyepop.ai/eyepop-render-2d/dist/eyepop.render2d.min.js"></script>
78
+ </head>
79
+ <body>
80
+ <!-- ... -->
81
+ <input
82
+ type="file"
83
+ id="my-file-chooser"
84
+ />
85
+ <!-- ... -->
86
+ <canvas id="my-canvas"></canvas>
87
+ <!-- ... -->
88
+ <script>
89
+ async
90
+ uploadFile(event)
91
+ {
92
+ const fileChooser = document.getElementById('my-file-chooser');
93
+ const context = document.getElementById('my-canvas').getContext("2d");
94
+ const renderer = Render2d.renderer(context);
95
+
96
+ const endpoint = await EyePop.workerEndpoint({auth: {oAuth2: true}, popId: '< Pop Id>'}).connect();
97
+ endpoint.process({file: fileChooser.files[0]}).then(async (results) => {
98
+ for await (let result of results) {
99
+ renderer.draw(result);
100
+ }
101
+ });
102
+ await endpoint.disconnect();
86
103
  }
87
- });
88
- await endpoint.disconnect();
89
- }
90
- )
91
- ;
92
- </script>
93
- </body>
104
+ )
105
+ ;
106
+ </script>
107
+ </body>
94
108
  </html>
95
-
96
109
  ```
110
+
97
111
  ### Rendering Rules
112
+
98
113
  By default, the 2d renderer renders boxes and class-labels for every top level object in the prediction.
99
114
  Change this rendering behaviour by passing in rendering rule(s), e.g.:
115
+
100
116
  ```javascript
101
117
  // ...
102
- Render2d.renderer(context,[Render2.renderFace()]).draw(result);
118
+ Render2d.renderer(context, [Render2.renderFace()]).draw(result)
103
119
  // ...
104
120
  ```
105
- Each rule has a `render` object and a `target` attribute. All prebuild render classes accept a JSONPath expression as `target` parameter to select which elements should be rendered from predictions.
121
+
122
+ Each rule has a `render` object and a `target` attribute. All prebuild render classes accept a JSONPath expression as `target` parameter to select which elements should be rendered from predictions.
106
123
  See [JSONPath expression](https://www.npmjs.com/package/jsonpath)
107
124
 
108
125
  Most prebuild render classes provide a reasonable defaults, as shown below.
126
+
109
127
  #### Rendering Bounding Boxes and Class Labels
110
128
 
111
129
  ```typescript
112
130
  Render2d.renderBox({
113
- showClass = true,
131
+ showClass = true,
114
132
  showConfidence = false,
115
133
  showTraceId = false,
116
134
  showNestedClasses = false,
117
- target = '$..objects.*'
135
+ target = '$..objects.*',
118
136
  })
119
- ```
137
+ ```
138
+
120
139
  #### Render Human Body Poses (2d or 3d)
140
+
121
141
  ```typescript
122
142
  Render2d.renderPose({
123
- target: '$..objects[?(@.category=="person")]'
143
+ target: '$..objects[?(@.category=="person")]',
124
144
  })
125
- ```
145
+ ```
146
+
126
147
  #### Render Human Hand Details
148
+
127
149
  ```typescript
128
150
  Render2d.renderHand({
129
- target: '$..objects[?(@.classLabel=="hand circumference")]'
151
+ target: '$..objects[?(@.classLabel=="hand circumference")]',
130
152
  })
131
153
  ```
154
+
132
155
  #### Render Human Faces
156
+
133
157
  ```typescript
134
158
  Render2d.renderFace({
135
159
  showLabels = false,
136
- target = '$..objects[?(@.classLabel=="face")]'
137
- })
160
+ target = '$..objects[?(@.classLabel=="face")]',
161
+ })
138
162
  ```
163
+
139
164
  #### Render Text (OCR Overlay)
165
+
140
166
  ```typescript
141
167
  Render2d.renderText({
142
- target: '$..objects[?(@.classLabel=="text")]'
168
+ target: '$..objects[?(@.classLabel=="text")]',
143
169
  })
144
170
  ```
171
+
145
172
  #### Render Segmentation Masks
173
+
146
174
  ```typescript
147
175
  Render2d.renderMask({
148
- target: '$..objects[?(@.mask)]'
149
- })
176
+ target: '$..objects[?(@.mask)]',
177
+ })
150
178
  ```
179
+
151
180
  #### Render Segmentation Contours
181
+
152
182
  ```typescript
153
183
  Render2d.renderContour({
154
- target: '$..objects[?(@.contours)]'
155
- })
184
+ target: '$..objects[?(@.contours)]',
185
+ })
156
186
  ```
187
+
157
188
  #### Blur an Object (TODO does black-put instead of blur)
189
+
158
190
  ```typescript
159
191
  Render2d.renderBlur({
160
- target: '$..objects[?(@.classLabel=="face")]'
192
+ target: '$..objects[?(@.classLabel=="face")]',
161
193
  })
162
194
  ```
195
+
163
196
  #### Render a Trail of a traced object over time
197
+
164
198
  ```typescript
165
199
  Render2d.renderTrail({
166
200
  target: '$..objects[?(@.traceId)]',
167
- trailLengthSeconds:1,
201
+ trailLengthSeconds: 1,
168
202
  })
169
203
  ```
170
- By default, this traces the mid-point of the object's bounding box. Instead, one can also draw trails of sub-objects or key points of the traced object. Use the optional parameter `traceDetails` for this purpose.
204
+
205
+ By default, this traces the mid-point of the object's bounding box. Instead, one can also draw trails of sub-objects or key points of the traced object. Use the optional parameter `traceDetails` for this purpose.
171
206
  E.g. trail the nose of every traced person:
207
+
172
208
  ```typescript
173
209
  Render2d.renderTrail({
174
210
  target: '$..objects[?(@.traceId)]',
175
- trailLengthSeconds:1,
176
- traceDetails:'$..keyPoints[?(@.category=="3d-body-points")].points[?(@.classLabel.includes("nose"))]'
211
+ trailLengthSeconds: 1,
212
+ traceDetails: '$..keyPoints[?(@.category=="3d-body-points")].points[?(@.classLabel.includes("nose"))]',
177
213
  })
178
214
  ```
215
+
179
216
  #### Custom render implementation
180
- To implement custom rendering rules, create a custom class as follows:
217
+
218
+ To implement custom rendering rules, create a custom class as follows:
219
+
181
220
  ```typescript
182
221
  import { PredictedObject, StreamTime } from '@eyepop.ai/eyepop'
183
222
 
@@ -187,57 +226,48 @@ export interface Render {
187
226
  draw(element: any, xOffset: number, yOffset: number, xScale: number, yScale: number, streamTime: StreamTime): void
188
227
  }
189
228
 
190
- export class RenderCustomImage implements Render
191
- {
192
- public target: string = "$..objects[?(@.category=='person')]"
193
-
194
- private context: CanvasRenderingContext2D | undefined
195
- private style: any
196
-
197
- // Optionally, add a constructor here. ie: constructor(...) { }
198
-
199
- // The start method sets the context and style properties.
200
- start(context: CanvasRenderingContext2D, style: any)
201
- {
202
- this.context = context
203
- this.style = style
204
- }
205
-
206
- // The draw method draws the image and line on the canvas based on the positions of the points in the PredictedObject.
207
- public draw(
208
- element: PredictedObject, // The object containing the keypoints
209
- xOffset: number, // The x offset for the drawing
210
- yOffset: number, // The y offset for the drawing
211
- xScale: number, // The x scale factor for the drawing
212
- yScale: number, // The y scale factor for the drawing
213
- streamTime: StreamTime // The timestamp for the stream of predicted objects
214
- ): void
215
- {
216
- // Check if the context and style properties have been set
217
- if (!this.context || !this.style)
218
- {
219
- throw new Error('render() called before start()')
229
+ export class RenderCustomImage implements Render {
230
+ public target: string = "$..objects[?(@.category=='person')]"
231
+
232
+ private context: CanvasRenderingContext2D | undefined
233
+ private style: any
234
+
235
+ // Optionally, add a constructor here. ie: constructor(...) { }
236
+
237
+ // The start method sets the context and style properties.
238
+ start(context: CanvasRenderingContext2D, style: any) {
239
+ this.context = context
240
+ this.style = style
220
241
  }
221
242
 
222
- // Check if the keypoints are defined
223
- if (!element.keyPoints) return
224
- if (!element.keyPoints.length) return
225
-
226
- // Find the points of interest in the keypoints
227
- for (let i = 0; i < element.keyPoints.length; i++)
228
- {
229
- const kp = element.keyPoints[ i ]
230
- for (let j = 0; j < kp.points.length; j++)
231
- {
232
- const point = kp.points[ j ]
233
- if (point.classLabel === 'left eye' || point.classLabel === 'right eye')
234
- {
235
- // Draw with the canvas context here
243
+ // The draw method draws the image and line on the canvas based on the positions of the points in the PredictedObject.
244
+ public draw(
245
+ element: PredictedObject, // The object containing the keypoints
246
+ xOffset: number, // The x offset for the drawing
247
+ yOffset: number, // The y offset for the drawing
248
+ xScale: number, // The x scale factor for the drawing
249
+ yScale: number, // The y scale factor for the drawing
250
+ streamTime: StreamTime, // The timestamp for the stream of predicted objects
251
+ ): void {
252
+ // Check if the context and style properties have been set
253
+ if (!this.context || !this.style) {
254
+ throw new Error('render() called before start()')
236
255
  }
237
- }
238
- }
239
- }
240
- }
241
256
 
257
+ // Check if the keypoints are defined
258
+ if (!element.keyPoints) return
259
+ if (!element.keyPoints.length) return
242
260
 
261
+ // Find the points of interest in the keypoints
262
+ for (let i = 0; i < element.keyPoints.length; i++) {
263
+ const kp = element.keyPoints[i]
264
+ for (let j = 0; j < kp.points.length; j++) {
265
+ const point = kp.points[j]
266
+ if (point.classLabel === 'left eye' || point.classLabel === 'right eye') {
267
+ // Draw with the canvas context here
268
+ }
269
+ }
270
+ }
271
+ }
272
+ }
243
273
  ```
@@ -50,6 +50,7 @@ declare enum BoxType {
50
50
  type RenderBoxOptions = {
51
51
  showClass?: boolean;
52
52
  showNestedClasses?: boolean;
53
+ showText?: boolean;
53
54
  showConfidence?: boolean;
54
55
  showTraceId?: boolean;
55
56
  boxType?: BoxType;
@@ -191,6 +192,28 @@ declare class RenderText implements Render {
191
192
  getFontSize(label: string, context: CanvasRenderingContext2D, style: Style, boundingBoxWidth: number, boundingBoxHeight: number, scaleToWidth?: boolean): number;
192
193
  }
193
194
 
195
+ type RenderClassesOptions = {
196
+ showConfidence?: boolean;
197
+ showDottedOutline?: boolean;
198
+ classProperties?: ClassificationProperties[];
199
+ } & RenderTarget;
200
+ type ClassificationProperties = {
201
+ color?: string;
202
+ disabled?: boolean;
203
+ disabledOpacity?: number;
204
+ };
205
+ declare class RenderClasses implements Render {
206
+ target: string;
207
+ private context;
208
+ private style;
209
+ private showConfidence;
210
+ private classProperties;
211
+ constructor(options?: Partial<RenderClassesOptions>);
212
+ start(context: CanvasRenderingContext2D, style: Style): void;
213
+ draw(element: PredictedObject, xOffset: number, yOffset: number, xScale: number, yScale: number, streamTime: StreamTime, color?: string): void;
214
+ drawLabel(label: string, context: CanvasRenderingContext2D, xOffset: number, yOffset: number, style: Style, drawDisabled: boolean, xPadding: number, yPadding: number, labelWidth: number, labelHeight: number, borderRadius: number): void;
215
+ }
216
+
194
217
  type Renderer2dOptions = {
195
218
  context: CanvasRenderingContext2D;
196
219
  rules?: Render[] | Render | undefined;
@@ -212,6 +235,7 @@ declare namespace Render2d {
212
235
  function renderer(context: CanvasRenderingContext2D, rules?: Render[] | undefined): Renderer;
213
236
  function renderBlur(options?: Partial<RenderBlurOptions>): Render;
214
237
  function renderBox(options?: Partial<RenderBoxOptions>): Render;
238
+ function renderClasses(options?: Partial<RenderClassesOptions>): Render;
215
239
  function renderMask(options?: Partial<RenderMaskOptions>): Render;
216
240
  function renderContour(options?: Partial<RenderContourOptions>): Render;
217
241
  function renderFace(options?: Partial<RenderFaceOptions>): Render;
@@ -222,4 +246,4 @@ declare namespace Render2d {
222
246
  function renderTrail(options?: Partial<RenderTrailOptions>): Render;
223
247
  }
224
248
 
225
- export { BoxType, DEFAULT_TARGET, type Render, Render2d, RenderBlur, type RenderBlurOptions, RenderBox, type RenderBoxOptions, 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 };
249
+ 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 };
@@ -50,6 +50,7 @@ declare enum BoxType {
50
50
  type RenderBoxOptions = {
51
51
  showClass?: boolean;
52
52
  showNestedClasses?: boolean;
53
+ showText?: boolean;
53
54
  showConfidence?: boolean;
54
55
  showTraceId?: boolean;
55
56
  boxType?: BoxType;
@@ -191,6 +192,28 @@ declare class RenderText implements Render {
191
192
  getFontSize(label: string, context: CanvasRenderingContext2D, style: Style, boundingBoxWidth: number, boundingBoxHeight: number, scaleToWidth?: boolean): number;
192
193
  }
193
194
 
195
+ type RenderClassesOptions = {
196
+ showConfidence?: boolean;
197
+ showDottedOutline?: boolean;
198
+ classProperties?: ClassificationProperties[];
199
+ } & RenderTarget;
200
+ type ClassificationProperties = {
201
+ color?: string;
202
+ disabled?: boolean;
203
+ disabledOpacity?: number;
204
+ };
205
+ declare class RenderClasses implements Render {
206
+ target: string;
207
+ private context;
208
+ private style;
209
+ private showConfidence;
210
+ private classProperties;
211
+ constructor(options?: Partial<RenderClassesOptions>);
212
+ start(context: CanvasRenderingContext2D, style: Style): void;
213
+ draw(element: PredictedObject, xOffset: number, yOffset: number, xScale: number, yScale: number, streamTime: StreamTime, color?: string): void;
214
+ drawLabel(label: string, context: CanvasRenderingContext2D, xOffset: number, yOffset: number, style: Style, drawDisabled: boolean, xPadding: number, yPadding: number, labelWidth: number, labelHeight: number, borderRadius: number): void;
215
+ }
216
+
194
217
  type Renderer2dOptions = {
195
218
  context: CanvasRenderingContext2D;
196
219
  rules?: Render[] | Render | undefined;
@@ -212,6 +235,7 @@ declare namespace Render2d {
212
235
  function renderer(context: CanvasRenderingContext2D, rules?: Render[] | undefined): Renderer;
213
236
  function renderBlur(options?: Partial<RenderBlurOptions>): Render;
214
237
  function renderBox(options?: Partial<RenderBoxOptions>): Render;
238
+ function renderClasses(options?: Partial<RenderClassesOptions>): Render;
215
239
  function renderMask(options?: Partial<RenderMaskOptions>): Render;
216
240
  function renderContour(options?: Partial<RenderContourOptions>): Render;
217
241
  function renderFace(options?: Partial<RenderFaceOptions>): Render;
@@ -222,4 +246,4 @@ declare namespace Render2d {
222
246
  function renderTrail(options?: Partial<RenderTrailOptions>): Render;
223
247
  }
224
248
 
225
- export { BoxType, DEFAULT_TARGET, type Render, Render2d, RenderBlur, type RenderBlurOptions, RenderBox, type RenderBoxOptions, 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 };
249
+ 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 };