desactivation de tous les scripts et ia, supression du modele yolo
This commit is contained in:
@@ -392,16 +392,21 @@ class TargetDetectionService {
|
||||
final impacts = await _yoloService.detectImpacts(imagePath);
|
||||
|
||||
return impacts.map((impact) {
|
||||
final score = targetType == TargetType.concentric
|
||||
? _calculateConcentricScoreWithRings(
|
||||
impact.x,
|
||||
impact.y,
|
||||
centerX,
|
||||
centerY,
|
||||
radius,
|
||||
ringCount,
|
||||
)
|
||||
: _calculateSilhouetteScore(impact.x, impact.y, centerX, centerY);
|
||||
// Use YOLO-detected score (valeur) if available, otherwise calculate it
|
||||
int score = impact.suggestedScore;
|
||||
|
||||
if (score <= 0) {
|
||||
score = targetType == TargetType.concentric
|
||||
? _calculateConcentricScoreWithRings(
|
||||
impact.x,
|
||||
impact.y,
|
||||
centerX,
|
||||
centerY,
|
||||
radius,
|
||||
ringCount,
|
||||
)
|
||||
: _calculateSilhouetteScore(impact.x, impact.y, centerX, centerY);
|
||||
}
|
||||
|
||||
return DetectedImpactResult(
|
||||
x: impact.x,
|
||||
|
||||
@@ -7,25 +7,41 @@ import 'target_detection_service.dart';
|
||||
|
||||
class YOLOImpactDetectionService {
|
||||
Interpreter? _interpreter;
|
||||
int _inputSize = 640;
|
||||
List<int> _outputShape = [1, 17, 8400];
|
||||
int _numClasses = 13;
|
||||
|
||||
static const String modelPath = 'assets/models/yolov11n_impact.tflite';
|
||||
static const String modelPath = 'assets/models/yolov8n_32.tflite';
|
||||
static const String labelsPath = 'assets/models/labels.txt';
|
||||
|
||||
Future<void> init() async {
|
||||
if (_interpreter != null) return;
|
||||
|
||||
try {
|
||||
// Try loading the specific YOLOv11 model first, fallback to v8 if not found
|
||||
try {
|
||||
_interpreter = await Interpreter.fromAsset(modelPath);
|
||||
} catch (e) {
|
||||
print('YOLOv11 model not found at $modelPath, trying YOLOv8 fallback');
|
||||
_interpreter = await Interpreter.fromAsset(
|
||||
'assets/models/yolov8n_impact.tflite',
|
||||
);
|
||||
_interpreter = await Interpreter.fromAsset(modelPath);
|
||||
|
||||
// Get model metadata
|
||||
final inputTensors = _interpreter!.getInputTensors();
|
||||
if (inputTensors.isNotEmpty) {
|
||||
// [1, 640, 640, 3] or [1, 3, 640, 640]
|
||||
final shape = inputTensors[0].shape;
|
||||
if (shape.length == 4) {
|
||||
_inputSize = shape[1] == 3 ? shape[2] : shape[1];
|
||||
}
|
||||
}
|
||||
|
||||
final outputTensors = _interpreter!.getOutputTensors();
|
||||
if (outputTensors.isNotEmpty) {
|
||||
_outputShape = outputTensors[0].shape;
|
||||
// Output is usually [1, 4 + num_classes, num_boxes]
|
||||
if (_outputShape.length == 3) {
|
||||
_numClasses = _outputShape[1] - 4;
|
||||
}
|
||||
}
|
||||
|
||||
print('YOLO Interpreter loaded successfully');
|
||||
print('Model Input Size: $_inputSize');
|
||||
print('Model Output Shape: $_outputShape (Classes: $_numClasses)');
|
||||
} catch (e) {
|
||||
print('Error loading YOLO model: $e');
|
||||
}
|
||||
@@ -37,31 +53,35 @@ class YOLOImpactDetectionService {
|
||||
|
||||
try {
|
||||
final bytes = File(imagePath).readAsBytesSync();
|
||||
final originalImage = img.decodeImage(bytes);
|
||||
if (originalImage == null) return [];
|
||||
final decodedImage = img.decodeImage(bytes);
|
||||
if (decodedImage == null) return [];
|
||||
|
||||
final originalImage = img.bakeOrientation(decodedImage);
|
||||
|
||||
// YOLOv8/v11 usually takes 640x640
|
||||
const int inputSize = 640;
|
||||
final resizedImage = img.copyResize(
|
||||
originalImage,
|
||||
width: inputSize,
|
||||
height: inputSize,
|
||||
width: _inputSize,
|
||||
height: _inputSize,
|
||||
);
|
||||
|
||||
// Prepare input tensor
|
||||
var input = _imageToByteListFloat32(resizedImage, inputSize);
|
||||
|
||||
// Raw YOLO output shape usually [1, 4 + num_classes, 8400]
|
||||
// For single class "impact", it's [1, 5, 8400]
|
||||
var output = List<double>.filled(1 * 5 * 8400, 0).reshape([1, 5, 8400]);
|
||||
var input = _imageToByteListFloat32(resizedImage, _inputSize);
|
||||
|
||||
// Allocate output buffer dynamically
|
||||
var output = List<double>.filled(
|
||||
_outputShape.fold(1, (a, b) => a * b),
|
||||
0
|
||||
).reshape(_outputShape);
|
||||
|
||||
_interpreter!.run(input, output);
|
||||
|
||||
return _processOutput(
|
||||
final results = _processOutput(
|
||||
output[0],
|
||||
originalImage.width,
|
||||
originalImage.height,
|
||||
);
|
||||
|
||||
print('YOLO Detection result count: ${results.length}');
|
||||
return results;
|
||||
} catch (e) {
|
||||
print('Error during YOLO inference: $e');
|
||||
return [];
|
||||
@@ -76,33 +96,55 @@ class YOLOImpactDetectionService {
|
||||
final List<_Detection> candidates = [];
|
||||
const double threshold = 0.25;
|
||||
|
||||
// output is [5, 8400] -> [x, y, w, h, conf]
|
||||
for (int i = 0; i < 8400; i++) {
|
||||
final double confidence = output[4][i];
|
||||
if (confidence > threshold) {
|
||||
// output is typically [4 + numClasses, numBoxes]
|
||||
final int rows = output.length;
|
||||
final int numBoxes = output[0].length;
|
||||
|
||||
for (int i = 0; i < numBoxes; i++) {
|
||||
double maxConfidence = 0;
|
||||
int bestClass = 4;
|
||||
|
||||
// Find best class among all classes (indices 4 to rows-1)
|
||||
for (int c = 4; c < rows; c++) {
|
||||
if (output[c][i] > maxConfidence) {
|
||||
maxConfidence = output[c][i];
|
||||
bestClass = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxConfidence > threshold) {
|
||||
final int classIndex = bestClass - 4;
|
||||
|
||||
candidates.add(
|
||||
_Detection(
|
||||
x: output[0][i],
|
||||
y: output[1][i],
|
||||
// Use dynamic mapping: 0,1,2,3 are typically x,y,w,h
|
||||
// We'll keep the current mapping for now as it matches user's previous model
|
||||
y: output[0][i],
|
||||
x: output[1][i],
|
||||
w: output[2][i],
|
||||
h: output[3][i],
|
||||
confidence: confidence,
|
||||
confidence: maxConfidence,
|
||||
classIndex: classIndex,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Non-Max Suppression (NMS)
|
||||
final List<_Detection> suppressed = _nms(candidates);
|
||||
|
||||
return suppressed
|
||||
.map(
|
||||
(det) => DetectedImpactResult(
|
||||
x: det.x / 640.0,
|
||||
y: det.y / 640.0,
|
||||
radius: 5.0,
|
||||
suggestedScore: 0,
|
||||
),
|
||||
(det) {
|
||||
// Score = ClassIndex (0 to 10) for impact models
|
||||
int score = det.classIndex;
|
||||
|
||||
return DetectedImpactResult(
|
||||
x: det.x,
|
||||
y: det.y,
|
||||
radius: 5.0,
|
||||
suggestedScore: score,
|
||||
);
|
||||
},
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
@@ -110,7 +152,6 @@ class YOLOImpactDetectionService {
|
||||
List<_Detection> _nms(List<_Detection> detections) {
|
||||
if (detections.isEmpty) return [];
|
||||
|
||||
// Sort by confidence descending
|
||||
detections.sort((a, b) => b.confidence.compareTo(a.confidence));
|
||||
|
||||
final List<_Detection> selected = [];
|
||||
@@ -164,11 +205,13 @@ class YOLOImpactDetectionService {
|
||||
|
||||
class _Detection {
|
||||
final double x, y, w, h, confidence;
|
||||
final int classIndex;
|
||||
_Detection({
|
||||
required this.x,
|
||||
required this.y,
|
||||
required this.w,
|
||||
required this.h,
|
||||
required this.confidence,
|
||||
required this.classIndex,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user