@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/out/plugin.zip
CHANGED
|
Binary file
|
package/package.json
CHANGED
package/src/main.ts
CHANGED
|
@@ -1584,7 +1584,7 @@ export class SpatialAwarenessPlugin extends ScryptedDeviceBase
|
|
|
1584
1584
|
}
|
|
1585
1585
|
}
|
|
1586
1586
|
|
|
1587
|
-
private handleTrainingEndRequest(response: HttpResponse): void {
|
|
1587
|
+
private async handleTrainingEndRequest(response: HttpResponse): Promise<void> {
|
|
1588
1588
|
if (!this.trackingEngine) {
|
|
1589
1589
|
response.send(JSON.stringify({ error: 'Tracking engine not running' }), {
|
|
1590
1590
|
code: 500,
|
|
@@ -1595,6 +1595,44 @@ export class SpatialAwarenessPlugin extends ScryptedDeviceBase
|
|
|
1595
1595
|
|
|
1596
1596
|
const session = this.trackingEngine.endTrainingSession();
|
|
1597
1597
|
if (session) {
|
|
1598
|
+
// Get unique visited cameras
|
|
1599
|
+
const visitedCameraIds = [...new Set(session.visits.map(v => v.cameraId))];
|
|
1600
|
+
|
|
1601
|
+
// Auto-run discovery on visited cameras to detect landmarks and zones
|
|
1602
|
+
if (this.discoveryEngine && visitedCameraIds.length > 0) {
|
|
1603
|
+
this.console.log(`[Training] Running discovery analysis on ${visitedCameraIds.length} visited cameras...`);
|
|
1604
|
+
|
|
1605
|
+
let landmarksFound = 0;
|
|
1606
|
+
let zonesFound = 0;
|
|
1607
|
+
|
|
1608
|
+
for (const cameraId of visitedCameraIds) {
|
|
1609
|
+
try {
|
|
1610
|
+
const analysis = await this.discoveryEngine.analyzeScene(cameraId);
|
|
1611
|
+
if (analysis.isValid) {
|
|
1612
|
+
landmarksFound += analysis.landmarks.length;
|
|
1613
|
+
zonesFound += analysis.zones.length;
|
|
1614
|
+
this.console.log(`[Training] ${cameraId}: Found ${analysis.landmarks.length} landmarks, ${analysis.zones.length} zones`);
|
|
1615
|
+
}
|
|
1616
|
+
} catch (e) {
|
|
1617
|
+
this.console.warn(`[Training] Failed to analyze ${cameraId}:`, e);
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
// Get all pending suggestions and auto-accept them
|
|
1622
|
+
const suggestions = this.discoveryEngine.getPendingSuggestions();
|
|
1623
|
+
for (const suggestion of suggestions) {
|
|
1624
|
+
this.applyDiscoverySuggestion(suggestion);
|
|
1625
|
+
this.discoveryEngine.acceptSuggestion(suggestion.id);
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
// Persist topology after applying suggestions
|
|
1629
|
+
if (suggestions.length > 0 && this.trackingEngine) {
|
|
1630
|
+
const updatedTopology = this.trackingEngine.getTopology();
|
|
1631
|
+
await this.storageSettings.putSetting('topology', JSON.stringify(updatedTopology));
|
|
1632
|
+
this.console.log(`[Training] Auto-applied ${suggestions.length} discoveries (${landmarksFound} landmarks, ${zonesFound} zones)`);
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1598
1636
|
response.send(JSON.stringify(session), {
|
|
1599
1637
|
headers: { 'Content-Type': 'application/json' },
|
|
1600
1638
|
});
|
|
@@ -1866,7 +1904,13 @@ export class SpatialAwarenessPlugin extends ScryptedDeviceBase
|
|
|
1866
1904
|
const dirRad = (direction - 90) * Math.PI / 180;
|
|
1867
1905
|
const halfFov = (fovAngle / 2) * Math.PI / 180;
|
|
1868
1906
|
|
|
1869
|
-
// Use
|
|
1907
|
+
// Use landmark TYPE to determine distance - some things are inherently far away
|
|
1908
|
+
// regardless of where they appear in the camera frame
|
|
1909
|
+
const landmarkType = suggestion.landmark.type;
|
|
1910
|
+
const farTypes = ['neighbor', 'boundary', 'street']; // Always place at edge of FOV
|
|
1911
|
+
const isFarType = farTypes.includes(landmarkType || '');
|
|
1912
|
+
|
|
1913
|
+
// Use bounding box if available for horizontal positioning
|
|
1870
1914
|
// boundingBox format: [x, y, width, height] normalized 0-1
|
|
1871
1915
|
const bbox = (suggestion.landmark as any).boundingBox as [number, number, number, number] | undefined;
|
|
1872
1916
|
|
|
@@ -1874,33 +1918,46 @@ export class SpatialAwarenessPlugin extends ScryptedDeviceBase
|
|
|
1874
1918
|
let distanceMultiplier: number;
|
|
1875
1919
|
|
|
1876
1920
|
if (bbox && bbox.length >= 2) {
|
|
1877
|
-
// Use bounding box
|
|
1921
|
+
// Use bounding box X for horizontal position in FOV
|
|
1878
1922
|
const bboxCenterX = bbox[0] + (bbox[2] || 0) / 2; // 0 = left edge, 1 = right edge
|
|
1879
|
-
const bboxCenterY = bbox[1] + (bbox[3] || 0) / 2; // 0 = top (far), 1 = bottom (close)
|
|
1880
1923
|
|
|
1881
1924
|
// Map X position to angle within FOV
|
|
1882
|
-
// bboxCenterX 0 → left side of FOV (-halfFov)
|
|
1883
|
-
// bboxCenterX 0.5 → center of FOV (0)
|
|
1884
|
-
// bboxCenterX 1 → right side of FOV (+halfFov)
|
|
1885
1925
|
angleOffset = (bboxCenterX - 0.5) * 2 * halfFov;
|
|
1886
1926
|
|
|
1887
|
-
//
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1927
|
+
// For distance: use TYPE first, then bbox Y as hint
|
|
1928
|
+
if (isFarType) {
|
|
1929
|
+
// Neighbors, boundaries, streets are BEYOND the camera's normal range
|
|
1930
|
+
// Place at 150-200% of range to indicate they're distant background features
|
|
1931
|
+
distanceMultiplier = 1.5 + Math.random() * 0.5; // 150-200% of range
|
|
1932
|
+
this.console.log(`[Discovery] Far-type landmark "${landmarkType}" placed BEYOND FOV (${(distanceMultiplier * 100).toFixed(0)}% of range)`);
|
|
1933
|
+
} else {
|
|
1934
|
+
// For other types, use bbox Y as a hint (but cap minimum distance)
|
|
1935
|
+
const bboxCenterY = bbox[1] + (bbox[3] || 0) / 2;
|
|
1936
|
+
// Map Y to distance: 0 (top) = far, 1 (bottom) = closer (but not too close)
|
|
1937
|
+
distanceMultiplier = Math.max(0.4, 0.9 - (bboxCenterY * 0.5));
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
this.console.log(`[Discovery] Using bounding box [${bbox.join(',')}] for horizontal position`);
|
|
1893
1941
|
} else {
|
|
1894
|
-
//
|
|
1942
|
+
// No bounding box - use type and spread pattern
|
|
1895
1943
|
const cameraDeviceId = camera.deviceId;
|
|
1896
1944
|
const existingFromCamera = (topology.landmarks || []).filter(l =>
|
|
1897
1945
|
l.visibleFromCameras?.includes(cameraDeviceId) ||
|
|
1898
1946
|
l.visibleFromCameras?.includes(camera.name)
|
|
1899
1947
|
).length;
|
|
1900
1948
|
|
|
1949
|
+
// Spread horizontally across FOV
|
|
1901
1950
|
angleOffset = (existingFromCamera % 3 - 1) * halfFov * 0.6;
|
|
1902
|
-
|
|
1903
|
-
|
|
1951
|
+
|
|
1952
|
+
// Distance based on type
|
|
1953
|
+
if (isFarType) {
|
|
1954
|
+
// Neighbors, boundaries, streets are BEYOND the camera's normal range
|
|
1955
|
+
distanceMultiplier = 1.5 + Math.random() * 0.5; // 150-200% of range
|
|
1956
|
+
this.console.log(`[Discovery] Far-type landmark "${landmarkType}" (no bbox) placed BEYOND FOV`);
|
|
1957
|
+
} else {
|
|
1958
|
+
distanceMultiplier = 0.5 + (existingFromCamera % 2) * 0.3;
|
|
1959
|
+
this.console.log(`[Discovery] No bounding box, using fallback spread (existing: ${existingFromCamera})`);
|
|
1960
|
+
}
|
|
1904
1961
|
}
|
|
1905
1962
|
|
|
1906
1963
|
const finalAngle = dirRad + angleOffset;
|