desactivation de tous les scripts et ia, supression du modele yolo
This commit is contained in:
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"avdmanager.executable": "c:\\Users\\streaper2\\AppData\\Local\\Android\\Sdk\\cmdline-tools\\latest\\bin\\avdmanager.bat",
|
||||||
|
"avdmanager.sdkManager": "c:\\Users\\streaper2\\AppData\\Local\\Android\\Sdk\\cmdline-tools\\latest\\bin\\sdkmanager.bat"
|
||||||
|
}
|
||||||
BIN
analyze_output.txt
Normal file
BIN
analyze_output.txt
Normal file
Binary file not shown.
BIN
analyze_results_final.txt
Normal file
BIN
analyze_results_final.txt
Normal file
Binary file not shown.
37
analyze_results_fixed.txt
Normal file
37
analyze_results_fixed.txt
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
Analyzing bully...
|
||||||
|
|
||||||
|
info - Don't invoke 'print' in production code - lib\features\analysis\analysis_provider.dart:553:7 - avoid_print
|
||||||
|
info - The private field _selectedType could be 'final' - lib\features\capture\capture_screen.dart:27:14 - prefer_final_fields
|
||||||
|
info - 'scale' is deprecated and shouldn't be used. Use scaleByVector3, scaleByVector4, or scaleByDouble instead - lib\features\crop\crop_screen.dart:142:25 - deprecated_member_use
|
||||||
|
info - Statements in an if should be enclosed in a block - lib\services\distortion_correction_service.dart:566:11 - curly_braces_in_flow_control_structures
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\distortion_correction_service.dart:639:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\distortion_correction_service.dart:764:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\distortion_correction_service.dart:825:9 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\distortion_correction_service.dart:953:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\distortion_correction_service.dart:1015:9 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\distortion_correction_service.dart:1063:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:192:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:239:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:246:9 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:278:9 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:289:11 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:292:11 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:297:9 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:332:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:336:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:683:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:725:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:736:7 - avoid_print
|
||||||
|
warning - The declaration '_detectDarkSpotsAdaptive' isn't referenced - lib\services\image_processing_service.dart:780:15 - unused_element
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\target_detection_service.dart:328:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\target_detection_service.dart:377:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\target_detection_service.dart:414:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\yolo_impact_detection_service.dart:23:9 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\yolo_impact_detection_service.dart:29:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\yolo_impact_detection_service.dart:31:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\yolo_impact_detection_service.dart:67:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - tests\opencv_quad_test.dart:4:3 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - tests\opencv_quad_test.dart:5:3 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - tests\opencv_quad_test.dart:6:3 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - tests\test_homography.dart:4:3 - avoid_print
|
||||||
|
|
||||||
38
analyze_utf8.txt
Normal file
38
analyze_utf8.txt
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
Analyzing bully...
|
||||||
|
|
||||||
|
info - Don't invoke 'print' in production code - lib\features\analysis\analysis_provider.dart:392:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\features\analysis\analysis_provider.dart:596:7 - avoid_print
|
||||||
|
info - The private field _selectedType could be 'final' - lib\features\capture\capture_screen.dart:27:14 - prefer_final_fields
|
||||||
|
info - 'scale' is deprecated and shouldn't be used. Use scaleByVector3, scaleByVector4, or scaleByDouble instead - lib\features\crop\crop_screen.dart:142:25 - deprecated_member_use
|
||||||
|
info - Statements in an if should be enclosed in a block - lib\services\distortion_correction_service.dart:566:11 - curly_braces_in_flow_control_structures
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\distortion_correction_service.dart:639:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\distortion_correction_service.dart:764:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\distortion_correction_service.dart:825:9 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\distortion_correction_service.dart:953:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\distortion_correction_service.dart:1015:9 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\distortion_correction_service.dart:1063:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:192:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:239:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:246:9 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:278:9 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:289:11 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:292:11 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:297:9 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:332:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:336:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:683:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:725:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\image_processing_service.dart:736:7 - avoid_print
|
||||||
|
warning - The declaration '_detectDarkSpotsAdaptive' isn't referenced - lib\services\image_processing_service.dart:780:15 - unused_element
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\target_detection_service.dart:328:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\target_detection_service.dart:377:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\target_detection_service.dart:414:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\yolo_impact_detection_service.dart:23:9 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\yolo_impact_detection_service.dart:29:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\yolo_impact_detection_service.dart:31:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - lib\services\yolo_impact_detection_service.dart:67:7 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - tests\opencv_quad_test.dart:4:3 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - tests\opencv_quad_test.dart:5:3 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - tests\opencv_quad_test.dart:6:3 - avoid_print
|
||||||
|
info - Don't invoke 'print' in production code - tests\test_homography.dart:4:3 - avoid_print
|
||||||
|
|
||||||
@@ -35,6 +35,7 @@ android {
|
|||||||
// TODO: Add your own signing config for the release build.
|
// TODO: Add your own signing config for the release build.
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
|
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7
android/app/proguard-rules.pro
vendored
Normal file
7
android/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# TensorFlow Lite
|
||||||
|
-keep class org.tensorflow.lite.** { *; }
|
||||||
|
-keep class com.google.android.gms.tflite.** { *; }
|
||||||
|
-dontwarn org.tensorflow.lite.**
|
||||||
|
|
||||||
|
# Specifically for the GPU delegate error
|
||||||
|
-dontwarn org.tensorflow.lite.gpu.GpuDelegateFactory$Options
|
||||||
@@ -223,6 +223,16 @@ class AnalysisProvider extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update a shot's score manually
|
||||||
|
void updateShotScore(String shotId, int newScore) {
|
||||||
|
final index = _shots.indexWhere((shot) => shot.id == shotId);
|
||||||
|
if (index == -1) return;
|
||||||
|
|
||||||
|
_shots[index] = _shots[index].copyWith(score: newScore);
|
||||||
|
_recalculateScores();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
/// Auto-detect impacts using image processing
|
/// Auto-detect impacts using image processing
|
||||||
Future<int> autoDetectImpacts({
|
Future<int> autoDetectImpacts({
|
||||||
int darkThreshold = 80,
|
int darkThreshold = 80,
|
||||||
@@ -293,6 +303,8 @@ class AnalysisProvider extends ChangeNotifier {
|
|||||||
double param2 = 30,
|
double param2 = 30,
|
||||||
int minRadius = 5,
|
int minRadius = 5,
|
||||||
int maxRadius = 50,
|
int maxRadius = 50,
|
||||||
|
int minSize = 5,
|
||||||
|
int maxSize = 1000,
|
||||||
int blurSize = 5,
|
int blurSize = 5,
|
||||||
bool useContourDetection = true,
|
bool useContourDetection = true,
|
||||||
double minCircularity = 0.6,
|
double minCircularity = 0.6,
|
||||||
@@ -351,6 +363,47 @@ class AnalysisProvider extends ChangeNotifier {
|
|||||||
return detectedImpacts.length;
|
return detectedImpacts.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Auto-detect impacts using YOLOv8 model
|
||||||
|
Future<int> autoDetectImpactsWithYOLO({bool clearExisting = false}) async {
|
||||||
|
if (_imagePath == null || _targetType == null) return 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final detectedImpacts = await _detectionService.detectImpactsWithYOLO(
|
||||||
|
_imagePath!,
|
||||||
|
_targetType!,
|
||||||
|
_targetCenterX,
|
||||||
|
_targetCenterY,
|
||||||
|
_targetRadius,
|
||||||
|
_ringCount,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (clearExisting) {
|
||||||
|
_shots.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add detected impacts as shots
|
||||||
|
for (final impact in detectedImpacts) {
|
||||||
|
final shot = Shot(
|
||||||
|
id: _uuid.v4(),
|
||||||
|
x: impact.x,
|
||||||
|
y: impact.y,
|
||||||
|
score: impact.suggestedScore,
|
||||||
|
sessionId: '',
|
||||||
|
);
|
||||||
|
_shots.add(shot);
|
||||||
|
}
|
||||||
|
|
||||||
|
_recalculateScores();
|
||||||
|
_recalculateGrouping();
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
return detectedImpacts.length;
|
||||||
|
} catch (e) {
|
||||||
|
print('Error in YOLO auto-detection: $e');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Detect impacts with OpenCV using reference points
|
/// Detect impacts with OpenCV using reference points
|
||||||
Future<int> detectFromReferencesWithOpenCV({
|
Future<int> detectFromReferencesWithOpenCV({
|
||||||
double tolerance = 2.0,
|
double tolerance = 2.0,
|
||||||
|
|||||||
@@ -274,68 +274,7 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
|||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// Auto-calibrate button
|
|
||||||
SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: ElevatedButton.icon(
|
|
||||||
onPressed: () async {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Row(
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
strokeWidth: 2,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 12),
|
|
||||||
Text('Auto-calibration en cours...'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
duration: Duration(seconds: 2),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
final success = await provider
|
|
||||||
.autoCalibrateTarget();
|
|
||||||
|
|
||||||
if (context.mounted) {
|
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).hideCurrentSnackBar();
|
|
||||||
if (success) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'Cible calibrée automatiquement',
|
|
||||||
),
|
|
||||||
backgroundColor: AppTheme.successColor,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'Échec de la calibration auto',
|
|
||||||
),
|
|
||||||
backgroundColor: AppTheme.errorColor,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.auto_fix_high),
|
|
||||||
label: const Text('Auto-Calibrer la Cible'),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: Colors.deepPurple,
|
|
||||||
foregroundColor: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
// Ring count slider
|
// Ring count slider
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
@@ -387,57 +326,6 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// Target size slider
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
const Icon(
|
|
||||||
Icons.zoom_out_map,
|
|
||||||
color: Colors.white,
|
|
||||||
size: 20,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
const Text(
|
|
||||||
'Taille:',
|
|
||||||
style: TextStyle(color: Colors.white),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Slider(
|
|
||||||
value: provider.targetRadius.clamp(0.05, 3.0),
|
|
||||||
min: 0.05,
|
|
||||||
max: 3.0,
|
|
||||||
label:
|
|
||||||
'${(provider.targetRadius * 100).toStringAsFixed(0)}%',
|
|
||||||
activeColor: AppTheme.warningColor,
|
|
||||||
onChanged: (value) {
|
|
||||||
provider.adjustTargetPosition(
|
|
||||||
provider.targetCenterX,
|
|
||||||
provider.targetCenterY,
|
|
||||||
provider.targetInnerRadius,
|
|
||||||
value,
|
|
||||||
ringCount: provider.ringCount,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 12,
|
|
||||||
vertical: 4,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: AppTheme.warningColor,
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
'${(provider.targetRadius * 100).toStringAsFixed(0)}%',
|
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const Divider(color: Colors.white24, height: 16),
|
const Divider(color: Colors.white24, height: 16),
|
||||||
// Distortion correction row
|
// Distortion correction row
|
||||||
/*Row(
|
/*Row(
|
||||||
@@ -793,6 +681,7 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
|||||||
),
|
),
|
||||||
// Overlay qui se transforme avec l'image
|
// Overlay qui se transforme avec l'image
|
||||||
TargetOverlay(
|
TargetOverlay(
|
||||||
|
showRings: true,
|
||||||
shots: provider.shots,
|
shots: provider.shots,
|
||||||
targetCenterX: provider.targetCenterX,
|
targetCenterX: provider.targetCenterX,
|
||||||
targetCenterY: provider.targetCenterY,
|
targetCenterY: provider.targetCenterY,
|
||||||
@@ -879,6 +768,7 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
|||||||
),
|
),
|
||||||
// Overlay qui se transforme avec l'image
|
// Overlay qui se transforme avec l'image
|
||||||
TargetOverlay(
|
TargetOverlay(
|
||||||
|
showRings: true,
|
||||||
shots: provider.shots,
|
shots: provider.shots,
|
||||||
targetCenterX: provider.targetCenterX,
|
targetCenterX: provider.targetCenterX,
|
||||||
targetCenterY: provider.targetCenterY,
|
targetCenterY: provider.targetCenterY,
|
||||||
@@ -991,107 +881,7 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildActionButtons(BuildContext context, AnalysisProvider provider) {
|
Widget _buildActionButtons(BuildContext context, AnalysisProvider provider) {
|
||||||
return Column(
|
return const SizedBox.shrink();
|
||||||
children: [
|
|
||||||
// Reference-based detection section
|
|
||||||
if (_isSelectingReferences) ...[
|
|
||||||
Card(
|
|
||||||
color: Colors.deepPurple.withValues(alpha: 0.1),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(12),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.touch_app, color: Colors.deepPurple),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Text(
|
|
||||||
'${provider.referenceImpacts.length} reference(s) selectionnee(s)',
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
const Text(
|
|
||||||
'Touchez l\'image pour marquer 3-4 impacts de reference. '
|
|
||||||
'L\'algorithme apprendra leurs caracteristiques pour detecter les autres.',
|
|
||||||
style: TextStyle(fontSize: 12, color: Colors.grey),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: OutlinedButton(
|
|
||||||
onPressed: () {
|
|
||||||
setState(() => _isSelectingReferences = false);
|
|
||||||
provider.clearReferenceImpacts();
|
|
||||||
},
|
|
||||||
child: const Text('Annuler'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
Expanded(
|
|
||||||
child: ElevatedButton.icon(
|
|
||||||
onPressed: provider.referenceImpacts.length >= 2
|
|
||||||
? () => _showCalibratedDetectionDialog(
|
|
||||||
context,
|
|
||||||
provider,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
icon: const Icon(Icons.auto_fix_high),
|
|
||||||
label: const Text('Detecter'),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: Colors.deepPurple,
|
|
||||||
foregroundColor: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
] else ...[
|
|
||||||
// désactiver le temps de l'amelioration du scripts d'auto-detection
|
|
||||||
// Auto-detect buttons row
|
|
||||||
// Row(
|
|
||||||
// children: [
|
|
||||||
// Expanded(
|
|
||||||
// child: ElevatedButton.icon(
|
|
||||||
// onPressed: () => _showAutoDetectDialog(context, provider),
|
|
||||||
// icon: const Icon(Icons.auto_fix_high),
|
|
||||||
// label: const Text('Auto-Detection'),
|
|
||||||
// style: ElevatedButton.styleFrom(
|
|
||||||
// backgroundColor: AppTheme.primaryColor,
|
|
||||||
// foregroundColor: Colors.white,
|
|
||||||
// padding: const EdgeInsets.symmetric(vertical: 12),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// const SizedBox(width: 12),
|
|
||||||
// Expanded(
|
|
||||||
// child: ElevatedButton.icon(
|
|
||||||
// onPressed: () => setState(() => _isSelectingReferences = true),
|
|
||||||
// icon: const Icon(Icons.touch_app),
|
|
||||||
// label: const Text('Par Reference'),
|
|
||||||
// style: ElevatedButton.styleFrom(
|
|
||||||
// backgroundColor: Colors.deepPurple,
|
|
||||||
// foregroundColor: Colors.white,
|
|
||||||
// padding: const EdgeInsets.symmetric(vertical: 12),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
],
|
|
||||||
|
|
||||||
// Manual actions
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showHelpDialog(BuildContext context) {
|
void _showHelpDialog(BuildContext context) {
|
||||||
@@ -1129,21 +919,68 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
|||||||
AnalysisProvider provider,
|
AnalysisProvider provider,
|
||||||
String shotId,
|
String shotId,
|
||||||
) {
|
) {
|
||||||
|
final shot = provider.shots.firstWhere((s) => s.id == shotId);
|
||||||
|
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||||
|
),
|
||||||
builder: (context) => SafeArea(
|
builder: (context) => SafeArea(
|
||||||
child: Wrap(
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(20.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
ListTile(
|
Text(
|
||||||
leading: const Icon(Icons.delete, color: AppTheme.errorColor),
|
'Modifier l\'impact',
|
||||||
title: const Text('Supprimer cet impact'),
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
onTap: () {
|
),
|
||||||
provider.removeShot(shotId);
|
const SizedBox(height: 20),
|
||||||
|
// Dropdown for score
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Text('Valeur de l\'impact : ', style: TextStyle(fontSize: 16)),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
DropdownButton<int>(
|
||||||
|
value: shot.score.clamp(0, 10),
|
||||||
|
items: List.generate(11, (i) => i).map((i) {
|
||||||
|
return DropdownMenuItem<int>(
|
||||||
|
value: i,
|
||||||
|
child: Text(i == 10 && provider.targetType == TargetType.concentric ? '10 (X)' : '$i'),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (newScore) {
|
||||||
|
if (newScore != null) {
|
||||||
|
provider.updateShotScore(shotId, newScore);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
// Delete button at the bottom
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
onPressed: () {
|
||||||
|
provider.removeShot(shotId);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.delete),
|
||||||
|
label: const Text('SUPPRIMER L\'IMPACT'),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: AppTheme.errorColor,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1187,7 +1024,7 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
void _showAutoDetectDialog(BuildContext context, AnalysisProvider provider) {
|
void _showAutoDetectDialog(BuildContext context, AnalysisProvider provider) {
|
||||||
// Detection settings
|
// Detection settings
|
||||||
bool clearExisting = true;
|
bool clearExisting = true;
|
||||||
@@ -1197,9 +1034,6 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
|||||||
int maxImpactSize = 500;
|
int maxImpactSize = 500;
|
||||||
double minFillRatio = 0.5;
|
double minFillRatio = 0.5;
|
||||||
|
|
||||||
// NOTE: OpenCV désactivé - problèmes de build Windows
|
|
||||||
// Utilisation de la détection classique uniquement
|
|
||||||
|
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => StatefulBuilder(
|
builder: (context) => StatefulBuilder(
|
||||||
@@ -1216,11 +1050,78 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
// YOLO option button
|
||||||
|
Card(
|
||||||
|
color: AppTheme.primaryColor.withAlpha(25),
|
||||||
|
child: ListTile(
|
||||||
|
leading: const Icon(Icons.psychology, color: AppTheme.primaryColor),
|
||||||
|
title: const Text('IA Detection (YOLOv8)', style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
|
subtitle: const Text('Détection intelligente via modèle entraîné'),
|
||||||
|
onTap: () async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 2,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 12),
|
||||||
|
Text('Détection IA en cours...'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
duration: Duration(seconds: 10),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final count = await provider.autoDetectImpactsWithYOLO(
|
||||||
|
clearExisting: clearExisting,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
count > 0
|
||||||
|
? '$count impact(s) détecté(s) par l\'IA'
|
||||||
|
: 'Aucun impact détecté par l\'IA.',
|
||||||
|
),
|
||||||
|
backgroundColor: count > 0
|
||||||
|
? AppTheme.successColor
|
||||||
|
: AppTheme.warningColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 12),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(child: Divider()),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: Text('OU', style: TextStyle(color: Colors.grey, fontSize: 12)),
|
||||||
|
),
|
||||||
|
Expanded(child: Divider()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
const Text(
|
const Text(
|
||||||
'Ajustez les parametres de detection:',
|
'Détection Classique (Paramétrable):',
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 8),
|
||||||
|
|
||||||
// Dark threshold slider
|
// Dark threshold slider
|
||||||
Text('Seuil de detection (zones sombres): $darkThreshold'),
|
Text('Seuil de detection (zones sombres): $darkThreshold'),
|
||||||
@@ -1379,14 +1280,13 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.search),
|
icon: const Icon(Icons.search),
|
||||||
label: const Text('Detecter'),
|
label: const Text('Détecter (Classique)'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
void _showCalibratedDetectionDialog(
|
void _showCalibratedDetectionDialog(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class TargetOverlay extends StatelessWidget {
|
|||||||
final double? groupingDiameter;
|
final double? groupingDiameter;
|
||||||
final List<Shot>? referenceImpacts;
|
final List<Shot>? referenceImpacts;
|
||||||
final double zoomScale;
|
final double zoomScale;
|
||||||
|
final bool showRings;
|
||||||
|
|
||||||
const TargetOverlay({
|
const TargetOverlay({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -42,6 +43,7 @@ class TargetOverlay extends StatelessWidget {
|
|||||||
this.groupingDiameter,
|
this.groupingDiameter,
|
||||||
this.referenceImpacts,
|
this.referenceImpacts,
|
||||||
this.zoomScale = 1.0,
|
this.zoomScale = 1.0,
|
||||||
|
this.showRings = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -72,6 +74,7 @@ class TargetOverlay extends StatelessWidget {
|
|||||||
groupingDiameter: groupingDiameter,
|
groupingDiameter: groupingDiameter,
|
||||||
referenceImpacts: referenceImpacts,
|
referenceImpacts: referenceImpacts,
|
||||||
zoomScale: zoomScale,
|
zoomScale: zoomScale,
|
||||||
|
showRings: showRings,
|
||||||
),
|
),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: shots.map((shot) {
|
children: shots.map((shot) {
|
||||||
@@ -132,6 +135,7 @@ class _TargetOverlayPainter extends CustomPainter {
|
|||||||
final double? groupingDiameter;
|
final double? groupingDiameter;
|
||||||
final List<Shot>? referenceImpacts;
|
final List<Shot>? referenceImpacts;
|
||||||
final double zoomScale;
|
final double zoomScale;
|
||||||
|
final bool showRings;
|
||||||
|
|
||||||
_TargetOverlayPainter({
|
_TargetOverlayPainter({
|
||||||
required this.shots,
|
required this.shots,
|
||||||
@@ -146,12 +150,15 @@ class _TargetOverlayPainter extends CustomPainter {
|
|||||||
this.groupingDiameter,
|
this.groupingDiameter,
|
||||||
this.referenceImpacts,
|
this.referenceImpacts,
|
||||||
this.zoomScale = 1.0,
|
this.zoomScale = 1.0,
|
||||||
|
this.showRings = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
// Draw target center indicator
|
// Draw target center indicator
|
||||||
|
if (showRings) {
|
||||||
_drawTargetCenter(canvas, size);
|
_drawTargetCenter(canvas, size);
|
||||||
|
}
|
||||||
|
|
||||||
// Draw grouping circle
|
// Draw grouping circle
|
||||||
if (groupingCenterX != null && groupingCenterY != null && groupingDiameter != null && shots.length > 1) {
|
if (groupingCenterX != null && groupingCenterY != null && groupingDiameter != null && shots.length > 1) {
|
||||||
@@ -371,6 +378,7 @@ class _TargetOverlayPainter extends CustomPainter {
|
|||||||
groupingCenterY != oldDelegate.groupingCenterY ||
|
groupingCenterY != oldDelegate.groupingCenterY ||
|
||||||
groupingDiameter != oldDelegate.groupingDiameter ||
|
groupingDiameter != oldDelegate.groupingDiameter ||
|
||||||
referenceImpacts != oldDelegate.referenceImpacts ||
|
referenceImpacts != oldDelegate.referenceImpacts ||
|
||||||
zoomScale != oldDelegate.zoomScale;
|
zoomScale != oldDelegate.zoomScale ||
|
||||||
|
showRings != oldDelegate.showRings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -392,7 +392,11 @@ class TargetDetectionService {
|
|||||||
final impacts = await _yoloService.detectImpacts(imagePath);
|
final impacts = await _yoloService.detectImpacts(imagePath);
|
||||||
|
|
||||||
return impacts.map((impact) {
|
return impacts.map((impact) {
|
||||||
final score = targetType == TargetType.concentric
|
// Use YOLO-detected score (valeur) if available, otherwise calculate it
|
||||||
|
int score = impact.suggestedScore;
|
||||||
|
|
||||||
|
if (score <= 0) {
|
||||||
|
score = targetType == TargetType.concentric
|
||||||
? _calculateConcentricScoreWithRings(
|
? _calculateConcentricScoreWithRings(
|
||||||
impact.x,
|
impact.x,
|
||||||
impact.y,
|
impact.y,
|
||||||
@@ -402,6 +406,7 @@ class TargetDetectionService {
|
|||||||
ringCount,
|
ringCount,
|
||||||
)
|
)
|
||||||
: _calculateSilhouetteScore(impact.x, impact.y, centerX, centerY);
|
: _calculateSilhouetteScore(impact.x, impact.y, centerX, centerY);
|
||||||
|
}
|
||||||
|
|
||||||
return DetectedImpactResult(
|
return DetectedImpactResult(
|
||||||
x: impact.x,
|
x: impact.x,
|
||||||
|
|||||||
@@ -7,25 +7,41 @@ import 'target_detection_service.dart';
|
|||||||
|
|
||||||
class YOLOImpactDetectionService {
|
class YOLOImpactDetectionService {
|
||||||
Interpreter? _interpreter;
|
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';
|
static const String labelsPath = 'assets/models/labels.txt';
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
if (_interpreter != null) return;
|
if (_interpreter != null) return;
|
||||||
|
|
||||||
try {
|
|
||||||
// Try loading the specific YOLOv11 model first, fallback to v8 if not found
|
|
||||||
try {
|
try {
|
||||||
_interpreter = await Interpreter.fromAsset(modelPath);
|
_interpreter = await Interpreter.fromAsset(modelPath);
|
||||||
} catch (e) {
|
|
||||||
print('YOLOv11 model not found at $modelPath, trying YOLOv8 fallback');
|
// Get model metadata
|
||||||
_interpreter = await Interpreter.fromAsset(
|
final inputTensors = _interpreter!.getInputTensors();
|
||||||
'assets/models/yolov8n_impact.tflite',
|
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('YOLO Interpreter loaded successfully');
|
||||||
|
print('Model Input Size: $_inputSize');
|
||||||
|
print('Model Output Shape: $_outputShape (Classes: $_numClasses)');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error loading YOLO model: $e');
|
print('Error loading YOLO model: $e');
|
||||||
}
|
}
|
||||||
@@ -37,31 +53,35 @@ class YOLOImpactDetectionService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final bytes = File(imagePath).readAsBytesSync();
|
final bytes = File(imagePath).readAsBytesSync();
|
||||||
final originalImage = img.decodeImage(bytes);
|
final decodedImage = img.decodeImage(bytes);
|
||||||
if (originalImage == null) return [];
|
if (decodedImage == null) return [];
|
||||||
|
|
||||||
|
final originalImage = img.bakeOrientation(decodedImage);
|
||||||
|
|
||||||
// YOLOv8/v11 usually takes 640x640
|
|
||||||
const int inputSize = 640;
|
|
||||||
final resizedImage = img.copyResize(
|
final resizedImage = img.copyResize(
|
||||||
originalImage,
|
originalImage,
|
||||||
width: inputSize,
|
width: _inputSize,
|
||||||
height: inputSize,
|
height: _inputSize,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Prepare input tensor
|
var input = _imageToByteListFloat32(resizedImage, _inputSize);
|
||||||
var input = _imageToByteListFloat32(resizedImage, inputSize);
|
|
||||||
|
|
||||||
// Raw YOLO output shape usually [1, 4 + num_classes, 8400]
|
// Allocate output buffer dynamically
|
||||||
// For single class "impact", it's [1, 5, 8400]
|
var output = List<double>.filled(
|
||||||
var output = List<double>.filled(1 * 5 * 8400, 0).reshape([1, 5, 8400]);
|
_outputShape.fold(1, (a, b) => a * b),
|
||||||
|
0
|
||||||
|
).reshape(_outputShape);
|
||||||
|
|
||||||
_interpreter!.run(input, output);
|
_interpreter!.run(input, output);
|
||||||
|
|
||||||
return _processOutput(
|
final results = _processOutput(
|
||||||
output[0],
|
output[0],
|
||||||
originalImage.width,
|
originalImage.width,
|
||||||
originalImage.height,
|
originalImage.height,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
print('YOLO Detection result count: ${results.length}');
|
||||||
|
return results;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error during YOLO inference: $e');
|
print('Error during YOLO inference: $e');
|
||||||
return [];
|
return [];
|
||||||
@@ -76,33 +96,55 @@ class YOLOImpactDetectionService {
|
|||||||
final List<_Detection> candidates = [];
|
final List<_Detection> candidates = [];
|
||||||
const double threshold = 0.25;
|
const double threshold = 0.25;
|
||||||
|
|
||||||
// output is [5, 8400] -> [x, y, w, h, conf]
|
// output is typically [4 + numClasses, numBoxes]
|
||||||
for (int i = 0; i < 8400; i++) {
|
final int rows = output.length;
|
||||||
final double confidence = output[4][i];
|
final int numBoxes = output[0].length;
|
||||||
if (confidence > threshold) {
|
|
||||||
|
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(
|
candidates.add(
|
||||||
_Detection(
|
_Detection(
|
||||||
x: output[0][i],
|
// Use dynamic mapping: 0,1,2,3 are typically x,y,w,h
|
||||||
y: output[1][i],
|
// 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],
|
w: output[2][i],
|
||||||
h: output[3][i],
|
h: output[3][i],
|
||||||
confidence: confidence,
|
confidence: maxConfidence,
|
||||||
|
classIndex: classIndex,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply Non-Max Suppression (NMS)
|
|
||||||
final List<_Detection> suppressed = _nms(candidates);
|
final List<_Detection> suppressed = _nms(candidates);
|
||||||
|
|
||||||
return suppressed
|
return suppressed
|
||||||
.map(
|
.map(
|
||||||
(det) => DetectedImpactResult(
|
(det) {
|
||||||
x: det.x / 640.0,
|
// Score = ClassIndex (0 to 10) for impact models
|
||||||
y: det.y / 640.0,
|
int score = det.classIndex;
|
||||||
|
|
||||||
|
return DetectedImpactResult(
|
||||||
|
x: det.x,
|
||||||
|
y: det.y,
|
||||||
radius: 5.0,
|
radius: 5.0,
|
||||||
suggestedScore: 0,
|
suggestedScore: score,
|
||||||
),
|
);
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
@@ -110,7 +152,6 @@ class YOLOImpactDetectionService {
|
|||||||
List<_Detection> _nms(List<_Detection> detections) {
|
List<_Detection> _nms(List<_Detection> detections) {
|
||||||
if (detections.isEmpty) return [];
|
if (detections.isEmpty) return [];
|
||||||
|
|
||||||
// Sort by confidence descending
|
|
||||||
detections.sort((a, b) => b.confidence.compareTo(a.confidence));
|
detections.sort((a, b) => b.confidence.compareTo(a.confidence));
|
||||||
|
|
||||||
final List<_Detection> selected = [];
|
final List<_Detection> selected = [];
|
||||||
@@ -164,11 +205,13 @@ class YOLOImpactDetectionService {
|
|||||||
|
|
||||||
class _Detection {
|
class _Detection {
|
||||||
final double x, y, w, h, confidence;
|
final double x, y, w, h, confidence;
|
||||||
|
final int classIndex;
|
||||||
_Detection({
|
_Detection({
|
||||||
required this.x,
|
required this.x,
|
||||||
required this.y,
|
required this.y,
|
||||||
required this.w,
|
required this.w,
|
||||||
required this.h,
|
required this.h,
|
||||||
required this.confidence,
|
required this.confidence,
|
||||||
|
required this.classIndex,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -665,10 +665,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: tflite_flutter
|
name: tflite_flutter
|
||||||
sha256: ffb8651fdb116ab0131d6dc47ff73883e0f634ad1ab12bb2852eef1bbeab4a6a
|
sha256: "48e6fde2ad97162bb66a16a142f4c4698add9e8cd397ce9d1cc7451b55537ac1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.10.4"
|
version: "0.11.0"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ dependencies:
|
|||||||
image: ^4.1.7
|
image: ^4.1.7
|
||||||
|
|
||||||
# Machine Learning for YOLOv8
|
# Machine Learning for YOLOv8
|
||||||
tflite_flutter: ^0.10.4
|
tflite_flutter: ^0.11.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@@ -90,7 +90,8 @@ flutter:
|
|||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
# assets:
|
assets:
|
||||||
|
- assets/models/yolov8n_32.tflite
|
||||||
# - images/a_dot_burr.jpeg
|
# - images/a_dot_burr.jpeg
|
||||||
# - images/a_dot_ham.jpeg
|
# - images/a_dot_ham.jpeg
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user