fix: filtre historique, fuite mémoire OpenCV, export IA, tests
- Historique : le filtre par type de cible est désormais appliqué au chargement ; correction du piège PopupMenuItem(value: null) qui empêchait l'option « Tous » de réinitialiser le filtre ; icône colorée quand un filtre est actif - OpenCV : libération des Mat natifs (img, gray, blurred, circles) dans un finally — detectTarget tourne toutes les secondes pendant l'aperçu caméra et faisait grimper la mémoire native en continu - Export IA : distance, arme et id de session réels transmis depuis SessionProvider au lieu des placeholders (25 m / "Unknown") - Tests : remplacement du test widget cassé (BullyApp sans providers) par 14 tests qui passent — calcul de score concentrique (centre, hors cible, ratio d'image, anneaux personnalisés), agrégation des scores, analyse de groupement, et rendu du widget StatsCard Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,8 @@ class AiExportService {
|
||||
required double targetCenterY,
|
||||
required double targetRadius,
|
||||
required List<Shot> shots,
|
||||
int distanceMeters = 25,
|
||||
String weaponName = 'Unknown',
|
||||
String? apiUrl,
|
||||
}) async {
|
||||
try {
|
||||
@@ -109,9 +111,9 @@ class AiExportService {
|
||||
"device_info": deviceData,
|
||||
"target_metadata": {
|
||||
"type": targetType.name,
|
||||
"distance_meters": 25, // Default/placeholder
|
||||
"weapon": "Unknown", // Default/placeholder
|
||||
// The backend could extract exact width/height from the image.
|
||||
"distance_meters": distanceMeters,
|
||||
"weapon": weaponName,
|
||||
// The backend could extract exact width/height from the image.
|
||||
},
|
||||
"plotting": {
|
||||
"target_corners": corners,
|
||||
|
||||
@@ -26,23 +26,34 @@ class TargetDetectionResult {
|
||||
|
||||
class OpenCVTargetService {
|
||||
/// Detect the main target (center and radius) from an image file
|
||||
///
|
||||
/// IMPORTANT : les Mat OpenCV sont de la mémoire NATIVE, invisible pour le
|
||||
/// garbage collector Dart. Cette méthode est appelée en boucle (~1 s)
|
||||
/// pendant l'aperçu caméra : sans dispose() explicite dans le finally, la
|
||||
/// mémoire native grimpe en continu tant que l'utilisateur vise.
|
||||
Future<TargetDetectionResult> detectTarget(String imagePath) async {
|
||||
cv.Mat? img;
|
||||
cv.Mat? gray;
|
||||
cv.Mat? blurred;
|
||||
cv.Mat? circles;
|
||||
cv.Mat? looseCircles;
|
||||
|
||||
try {
|
||||
// Read image
|
||||
final img = cv.imread(imagePath, flags: cv.IMREAD_COLOR);
|
||||
img = cv.imread(imagePath, flags: cv.IMREAD_COLOR);
|
||||
if (img.isEmpty) {
|
||||
return TargetDetectionResult.failure();
|
||||
}
|
||||
|
||||
// Convert to grayscale
|
||||
final gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY);
|
||||
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY);
|
||||
|
||||
// Apply Gaussian blur to reduce noise
|
||||
final blurred = cv.gaussianBlur(gray, (9, 9), 2, sigmaY: 2);
|
||||
blurred = cv.gaussianBlur(gray, (9, 9), 2, sigmaY: 2);
|
||||
|
||||
// Detect circles using Hough Transform
|
||||
// Parameters need to be tuned for the specific target type
|
||||
final circles = cv.HoughCircles(
|
||||
// Detect circles using Hough Transform.
|
||||
// HoughCircles returns a Mat of shape (1, N) of Vec3f (x, y, r).
|
||||
circles = cv.HoughCircles(
|
||||
blurred,
|
||||
cv.HOUGH_GRADIENT,
|
||||
1, // dp
|
||||
@@ -55,26 +66,9 @@ class OpenCVTargetService {
|
||||
maxRadius: img.cols ~/ 2,
|
||||
);
|
||||
|
||||
// HoughCircles returns a Mat of shape (1, N, 3) where N is number of circles.
|
||||
// In opencv_dart, we cannot iterate easily.
|
||||
// However, we can access data via pointer if needed, or check if Vec3f is supported.
|
||||
// Given the user report, `at<Vec3f>` likely failed compilation or runtime.
|
||||
// Let's use a safer approach: assume standard memory layout (x, y, r, x, y, r...).
|
||||
// Or use `at<double>` carefully.
|
||||
|
||||
// Better yet: try to use `circles.data` if available, but it returns a Pointer.
|
||||
// Let's stick to `at` but use `double` and manual offset if Vec3f fails.
|
||||
// actually, let's try to trust `at<double>` for flattened access OR `at<Vec3f>`.
|
||||
// NOTE: `at<Vec3f>` was reported as "method at not defined for VecPoint2f" earlier, NOT for Mat.
|
||||
// The user error was for `VecPoint2f`. `Mat` definitely has `at`.
|
||||
// BUT `VecPoint2f` is a List-like structure in Dart wrapper.
|
||||
// usage of `at` on `VecPoint2f` was the error.
|
||||
// Here `circles` IS A MAT. So `at` IS defined.
|
||||
// However, to be safe and robust, and to implement clustering...
|
||||
|
||||
if (circles.isEmpty) {
|
||||
// Try with different parameters if first attempt fails (more lenient)
|
||||
final looseCircles = cv.HoughCircles(
|
||||
looseCircles = cv.HoughCircles(
|
||||
blurred,
|
||||
cv.HOUGH_GRADIENT,
|
||||
1,
|
||||
@@ -93,8 +87,15 @@ class OpenCVTargetService {
|
||||
|
||||
return _findBestConcentricCircles(circles, img.cols, img.rows);
|
||||
} catch (e) {
|
||||
// print('Error detecting target with OpenCV: $e');
|
||||
return TargetDetectionResult.failure();
|
||||
} finally {
|
||||
// _findBestConcentricCircles a déjà extrait les données dans des listes
|
||||
// Dart avant qu'on arrive ici : libérer les Mat est donc toujours sûr.
|
||||
img?.dispose();
|
||||
gray?.dispose();
|
||||
blurred?.dispose();
|
||||
circles?.dispose();
|
||||
looseCircles?.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user