edge-impulse-linux 1.16.2 → 1.17.2
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/build/cli/linux/linux.js +1 -0
- package/build/cli/linux/linux.js.map +1 -1
- package/build/cli/linux/runner-profiling.d.ts +10 -0
- package/build/cli/linux/runner-profiling.js +72 -0
- package/build/cli/linux/runner-profiling.js.map +1 -0
- package/build/cli/linux/runner-utils.d.ts +1 -0
- package/build/cli/linux/runner-utils.js +83 -79
- package/build/cli/linux/runner-utils.js.map +1 -1
- package/build/cli/linux/runner.js +57 -8
- package/build/cli/linux/runner.js.map +1 -1
- package/build/cli/linux/webserver/public/inference-server.js +92 -83
- package/build/cli/linux/webserver/public/inference-server.js.map +1 -1
- package/build/cli/linux/webserver/public/webserver.js +124 -17
- package/build/cli/linux/webserver/public/webserver.js.map +1 -1
- package/build/cli/linux/webserver/views/index.js +5 -3
- package/build/cli/linux/webserver/views/index.js.map +1 -1
- package/build/cli-common/model-monitor.d.ts +1 -2
- package/build/cli-common/model-monitor.js +5 -5
- package/build/cli-common/model-monitor.js.map +1 -1
- package/build/cli-common/remote-mgmt-service.d.ts +1 -1
- package/build/library/async-pool.d.ts +1 -0
- package/build/library/async-pool.js +21 -0
- package/build/library/async-pool.js.map +1 -0
- package/build/library/classifier/image-classifier.d.ts +16 -3
- package/build/library/classifier/image-classifier.js +38 -8
- package/build/library/classifier/image-classifier.js.map +1 -1
- package/build/library/classifier/libcwrapper.d.ts +26 -0
- package/build/library/classifier/libcwrapper.js +37 -0
- package/build/library/classifier/libcwrapper.js.map +1 -0
- package/build/library/classifier/linux-impulse-runner-types.d.ts +177 -0
- package/build/library/classifier/linux-impulse-runner-types.js +28 -0
- package/build/library/classifier/linux-impulse-runner-types.js.map +1 -0
- package/build/library/classifier/linux-impulse-runner.d.ts +15 -125
- package/build/library/classifier/linux-impulse-runner.js +154 -46
- package/build/library/classifier/linux-impulse-runner.js.map +1 -1
- package/build/library/classifier/valgrind-suppression.d.ts +1 -0
- package/build/library/classifier/valgrind-suppression.js +64 -0
- package/build/library/classifier/valgrind-suppression.js.map +1 -0
- package/build/library/moving-average-filter.d.ts +1 -1
- package/build/library/sensors/gstreamer.d.ts +12 -5
- package/build/library/sensors/gstreamer.js +217 -66
- package/build/library/sensors/gstreamer.js.map +1 -1
- package/build/library/sensors/icamera.d.ts +3 -1
- package/build/library/sensors/imagesnap.d.ts +2 -0
- package/build/library/sensors/imagesnap.js +2 -0
- package/build/library/sensors/imagesnap.js.map +1 -1
- package/build/library/sensors/prophesee.d.ts +2 -0
- package/build/library/sensors/prophesee.js +1 -0
- package/build/library/sensors/prophesee.js.map +1 -1
- package/build/library/sensors/sensors-helper.d.ts +1 -0
- package/build/library/sensors/sensors-helper.js +1 -1
- package/build/library/sensors/sensors-helper.js.map +1 -1
- package/build/sdk/studio/sdk/api/classifyApi.d.ts +64 -0
- package/build/sdk/studio/sdk/api/classifyApi.js +128 -0
- package/build/sdk/studio/sdk/api/classifyApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/rawDataApi.d.ts +55 -1
- package/build/sdk/studio/sdk/api/rawDataApi.js +166 -1
- package/build/sdk/studio/sdk/api/rawDataApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/testApi.d.ts +16 -0
- package/build/sdk/studio/sdk/api/testApi.js +90 -0
- package/build/sdk/studio/sdk/api/testApi.js.map +1 -1
- package/build/sdk/studio/sdk/model/batchEditBoundingBoxesRequest.d.ts +32 -0
- package/build/sdk/studio/sdk/model/batchEditBoundingBoxesRequest.js +34 -0
- package/build/sdk/studio/sdk/model/batchEditBoundingBoxesRequest.js.map +1 -0
- package/build/sdk/studio/sdk/model/models.d.ts +2 -0
- package/build/sdk/studio/sdk/model/models.js +6 -0
- package/build/sdk/studio/sdk/model/models.js.map +1 -1
- package/build/sdk/studio/sdk/model/permission.d.ts +1 -1
- package/build/sdk/studio/sdk/model/permission.js +1 -1
- package/build/sdk/studio/sdk/model/permission.js.map +1 -1
- package/build/sdk/studio/sdk/model/uploadVersionArchiveRequest.d.ts +34 -0
- package/build/sdk/studio/sdk/model/uploadVersionArchiveRequest.js +29 -0
- package/build/sdk/studio/sdk/model/uploadVersionArchiveRequest.js.map +1 -0
- package/build/shared/views/project/bounding-box-scaling.d.ts +66 -0
- package/build/shared/views/project/bounding-box-scaling.js +155 -0
- package/build/shared/views/project/bounding-box-scaling.js.map +1 -0
- package/cli/linux/webserver/public/assets/mobileclient.css +31 -3
- package/cli/linux/webserver/public/inference-server.js +100 -89
- package/cli/linux/webserver/public/webserver.js +136 -17
- package/examples/js/classify-camera.js +1 -3
- package/examples/ts/classify-camera.ts +1 -3
- package/package.json +2 -1
- package/test/gstreamer.test.ts +28 -23
- package/examples/ts/classify-custom-from-test.ts +0 -96
|
@@ -2,6 +2,7 @@ window.WebServer = async () => {
|
|
|
2
2
|
|
|
3
3
|
const els = {
|
|
4
4
|
title: document.querySelector('#header-row h1'),
|
|
5
|
+
cameraOuterContainer: document.querySelector('#capture-camera .capture-camera-outer'),
|
|
5
6
|
cameraContainer: document.querySelector('#capture-camera .capture-camera-inner'),
|
|
6
7
|
cameraImg: document.querySelector('#capture-camera img'),
|
|
7
8
|
timePerInference: document.querySelector('#time-per-inference'),
|
|
@@ -29,6 +30,9 @@ window.WebServer = async () => {
|
|
|
29
30
|
];
|
|
30
31
|
let colorIx = 0;
|
|
31
32
|
const labelToColor = { };
|
|
33
|
+
let isFirstClassification = true;
|
|
34
|
+
let inferenceIx = 0;
|
|
35
|
+
let lastClassification;
|
|
32
36
|
|
|
33
37
|
function switchView(el) {
|
|
34
38
|
for (let k of Object.keys(els.views)) {
|
|
@@ -150,6 +154,7 @@ window.WebServer = async () => {
|
|
|
150
154
|
inputEl.oninput = () => {
|
|
151
155
|
if (typeof threshold[k] === 'number') {
|
|
152
156
|
if (!inputEl.value || isNaN(Number(inputEl.value))) return;
|
|
157
|
+
if (k === 'min_score' && Number(inputEl.value) === 0) return;
|
|
153
158
|
|
|
154
159
|
threshold[k] = Number(inputEl.value);
|
|
155
160
|
}
|
|
@@ -194,14 +199,65 @@ window.WebServer = async () => {
|
|
|
194
199
|
bindThresholdSettings(opts.thresholds);
|
|
195
200
|
});
|
|
196
201
|
|
|
202
|
+
const onWindowResize = () => {
|
|
203
|
+
if (els.cameraContainer.naturalWidth === 0) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
let oldStyleWidth = els.cameraImg.style.width;
|
|
208
|
+
const containerWidth = els.cameraOuterContainer.getBoundingClientRect().width;
|
|
209
|
+
|
|
210
|
+
// height >480
|
|
211
|
+
if (els.cameraImg.naturalHeight > 480) {
|
|
212
|
+
// and fits within the container? just display as is
|
|
213
|
+
if (els.cameraImg.naturalWidth < containerWidth) {
|
|
214
|
+
els.cameraImg.style.width = els.cameraImg.naturalWidth + 'px';
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
// does not fit within container? just use 100%
|
|
218
|
+
els.cameraImg.style.width = containerWidth + 'px';
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
// what if we resize to 480 high?
|
|
223
|
+
const factor = els.cameraImg.naturalWidth / els.cameraImg.naturalHeight;
|
|
224
|
+
let newHeight = 480;
|
|
225
|
+
let newWidth = newHeight * factor;
|
|
226
|
+
|
|
227
|
+
// fits within the container? just display as is
|
|
228
|
+
if (newWidth < containerWidth) {
|
|
229
|
+
els.cameraImg.style.width = newWidth + 'px';
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
// does not fit within container? just use 100%
|
|
233
|
+
els.cameraImg.style.width = containerWidth + 'px';
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (oldStyleWidth !== els.cameraImg.style.width && lastClassification) {
|
|
238
|
+
onClassification({
|
|
239
|
+
dontUpdateTable: true,
|
|
240
|
+
...lastClassification,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
let isFirstImage = true;
|
|
197
246
|
socket.on('image', (opts) => {
|
|
247
|
+
if (isFirstImage) {
|
|
248
|
+
els.cameraImg.onload = () => {
|
|
249
|
+
onWindowResize();
|
|
250
|
+
els.cameraImg.onload = null;
|
|
251
|
+
};
|
|
252
|
+
isFirstImage = false;
|
|
253
|
+
}
|
|
198
254
|
els.cameraImg.src = opts.img;
|
|
199
255
|
});
|
|
256
|
+
window.addEventListener('resize', onWindowResize);
|
|
200
257
|
|
|
201
|
-
|
|
202
|
-
|
|
258
|
+
function onClassification(opts) {
|
|
259
|
+
lastClassification = opts;
|
|
203
260
|
|
|
204
|
-
socket.on('classification', (opts) => {
|
|
205
261
|
let result = opts.result;
|
|
206
262
|
let modelType = opts.modelType;
|
|
207
263
|
|
|
@@ -218,16 +274,39 @@ window.WebServer = async () => {
|
|
|
218
274
|
|
|
219
275
|
els.imageClassify.row.style.display = 'none';
|
|
220
276
|
|
|
221
|
-
if (result.classification) {
|
|
277
|
+
if (result.classification && !opts.dontUpdateTable) {
|
|
278
|
+
const showOnlyTopResults = Object.keys(result.classification).length > 10 && !result.visual_anomaly_grid;
|
|
279
|
+
|
|
222
280
|
if (isFirstClassification) {
|
|
223
|
-
|
|
224
|
-
|
|
281
|
+
if (showOnlyTopResults) {
|
|
282
|
+
// only 1 results th
|
|
283
|
+
{
|
|
284
|
+
let th = document.createElement('th');
|
|
285
|
+
th.scope = 'col';
|
|
286
|
+
th.textContent = th.title = 'Top 5 results';
|
|
287
|
+
th.classList.add('px-0', 'text-center');
|
|
288
|
+
els.resultsThead.appendChild(th);
|
|
289
|
+
}
|
|
225
290
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
291
|
+
// unless also have anomaly...
|
|
292
|
+
if (Object.keys(result.classification).indexOf('anomaly') > -1) {
|
|
293
|
+
let th = document.createElement('th');
|
|
294
|
+
th.scope = 'col';
|
|
295
|
+
th.textContent = th.title = 'anomaly';
|
|
296
|
+
th.classList.add('px-0', 'text-center');
|
|
297
|
+
els.resultsThead.appendChild(th);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
for (let ix = 0; ix < Object.keys(result.classification).length; ix++) {
|
|
302
|
+
const key = Object.keys(result.classification)[ix];
|
|
303
|
+
|
|
304
|
+
let th = document.createElement('th');
|
|
305
|
+
th.scope = 'col';
|
|
306
|
+
th.classList.add('px-0', 'text-center');
|
|
307
|
+
th.textContent = th.title = key;
|
|
308
|
+
els.resultsThead.appendChild(th);
|
|
309
|
+
}
|
|
231
310
|
}
|
|
232
311
|
|
|
233
312
|
if (result.visual_anomaly_grid) {
|
|
@@ -264,15 +343,53 @@ window.WebServer = async () => {
|
|
|
264
343
|
let td1 = document.createElement('td');
|
|
265
344
|
td1.textContent = (++inferenceIx).toString();
|
|
266
345
|
tr.appendChild(td1);
|
|
267
|
-
|
|
346
|
+
if (showOnlyTopResults) {
|
|
347
|
+
// only print top 5
|
|
268
348
|
let td = document.createElement('td');
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
349
|
+
|
|
350
|
+
let results = [];
|
|
351
|
+
for (const key of Object.keys(result.classification)) {
|
|
352
|
+
if (key === 'anomaly') continue;
|
|
353
|
+
|
|
354
|
+
results.push({
|
|
355
|
+
label: key,
|
|
356
|
+
value: result.classification[key],
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const top = results.sort((a, b) => b.value - a.value).slice(0, 5);
|
|
361
|
+
for (let ix = 0; ix < top.length; ix++) {
|
|
362
|
+
let span = ix === 0 ? document.createElement('strong') : document.createElement('span');
|
|
363
|
+
span.textContent = `${top[ix].label}: ${top[ix].value.toFixed(2)}`;
|
|
364
|
+
td.appendChild(span);
|
|
365
|
+
|
|
366
|
+
if (ix !== top.length - 1) {
|
|
367
|
+
let commaSpan = document.createElement('span');
|
|
368
|
+
commaSpan.textContent = ', ';
|
|
369
|
+
td.appendChild(commaSpan);
|
|
370
|
+
}
|
|
273
371
|
}
|
|
274
372
|
tr.appendChild(td);
|
|
373
|
+
|
|
374
|
+
if (Object.keys(result.classification).indexOf('anomaly') > -1) {
|
|
375
|
+
let anomalyTd = document.createElement('td');
|
|
376
|
+
anomalyTd.classList.add('text-center');
|
|
377
|
+
anomalyTd.textContent = result.classification.anomaly.toFixed(2);
|
|
378
|
+
tr.appendChild(anomalyTd);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
for (let k of Object.keys(result.classification)) {
|
|
383
|
+
let td = document.createElement('td');
|
|
384
|
+
td.classList.add('text-center');
|
|
385
|
+
td.textContent = result.classification[k].toFixed(2);
|
|
386
|
+
if (result.classification[k] === highest && !isVisualAnomaly) {
|
|
387
|
+
td.style.fontWeight = 600;
|
|
388
|
+
}
|
|
389
|
+
tr.appendChild(td);
|
|
390
|
+
}
|
|
275
391
|
}
|
|
392
|
+
|
|
276
393
|
if (result.visual_anomaly_grid) {
|
|
277
394
|
let td = document.createElement('td');
|
|
278
395
|
td.classList.add('text-center');
|
|
@@ -406,7 +523,9 @@ window.WebServer = async () => {
|
|
|
406
523
|
els.cameraContainer.appendChild(el);
|
|
407
524
|
}
|
|
408
525
|
}
|
|
409
|
-
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
socket.on('classification', onClassification);
|
|
410
529
|
|
|
411
530
|
if (els.websocketAddress) {
|
|
412
531
|
els.websocketAddress.textContent = `ws://${location.host}`;
|
|
@@ -48,9 +48,7 @@ const { ImageClassifier, LinuxImpulseRunner, Ffmpeg, Imagesnap, RunnerHelloHasAn
|
|
|
48
48
|
camera = new Imagesnap();
|
|
49
49
|
}
|
|
50
50
|
else if (process.platform === 'linux') {
|
|
51
|
-
camera = new Ffmpeg(false /* verbose
|
|
52
|
-
scaleAndCropInPipeline: true,
|
|
53
|
-
});
|
|
51
|
+
camera = new Ffmpeg(false /* verbose */);
|
|
54
52
|
}
|
|
55
53
|
else {
|
|
56
54
|
throw new Error('Unsupported platform "' + process.platform + '"');
|
|
@@ -49,9 +49,7 @@ import { RunnerHelloHasAnomaly } from "../../library/classifier/linux-impulse-ru
|
|
|
49
49
|
camera = new Imagesnap();
|
|
50
50
|
}
|
|
51
51
|
else if (process.platform === 'linux') {
|
|
52
|
-
camera = new GStreamer(false /* verbose
|
|
53
|
-
scaleAndCropInPipeline: true,
|
|
54
|
-
});
|
|
52
|
+
camera = new GStreamer(false /* verbose */);
|
|
55
53
|
}
|
|
56
54
|
else {
|
|
57
55
|
throw new Error('Unsupported platform "' + process.platform + '"');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "edge-impulse-linux",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.2",
|
|
4
4
|
"description": "Node.js SDK and tools for Edge Impulse for Linux",
|
|
5
5
|
"directories": {
|
|
6
6
|
"example": "examples"
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"form-data": "4.0.4",
|
|
43
43
|
"inquirer": "7.0.0",
|
|
44
44
|
"inquirer-search-list": "1.2.6",
|
|
45
|
+
"koffi": "2.12.1",
|
|
45
46
|
"multer": "1.4.5-lts.1",
|
|
46
47
|
"node-fetch": "2.7.0",
|
|
47
48
|
"npm-registry-fetch": "17.1.0",
|
package/test/gstreamer.test.ts
CHANGED
|
@@ -1288,8 +1288,6 @@ Device found:
|
|
|
1288
1288
|
|
|
1289
1289
|
});
|
|
1290
1290
|
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
1291
|
// https://forum.edgeimpulse.com/t/edge-impulse-on-coral-edgetpu/2311
|
|
1294
1292
|
it("coral edge tpu with iMX6S", async () => {
|
|
1295
1293
|
const gstOutput = `Probing devices...
|
|
@@ -5234,7 +5232,7 @@ Freeing pipeline ...
|
|
|
5234
5232
|
|
|
5235
5233
|
const gstreamer = new GStreamer(false, {
|
|
5236
5234
|
spawnHelperOverride: spawnHelper,
|
|
5237
|
-
|
|
5235
|
+
dontRunCleanupLoop: true,
|
|
5238
5236
|
});
|
|
5239
5237
|
await gstreamer.init();
|
|
5240
5238
|
const launchResp = await gstreamer.getGstreamerLaunchCommand({
|
|
@@ -5251,10 +5249,9 @@ Freeing pipeline ...
|
|
|
5251
5249
|
|
|
5252
5250
|
// console.log('launchResp', launchResp);
|
|
5253
5251
|
|
|
5254
|
-
assert.equal(launchResp.invokeProcess, 'spawn');
|
|
5255
5252
|
assert.equal(launchResp.command, 'gst-launch-1.0');
|
|
5256
|
-
assert.equal(launchResp.
|
|
5257
|
-
'pylonsrc ! video/x-raw,width=1440,height=1080 ! videoconvert ! jpegenc ! multifilesink location=
|
|
5253
|
+
assert.equal(launchResp.pipeline,
|
|
5254
|
+
'pylonsrc ! video/x-raw,width=1440,height=1080 ! videoconvert ! jpegenc ! multifilesink location=resized%05d.jpg');
|
|
5258
5255
|
});
|
|
5259
5256
|
|
|
5260
5257
|
it("w/ inference dims #1", async () => {
|
|
@@ -5277,7 +5274,7 @@ Freeing pipeline ...
|
|
|
5277
5274
|
|
|
5278
5275
|
const gstreamer = new GStreamer(false, {
|
|
5279
5276
|
spawnHelperOverride: spawnHelper,
|
|
5280
|
-
|
|
5277
|
+
dontRunCleanupLoop: true,
|
|
5281
5278
|
});
|
|
5282
5279
|
await gstreamer.init();
|
|
5283
5280
|
const launchResp = await gstreamer.getGstreamerLaunchCommand({
|
|
@@ -5298,10 +5295,13 @@ Freeing pipeline ...
|
|
|
5298
5295
|
|
|
5299
5296
|
// console.log('launchResp', launchResp);
|
|
5300
5297
|
|
|
5301
|
-
assert.equal(launchResp.invokeProcess, 'spawn');
|
|
5302
5298
|
assert.equal(launchResp.command, 'gst-launch-1.0');
|
|
5303
|
-
assert.equal(launchResp.
|
|
5304
|
-
'pylonsrc ! video/x-raw,width=1440,height=1080 ! videoconvert !
|
|
5299
|
+
assert.equal(launchResp.pipeline,
|
|
5300
|
+
'pylonsrc ! video/x-raw,width=1440,height=1080 ! videoconvert ! ' +
|
|
5301
|
+
'tee name=t ' +
|
|
5302
|
+
't. ! queue ! jpegenc ! multifilesink location=original%05d.jpg ' +
|
|
5303
|
+
't. ! queue ! videocrop left=180 right=180 ! videoscale method=lanczos ! video/x-raw,width=320,height=320 ! jpegenc ! multifilesink location=resized%05d.jpg'
|
|
5304
|
+
);
|
|
5305
5305
|
});
|
|
5306
5306
|
|
|
5307
5307
|
it("w/ inference dims #2", async () => {
|
|
@@ -5324,7 +5324,7 @@ Freeing pipeline ...
|
|
|
5324
5324
|
|
|
5325
5325
|
const gstreamer = new GStreamer(false, {
|
|
5326
5326
|
spawnHelperOverride: spawnHelper,
|
|
5327
|
-
|
|
5327
|
+
dontRunCleanupLoop: true,
|
|
5328
5328
|
});
|
|
5329
5329
|
await gstreamer.init();
|
|
5330
5330
|
const launchResp = await gstreamer.getGstreamerLaunchCommand({
|
|
@@ -5345,10 +5345,13 @@ Freeing pipeline ...
|
|
|
5345
5345
|
|
|
5346
5346
|
// console.log('launchResp', launchResp);
|
|
5347
5347
|
|
|
5348
|
-
assert.equal(launchResp.invokeProcess, 'spawn');
|
|
5349
5348
|
assert.equal(launchResp.command, 'gst-launch-1.0');
|
|
5350
|
-
assert.equal(launchResp.
|
|
5351
|
-
'pylonsrc ! video/x-raw,width=1440,height=1080 ! videoconvert !
|
|
5349
|
+
assert.equal(launchResp.pipeline,
|
|
5350
|
+
'pylonsrc ! video/x-raw,width=1440,height=1080 ! videoconvert ! ' +
|
|
5351
|
+
'tee name=t ' +
|
|
5352
|
+
't. ! queue ! jpegenc ! multifilesink location=original%05d.jpg ' +
|
|
5353
|
+
't. ! queue ! videoscale method=lanczos ! video/x-raw,width=320,height=320 ! jpegenc ! multifilesink location=resized%05d.jpg'
|
|
5354
|
+
);
|
|
5352
5355
|
});
|
|
5353
5356
|
|
|
5354
5357
|
it("w/ inference dims #3", async () => {
|
|
@@ -5371,7 +5374,7 @@ Freeing pipeline ...
|
|
|
5371
5374
|
|
|
5372
5375
|
const gstreamer = new GStreamer(false, {
|
|
5373
5376
|
spawnHelperOverride: spawnHelper,
|
|
5374
|
-
|
|
5377
|
+
dontRunCleanupLoop: true,
|
|
5375
5378
|
});
|
|
5376
5379
|
await gstreamer.init();
|
|
5377
5380
|
const launchResp = await gstreamer.getGstreamerLaunchCommand({
|
|
@@ -5392,10 +5395,9 @@ Freeing pipeline ...
|
|
|
5392
5395
|
|
|
5393
5396
|
// console.log('launchResp', launchResp);
|
|
5394
5397
|
|
|
5395
|
-
assert.equal(launchResp.invokeProcess, 'spawn');
|
|
5396
5398
|
assert.equal(launchResp.command, 'gst-launch-1.0');
|
|
5397
|
-
assert.equal(launchResp.
|
|
5398
|
-
'pylonsrc ! video/x-raw,width=1440,height=1080 ! videoconvert ! jpegenc ! multifilesink location=
|
|
5399
|
+
assert.equal(launchResp.pipeline,
|
|
5400
|
+
'pylonsrc ! video/x-raw,width=1440,height=1080 ! videoconvert ! jpegenc ! multifilesink location=resized%05d.jpg');
|
|
5399
5401
|
});
|
|
5400
5402
|
|
|
5401
5403
|
it("w/ inference dims #4", async () => {
|
|
@@ -5418,7 +5420,7 @@ Freeing pipeline ...
|
|
|
5418
5420
|
|
|
5419
5421
|
const gstreamer = new GStreamer(false, {
|
|
5420
5422
|
spawnHelperOverride: spawnHelper,
|
|
5421
|
-
|
|
5423
|
+
dontRunCleanupLoop: true,
|
|
5422
5424
|
});
|
|
5423
5425
|
await gstreamer.init();
|
|
5424
5426
|
const launchResp = await gstreamer.getGstreamerLaunchCommand({
|
|
@@ -5439,10 +5441,13 @@ Freeing pipeline ...
|
|
|
5439
5441
|
|
|
5440
5442
|
// console.log('launchResp', launchResp);
|
|
5441
5443
|
|
|
5442
|
-
assert.equal(launchResp.invokeProcess, 'spawn');
|
|
5443
5444
|
assert.equal(launchResp.command, 'gst-launch-1.0');
|
|
5444
|
-
assert.equal(launchResp.
|
|
5445
|
-
'pylonsrc ! video/x-raw,width=1440,height=1080 ! videoconvert !
|
|
5445
|
+
assert.equal(launchResp.pipeline,
|
|
5446
|
+
'pylonsrc ! video/x-raw,width=1440,height=1080 ! videoconvert ! ' +
|
|
5447
|
+
'tee name=t ' +
|
|
5448
|
+
't. ! queue ! jpegenc ! multifilesink location=original%05d.jpg ' +
|
|
5449
|
+
't. ! queue ! videoscale method=lanczos ! video/x-raw,width=320,height=320 ! jpegenc ! multifilesink location=resized%05d.jpg'
|
|
5450
|
+
);
|
|
5446
5451
|
});
|
|
5447
5452
|
});
|
|
5448
5453
|
});
|
|
@@ -5491,7 +5496,7 @@ async function testGetDevices(output: {
|
|
|
5491
5496
|
const gstreamer = new GStreamer(false, {
|
|
5492
5497
|
spawnHelperOverride: spawnHelper,
|
|
5493
5498
|
modeOverride: output?.modeOverride,
|
|
5494
|
-
|
|
5499
|
+
dontRunCleanupLoop: true,
|
|
5495
5500
|
});
|
|
5496
5501
|
await gstreamer.init();
|
|
5497
5502
|
const devices = await gstreamer.getAllDevices();
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { LinuxImpulseRunner } from "../../library";
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
|
|
4
|
-
// This script expects two arguments:
|
|
5
|
-
// 1. The model file
|
|
6
|
-
// 2. A features file with raw data. You can get this by going to **Live classification > Load sample**
|
|
7
|
-
// then copy the features from the 'Raw features' block.
|
|
8
|
-
|
|
9
|
-
(async () => {
|
|
10
|
-
try {
|
|
11
|
-
if (!process.argv[2]) {
|
|
12
|
-
console.log('Missing one argument (model file)');
|
|
13
|
-
process.exit(1);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (!process.argv[3]) {
|
|
17
|
-
console.log('Missing second argument (features file)');
|
|
18
|
-
process.exit(1);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Load the model
|
|
22
|
-
let runner = new LinuxImpulseRunner(process.argv[2]);
|
|
23
|
-
let model = await runner.init();
|
|
24
|
-
|
|
25
|
-
const windowLengthMs = ((model.modelParameters.input_features_count /
|
|
26
|
-
model.modelParameters.frequency /
|
|
27
|
-
model.modelParameters.axis_count) * 1000);
|
|
28
|
-
|
|
29
|
-
console.log('Starting the custom classifier for',
|
|
30
|
-
model.project.owner + ' / ' + model.project.name, '(v' + model.project.deploy_version + ')');
|
|
31
|
-
console.log('Parameters', 'freq', model.modelParameters.frequency + 'Hz',
|
|
32
|
-
'window length', windowLengthMs + 'ms.',
|
|
33
|
-
'classes', model.modelParameters.labels);
|
|
34
|
-
|
|
35
|
-
// read the features file (comma separated numbers)
|
|
36
|
-
// Newlines deliminate samples
|
|
37
|
-
// Create an array of array of Numbers. Each inner array is a sample.
|
|
38
|
-
let samples = (<string>await fs.promises.readFile(process.argv[3], 'utf-8'))
|
|
39
|
-
.trim().split('\n').map(line => line.split(',').map(n => Number(n)));
|
|
40
|
-
|
|
41
|
-
for (let features of samples) {
|
|
42
|
-
// and classify the data, this should match the classification in the Studio
|
|
43
|
-
let res = await runner.classify(features);
|
|
44
|
-
|
|
45
|
-
console.log('Begin output');
|
|
46
|
-
if (res.result.classification) {
|
|
47
|
-
let ret: number[] = [];
|
|
48
|
-
for (let k of Object.keys(res.result.classification)) {
|
|
49
|
-
ret.push(res.result.classification[k]);
|
|
50
|
-
}
|
|
51
|
-
if (typeof res.result.visual_anomaly_max === 'number') {
|
|
52
|
-
ret.push(res.result.visual_anomaly_max);
|
|
53
|
-
}
|
|
54
|
-
else if (typeof res.result.anomaly === 'number') {
|
|
55
|
-
ret.push(res.result.anomaly);
|
|
56
|
-
}
|
|
57
|
-
console.log('[' + ret.map(x => x.toFixed(5)).join(', ') + ']');
|
|
58
|
-
}
|
|
59
|
-
if (res.result.bounding_boxes) {
|
|
60
|
-
for (let bb of res.result.bounding_boxes) {
|
|
61
|
-
if (bb.value === 0) {
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
console.log(`${bb.label} (${bb.value.toFixed(5)}) ` +
|
|
65
|
-
`[ x: ${bb.x}, y: ${bb.y}, width: ${bb.width}, height: ${bb.height} ]`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
if (res.result.visual_anomaly_grid) {
|
|
69
|
-
for (let bb of res.result.visual_anomaly_grid) {
|
|
70
|
-
console.log(`${bb.label} (${bb.value.toFixed(5)}) ` +
|
|
71
|
-
`[ x: ${bb.x}, y: ${bb.y}, width: ${bb.width}, height: ${bb.height} ]`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
console.log('End output');
|
|
75
|
-
|
|
76
|
-
// if you want to fill in data on the fly you can also do this; e.g. if you have 3-axis accelerometer
|
|
77
|
-
// with 2 second window and 100Hz, then input_features_count=600, axis_count=3
|
|
78
|
-
// let features = [];
|
|
79
|
-
// for (let ix = 0; ix <
|
|
80
|
-
// model.modelParameters.input_features_count; ix += model.modelParameters.axis_count) {
|
|
81
|
-
// features.push(x);
|
|
82
|
-
// features.push(y);
|
|
83
|
-
// features.push(z);
|
|
84
|
-
// }
|
|
85
|
-
// and classify features
|
|
86
|
-
}
|
|
87
|
-
await runner.stop();
|
|
88
|
-
}
|
|
89
|
-
catch (ex) {
|
|
90
|
-
console.error(ex);
|
|
91
|
-
process.exit(1);
|
|
92
|
-
}
|
|
93
|
-
finally {
|
|
94
|
-
process.exit(0);
|
|
95
|
-
}
|
|
96
|
-
})();
|