Files
sight-identification/lib/services/yolo_service.dart

148 lines
3.9 KiB
Dart
Raw Normal View History

2026-01-07 16:14:34 +08:00
import 'dart:io';
import 'package:http/http.dart' as http;
import 'dart:convert';
class YOLOAnalysisResult {
final List<DetectedObject> objects;
final String? error;
YOLOAnalysisResult({
required this.objects,
this.error,
});
factory YOLOAnalysisResult.fromJson(Map<String, dynamic> json) {
if (json.containsKey('error')) {
return YOLOAnalysisResult(
objects: [],
error: json['error'],
);
}
List<DetectedObject> objects = [];
if (json.containsKey('objects') || json.containsKey('detections')) {
final detections = json['objects'] ?? json['detections'] ?? [];
objects = (detections as List)
.map((item) => DetectedObject.fromJson(item))
.toList();
}
return YOLOAnalysisResult(objects: objects);
}
}
class DetectedObject {
final String label;
final double confidence;
final BoundingBox bbox;
DetectedObject({
required this.label,
required this.confidence,
required this.bbox,
});
factory DetectedObject.fromJson(Map<String, dynamic> json) {
return DetectedObject(
label: json['label'] ?? json['class'] ?? json['name'] ?? 'Unknown',
confidence: (json['confidence'] ?? json['score'] ?? 0.0).toDouble(),
bbox: BoundingBox.fromJson(json['bbox'] ?? json['box'] ?? {}),
);
}
}
class BoundingBox {
final double x;
final double y;
final double width;
final double height;
BoundingBox({
required this.x,
required this.y,
required this.width,
required this.height,
});
factory BoundingBox.fromJson(Map<String, dynamic> json) {
return BoundingBox(
x: (json['x'] ?? json['x1'] ?? 0.0).toDouble(),
y: (json['y'] ?? json['y1'] ?? 0.0).toDouble(),
width: (json['width'] ?? (json['x2'] ?? 0.0) - (json['x1'] ?? 0.0)).toDouble(),
height: (json['height'] ?? (json['y2'] ?? 0.0) - (json['y1'] ?? 0.0)).toDouble(),
);
}
}
class YOLOService {
// 配置YOLO API端点用户可以修改
2026-01-07 16:42:22 +08:00
static const String yoloApiUrl = 'http://localhost:8000/api/detect';
2026-01-07 16:14:34 +08:00
// 分析单张图片
Future<YOLOAnalysisResult> analyzeImage(String imagePath) async {
try {
final file = File(imagePath);
if (!await file.exists()) {
return YOLOAnalysisResult(
objects: [],
error: '图片文件不存在',
);
}
// 创建multipart请求
var request = http.MultipartRequest('POST', Uri.parse(yoloApiUrl));
request.files.add(
await http.MultipartFile.fromPath('image', imagePath),
);
// 发送请求
var response = await request.send();
var responseBody = await response.stream.bytesToString();
if (response.statusCode == 200) {
final jsonData = json.decode(responseBody);
return YOLOAnalysisResult.fromJson(jsonData);
} else {
return YOLOAnalysisResult(
objects: [],
error: 'API请求失败: ${response.statusCode}',
);
}
} catch (e) {
// 如果API不可用返回模拟数据用于测试
return _getMockAnalysisResult();
}
}
// 分析多张图片
Future<Map<String, YOLOAnalysisResult>> analyzeImages(List<String> imagePaths) async {
Map<String, YOLOAnalysisResult> results = {};
for (String path in imagePaths) {
results[path] = await analyzeImage(path);
}
return results;
}
// 获取模拟分析结果用于测试当API不可用时
YOLOAnalysisResult _getMockAnalysisResult() {
return YOLOAnalysisResult(
objects: [
DetectedObject(
label: 'person',
confidence: 0.95,
bbox: BoundingBox(x: 100, y: 100, width: 200, height: 300),
),
DetectedObject(
label: 'chair',
confidence: 0.87,
bbox: BoundingBox(x: 300, y: 250, width: 150, height: 200),
),
],
error: '使用模拟数据YOLO API未配置或不可用',
);
}
}