@blueharford/scrypted-spatial-awareness 0.6.5 → 0.6.7
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/dist/main.nodejs.js +1 -1
- package/dist/main.nodejs.js.map +1 -1
- package/dist/plugin.zip +0 -0
- package/out/main.nodejs.js +67 -15
- package/out/main.nodejs.js.map +1 -1
- package/out/plugin.zip +0 -0
- package/package.json +1 -1
- package/src/main.ts +73 -16
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/out/main.nodejs.js
CHANGED
|
@@ -40054,7 +40054,7 @@ class SpatialAwarenessPlugin extends sdk_1.ScryptedDeviceBase {
|
|
|
40054
40054
|
});
|
|
40055
40055
|
}
|
|
40056
40056
|
}
|
|
40057
|
-
handleTrainingEndRequest(response) {
|
|
40057
|
+
async handleTrainingEndRequest(response) {
|
|
40058
40058
|
if (!this.trackingEngine) {
|
|
40059
40059
|
response.send(JSON.stringify({ error: 'Tracking engine not running' }), {
|
|
40060
40060
|
code: 500,
|
|
@@ -40064,6 +40064,39 @@ class SpatialAwarenessPlugin extends sdk_1.ScryptedDeviceBase {
|
|
|
40064
40064
|
}
|
|
40065
40065
|
const session = this.trackingEngine.endTrainingSession();
|
|
40066
40066
|
if (session) {
|
|
40067
|
+
// Get unique visited cameras
|
|
40068
|
+
const visitedCameraIds = [...new Set(session.visits.map(v => v.cameraId))];
|
|
40069
|
+
// Auto-run discovery on visited cameras to detect landmarks and zones
|
|
40070
|
+
if (this.discoveryEngine && visitedCameraIds.length > 0) {
|
|
40071
|
+
this.console.log(`[Training] Running discovery analysis on ${visitedCameraIds.length} visited cameras...`);
|
|
40072
|
+
let landmarksFound = 0;
|
|
40073
|
+
let zonesFound = 0;
|
|
40074
|
+
for (const cameraId of visitedCameraIds) {
|
|
40075
|
+
try {
|
|
40076
|
+
const analysis = await this.discoveryEngine.analyzeScene(cameraId);
|
|
40077
|
+
if (analysis.isValid) {
|
|
40078
|
+
landmarksFound += analysis.landmarks.length;
|
|
40079
|
+
zonesFound += analysis.zones.length;
|
|
40080
|
+
this.console.log(`[Training] ${cameraId}: Found ${analysis.landmarks.length} landmarks, ${analysis.zones.length} zones`);
|
|
40081
|
+
}
|
|
40082
|
+
}
|
|
40083
|
+
catch (e) {
|
|
40084
|
+
this.console.warn(`[Training] Failed to analyze ${cameraId}:`, e);
|
|
40085
|
+
}
|
|
40086
|
+
}
|
|
40087
|
+
// Get all pending suggestions and auto-accept them
|
|
40088
|
+
const suggestions = this.discoveryEngine.getPendingSuggestions();
|
|
40089
|
+
for (const suggestion of suggestions) {
|
|
40090
|
+
this.applyDiscoverySuggestion(suggestion);
|
|
40091
|
+
this.discoveryEngine.acceptSuggestion(suggestion.id);
|
|
40092
|
+
}
|
|
40093
|
+
// Persist topology after applying suggestions
|
|
40094
|
+
if (suggestions.length > 0 && this.trackingEngine) {
|
|
40095
|
+
const updatedTopology = this.trackingEngine.getTopology();
|
|
40096
|
+
await this.storageSettings.putSetting('topology', JSON.stringify(updatedTopology));
|
|
40097
|
+
this.console.log(`[Training] Auto-applied ${suggestions.length} discoveries (${landmarksFound} landmarks, ${zonesFound} zones)`);
|
|
40098
|
+
}
|
|
40099
|
+
}
|
|
40067
40100
|
response.send(JSON.stringify(session), {
|
|
40068
40101
|
headers: { 'Content-Type': 'application/json' },
|
|
40069
40102
|
});
|
|
@@ -40311,34 +40344,53 @@ class SpatialAwarenessPlugin extends sdk_1.ScryptedDeviceBase {
|
|
|
40311
40344
|
// Convert direction to radians (0 = up/north, 90 = right/east)
|
|
40312
40345
|
const dirRad = (direction - 90) * Math.PI / 180;
|
|
40313
40346
|
const halfFov = (fovAngle / 2) * Math.PI / 180;
|
|
40314
|
-
// Use
|
|
40347
|
+
// Use landmark TYPE to determine distance - some things are inherently far away
|
|
40348
|
+
// regardless of where they appear in the camera frame
|
|
40349
|
+
const landmarkType = suggestion.landmark.type;
|
|
40350
|
+
const farTypes = ['neighbor', 'boundary', 'street']; // Always place at edge of FOV
|
|
40351
|
+
const isFarType = farTypes.includes(landmarkType || '');
|
|
40352
|
+
// Use bounding box if available for horizontal positioning
|
|
40315
40353
|
// boundingBox format: [x, y, width, height] normalized 0-1
|
|
40316
40354
|
const bbox = suggestion.landmark.boundingBox;
|
|
40317
40355
|
let angleOffset;
|
|
40318
40356
|
let distanceMultiplier;
|
|
40319
40357
|
if (bbox && bbox.length >= 2) {
|
|
40320
|
-
// Use bounding box
|
|
40358
|
+
// Use bounding box X for horizontal position in FOV
|
|
40321
40359
|
const bboxCenterX = bbox[0] + (bbox[2] || 0) / 2; // 0 = left edge, 1 = right edge
|
|
40322
|
-
const bboxCenterY = bbox[1] + (bbox[3] || 0) / 2; // 0 = top (far), 1 = bottom (close)
|
|
40323
40360
|
// Map X position to angle within FOV
|
|
40324
|
-
// bboxCenterX 0 → left side of FOV (-halfFov)
|
|
40325
|
-
// bboxCenterX 0.5 → center of FOV (0)
|
|
40326
|
-
// bboxCenterX 1 → right side of FOV (+halfFov)
|
|
40327
40361
|
angleOffset = (bboxCenterX - 0.5) * 2 * halfFov;
|
|
40328
|
-
//
|
|
40329
|
-
|
|
40330
|
-
|
|
40331
|
-
|
|
40332
|
-
|
|
40362
|
+
// For distance: use TYPE first, then bbox Y as hint
|
|
40363
|
+
if (isFarType) {
|
|
40364
|
+
// Neighbors, boundaries, streets are BEYOND the camera's normal range
|
|
40365
|
+
// Place at 150-200% of range to indicate they're distant background features
|
|
40366
|
+
distanceMultiplier = 1.5 + Math.random() * 0.5; // 150-200% of range
|
|
40367
|
+
this.console.log(`[Discovery] Far-type landmark "${landmarkType}" placed BEYOND FOV (${(distanceMultiplier * 100).toFixed(0)}% of range)`);
|
|
40368
|
+
}
|
|
40369
|
+
else {
|
|
40370
|
+
// For other types, use bbox Y as a hint (but cap minimum distance)
|
|
40371
|
+
const bboxCenterY = bbox[1] + (bbox[3] || 0) / 2;
|
|
40372
|
+
// Map Y to distance: 0 (top) = far, 1 (bottom) = closer (but not too close)
|
|
40373
|
+
distanceMultiplier = Math.max(0.4, 0.9 - (bboxCenterY * 0.5));
|
|
40374
|
+
}
|
|
40375
|
+
this.console.log(`[Discovery] Using bounding box [${bbox.join(',')}] for horizontal position`);
|
|
40333
40376
|
}
|
|
40334
40377
|
else {
|
|
40335
|
-
//
|
|
40378
|
+
// No bounding box - use type and spread pattern
|
|
40336
40379
|
const cameraDeviceId = camera.deviceId;
|
|
40337
40380
|
const existingFromCamera = (topology.landmarks || []).filter(l => l.visibleFromCameras?.includes(cameraDeviceId) ||
|
|
40338
40381
|
l.visibleFromCameras?.includes(camera.name)).length;
|
|
40382
|
+
// Spread horizontally across FOV
|
|
40339
40383
|
angleOffset = (existingFromCamera % 3 - 1) * halfFov * 0.6;
|
|
40340
|
-
|
|
40341
|
-
|
|
40384
|
+
// Distance based on type
|
|
40385
|
+
if (isFarType) {
|
|
40386
|
+
// Neighbors, boundaries, streets are BEYOND the camera's normal range
|
|
40387
|
+
distanceMultiplier = 1.5 + Math.random() * 0.5; // 150-200% of range
|
|
40388
|
+
this.console.log(`[Discovery] Far-type landmark "${landmarkType}" (no bbox) placed BEYOND FOV`);
|
|
40389
|
+
}
|
|
40390
|
+
else {
|
|
40391
|
+
distanceMultiplier = 0.5 + (existingFromCamera % 2) * 0.3;
|
|
40392
|
+
this.console.log(`[Discovery] No bounding box, using fallback spread (existing: ${existingFromCamera})`);
|
|
40393
|
+
}
|
|
40342
40394
|
}
|
|
40343
40395
|
const finalAngle = dirRad + angleOffset;
|
|
40344
40396
|
const distance = range * distanceMultiplier;
|