feat: implement base architecture and core repositories for weapon tracking and target analysis functionality
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'dart:math' as math;
|
||||
import 'package:image/image.dart' as img;
|
||||
|
||||
@@ -189,7 +190,7 @@ class ImageProcessingService {
|
||||
);
|
||||
}).toList();
|
||||
} catch (e) {
|
||||
print('Error detecting impacts: $e');
|
||||
debugPrint('Error detecting impacts: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -236,14 +237,14 @@ class ImageProcessingService {
|
||||
final fillRatios = <double>[];
|
||||
final thresholds = <double>[];
|
||||
|
||||
print('Analyzing ${references.length} reference impacts...');
|
||||
debugPrint('Analyzing ${references.length} reference impacts...');
|
||||
|
||||
for (int refIndex = 0; refIndex < references.length; refIndex++) {
|
||||
final ref = references[refIndex];
|
||||
final centerX = (ref.x * width).round().clamp(0, width - 1);
|
||||
final centerY = (ref.y * height).round().clamp(0, height - 1);
|
||||
|
||||
print('Reference $refIndex at ($centerX, $centerY)');
|
||||
debugPrint('Reference $refIndex at ($centerX, $centerY)');
|
||||
|
||||
// AMÉLIORATION : Recherche du point le plus sombre dans une zone plus large
|
||||
int darkestX = centerX;
|
||||
@@ -275,7 +276,7 @@ class ImageProcessingService {
|
||||
if (darkestLum < 50 && r > 5) break;
|
||||
}
|
||||
|
||||
print(' Darkest point at ($darkestX, $darkestY), lum=$darkestLum');
|
||||
debugPrint(' Darkest point at ($darkestX, $darkestY), lum=$darkestLum');
|
||||
|
||||
// Now find the blob at the darkest point using adaptive threshold
|
||||
final blobResult = _findBlobAtPoint(blurred, darkestX, darkestY, width, height);
|
||||
@@ -286,15 +287,15 @@ class ImageProcessingService {
|
||||
circularities.add(blobResult.circularity);
|
||||
fillRatios.add(blobResult.fillRatio);
|
||||
thresholds.add(blobResult.threshold);
|
||||
print(' Found blob: size=${blobResult.size}, circ=${blobResult.circularity.toStringAsFixed(2)}, '
|
||||
debugPrint(' Found blob: size=${blobResult.size}, circ=${blobResult.circularity.toStringAsFixed(2)}, '
|
||||
'fill=${blobResult.fillRatio.toStringAsFixed(2)}, threshold=${blobResult.threshold.toStringAsFixed(0)}');
|
||||
} else {
|
||||
print(' No valid blob found at this reference');
|
||||
debugPrint(' No valid blob found at this reference');
|
||||
}
|
||||
}
|
||||
|
||||
if (luminances.isEmpty) {
|
||||
print('ERROR: No valid blobs found from any reference!');
|
||||
debugPrint('ERROR: No valid blobs found from any reference!');
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -329,11 +330,11 @@ class ImageProcessingService {
|
||||
avgDarkThreshold: avgThreshold,
|
||||
);
|
||||
|
||||
print('Learned characteristics: $result');
|
||||
debugPrint('Learned characteristics: $result');
|
||||
|
||||
return result;
|
||||
} catch (e) {
|
||||
print('Error analyzing reference impacts: $e');
|
||||
debugPrint('Error analyzing reference impacts: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -680,7 +681,7 @@ class ImageProcessingService {
|
||||
// Calculate minimum fill ratio - impacts pleins
|
||||
final minFillRatio = (characteristics.avgFillRatio - 0.2).clamp(0.35, 0.85);
|
||||
|
||||
print('Detection params: thresholds=$thresholds, size=$minSize-$maxSize, '
|
||||
debugPrint('Detection params: thresholds=$thresholds, size=$minSize-$maxSize, '
|
||||
'circ>=$effectiveMinCircularity, fill>=$minFillRatio');
|
||||
|
||||
// Détecter avec plusieurs seuils et combiner les résultats
|
||||
@@ -722,7 +723,7 @@ class ImageProcessingService {
|
||||
return true;
|
||||
}).toList();
|
||||
|
||||
print('Found ${filteredBlobs.length} impacts after filtering (from ${mergedBlobs.length} merged)');
|
||||
debugPrint('Found ${filteredBlobs.length} impacts after filtering (from ${mergedBlobs.length} merged)');
|
||||
|
||||
// Convert to relative coordinates
|
||||
return filteredBlobs.map((blob) {
|
||||
@@ -733,7 +734,7 @@ class ImageProcessingService {
|
||||
);
|
||||
}).toList();
|
||||
} catch (e) {
|
||||
print('Error detecting impacts from references: $e');
|
||||
debugPrint('Error detecting impacts from references: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -776,50 +777,6 @@ class ImageProcessingService {
|
||||
return merged;
|
||||
}
|
||||
|
||||
/// Detect dark spots with adaptive luminance range
|
||||
List<_Blob> _detectDarkSpotsAdaptive(
|
||||
img.Image image,
|
||||
int minLuminance,
|
||||
int maxLuminance,
|
||||
int minSize,
|
||||
int maxSize, {
|
||||
double minCircularity = 0.5,
|
||||
double minFillRatio = 0.5,
|
||||
}) {
|
||||
final width = image.width;
|
||||
final height = image.height;
|
||||
|
||||
// Create binary mask of pixels within luminance range
|
||||
final mask = List.generate(height, (_) => List.filled(width, false));
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
final pixel = image.getPixel(x, y);
|
||||
final luminance = img.getLuminance(pixel);
|
||||
mask[y][x] = luminance >= minLuminance && luminance <= maxLuminance;
|
||||
}
|
||||
}
|
||||
|
||||
// Find connected components
|
||||
final visited = List.generate(height, (_) => List.filled(width, false));
|
||||
final blobs = <_Blob>[];
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
if (mask[y][x] && !visited[y][x]) {
|
||||
final blob = _floodFill(mask, visited, x, y, width, height);
|
||||
if (blob.size >= minSize &&
|
||||
blob.size <= maxSize &&
|
||||
blob.circularity >= minCircularity &&
|
||||
blob.fillRatio >= minFillRatio) {
|
||||
blobs.add(blob);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _filterOverlappingBlobs(blobs);
|
||||
}
|
||||
|
||||
/// Detect dark spots in a grayscale image using blob detection
|
||||
List<_Blob> _detectDarkSpots(
|
||||
|
||||
Reference in New Issue
Block a user