feat: finalize AI analyzer, sync endpoints, and stabilize builds
This commit is contained in:
@@ -1,5 +1,23 @@
|
||||
enum ObstacleDirection { left, center, right }
|
||||
|
||||
class BoundingBox {
|
||||
final double left;
|
||||
final double top;
|
||||
final double right;
|
||||
final double bottom;
|
||||
|
||||
const BoundingBox({
|
||||
required this.left,
|
||||
required this.top,
|
||||
required this.right,
|
||||
required this.bottom,
|
||||
});
|
||||
|
||||
double get width => right - left;
|
||||
double get height => bottom - top;
|
||||
double get centerX => left + width / 2;
|
||||
}
|
||||
|
||||
class DetectionResult {
|
||||
final String label;
|
||||
final double confidence;
|
||||
@@ -26,12 +44,73 @@ class DetectionResult {
|
||||
}
|
||||
|
||||
class ObstacleAnalyzer {
|
||||
DetectionResult analyzeFallback({String label = 'person', double confidence = 0.86}) {
|
||||
static const double frameWidth = 640.0;
|
||||
static const double frameHeight = 480.0;
|
||||
|
||||
ObstacleDirection analyzeDirection(BoundingBox box) {
|
||||
final cx = box.centerX;
|
||||
if (cx < frameWidth * 0.33) return ObstacleDirection.left;
|
||||
if (cx > frameWidth * 0.67) return ObstacleDirection.right;
|
||||
return ObstacleDirection.center;
|
||||
}
|
||||
|
||||
String estimateDistance(BoundingBox box) {
|
||||
final ratio = box.height / frameHeight;
|
||||
if (ratio > 0.60) return 'Very Close (< 1m)';
|
||||
if (ratio > 0.35) return 'Close (1-2m)';
|
||||
if (ratio > 0.15) return 'Medium (2-4m)';
|
||||
return 'Far (> 4m)';
|
||||
}
|
||||
|
||||
String buildTtsMessage(DetectionResult result) {
|
||||
final directionLabel = switch (result.direction) {
|
||||
ObstacleDirection.left => 'kiri',
|
||||
ObstacleDirection.center => 'depan',
|
||||
ObstacleDirection.right => 'kanan',
|
||||
};
|
||||
return 'Hati-hati, ${result.label} di $directionLabel. '
|
||||
'Jarak ${result.estimatedDistance}.';
|
||||
}
|
||||
|
||||
DetectionResult? prioritize(List<DetectionResult> detections) {
|
||||
if (detections.isEmpty) return null;
|
||||
const order = [
|
||||
'Very Close (< 1m)',
|
||||
'Very Close',
|
||||
'Close (1-2m)',
|
||||
'Close',
|
||||
'Medium (2-4m)',
|
||||
'Medium',
|
||||
'Far (> 4m)',
|
||||
'Far',
|
||||
];
|
||||
final sorted = List<DetectionResult>.of(detections);
|
||||
sorted.sort((a, b) {
|
||||
final ai = order.indexOf(a.estimatedDistance);
|
||||
final bi = order.indexOf(b.estimatedDistance);
|
||||
final aRank = ai == -1 ? order.length : ai;
|
||||
final bRank = bi == -1 ? order.length : bi;
|
||||
return aRank.compareTo(bRank);
|
||||
});
|
||||
return sorted.first;
|
||||
}
|
||||
|
||||
List<DetectionResult> filterByConfidence(
|
||||
List<DetectionResult> detections,
|
||||
double threshold,
|
||||
) {
|
||||
return detections.where((d) => d.confidence >= threshold).toList();
|
||||
}
|
||||
|
||||
DetectionResult analyzeFallback({
|
||||
String label = 'person',
|
||||
double confidence = 0.86,
|
||||
}) {
|
||||
return DetectionResult(
|
||||
label: label,
|
||||
confidence: confidence,
|
||||
direction: ObstacleDirection.center,
|
||||
estimatedDistance: 'Close',
|
||||
estimatedDistance: 'Close (1-2m)',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user