desactivation de tous les scripts et ia, supression du modele yolo
This commit is contained in:
@@ -223,6 +223,16 @@ class AnalysisProvider extends ChangeNotifier {
|
||||
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
|
||||
Future<int> autoDetectImpacts({
|
||||
int darkThreshold = 80,
|
||||
@@ -293,6 +303,8 @@ class AnalysisProvider extends ChangeNotifier {
|
||||
double param2 = 30,
|
||||
int minRadius = 5,
|
||||
int maxRadius = 50,
|
||||
int minSize = 5,
|
||||
int maxSize = 1000,
|
||||
int blurSize = 5,
|
||||
bool useContourDetection = true,
|
||||
double minCircularity = 0.6,
|
||||
@@ -351,6 +363,47 @@ class AnalysisProvider extends ChangeNotifier {
|
||||
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
|
||||
Future<int> detectFromReferencesWithOpenCV({
|
||||
double tolerance = 2.0,
|
||||
|
||||
@@ -274,68 +274,7 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
||||
),
|
||||
child: Column(
|
||||
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
|
||||
Row(
|
||||
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),
|
||||
// Distortion correction row
|
||||
/*Row(
|
||||
@@ -793,6 +681,7 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
||||
),
|
||||
// Overlay qui se transforme avec l'image
|
||||
TargetOverlay(
|
||||
showRings: true,
|
||||
shots: provider.shots,
|
||||
targetCenterX: provider.targetCenterX,
|
||||
targetCenterY: provider.targetCenterY,
|
||||
@@ -879,6 +768,7 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
||||
),
|
||||
// Overlay qui se transforme avec l'image
|
||||
TargetOverlay(
|
||||
showRings: true,
|
||||
shots: provider.shots,
|
||||
targetCenterX: provider.targetCenterX,
|
||||
targetCenterY: provider.targetCenterY,
|
||||
@@ -991,107 +881,7 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
||||
}
|
||||
|
||||
Widget _buildActionButtons(BuildContext context, AnalysisProvider provider) {
|
||||
return Column(
|
||||
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
|
||||
],
|
||||
);
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
void _showHelpDialog(BuildContext context) {
|
||||
@@ -1129,20 +919,67 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
||||
AnalysisProvider provider,
|
||||
String shotId,
|
||||
) {
|
||||
final shot = provider.shots.firstWhere((s) => s.id == shotId);
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||
),
|
||||
builder: (context) => SafeArea(
|
||||
child: Wrap(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const Icon(Icons.delete, color: AppTheme.errorColor),
|
||||
title: const Text('Supprimer cet impact'),
|
||||
onTap: () {
|
||||
provider.removeShot(shotId);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'Modifier l\'impact',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
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);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
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) {
|
||||
// Detection settings
|
||||
bool clearExisting = true;
|
||||
@@ -1197,9 +1034,6 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
||||
int maxImpactSize = 500;
|
||||
double minFillRatio = 0.5;
|
||||
|
||||
// NOTE: OpenCV désactivé - problèmes de build Windows
|
||||
// Utilisation de la détection classique uniquement
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => StatefulBuilder(
|
||||
@@ -1216,11 +1050,78 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
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(
|
||||
'Ajustez les parametres de detection:',
|
||||
'Détection Classique (Paramétrable):',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Dark threshold slider
|
||||
Text('Seuil de detection (zones sombres): $darkThreshold'),
|
||||
@@ -1379,14 +1280,13 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.search),
|
||||
label: const Text('Detecter'),
|
||||
label: const Text('Détecter (Classique)'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
||||
void _showCalibratedDetectionDialog(
|
||||
BuildContext context,
|
||||
|
||||
@@ -25,6 +25,7 @@ class TargetOverlay extends StatelessWidget {
|
||||
final double? groupingDiameter;
|
||||
final List<Shot>? referenceImpacts;
|
||||
final double zoomScale;
|
||||
final bool showRings;
|
||||
|
||||
const TargetOverlay({
|
||||
super.key,
|
||||
@@ -42,6 +43,7 @@ class TargetOverlay extends StatelessWidget {
|
||||
this.groupingDiameter,
|
||||
this.referenceImpacts,
|
||||
this.zoomScale = 1.0,
|
||||
this.showRings = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -72,6 +74,7 @@ class TargetOverlay extends StatelessWidget {
|
||||
groupingDiameter: groupingDiameter,
|
||||
referenceImpacts: referenceImpacts,
|
||||
zoomScale: zoomScale,
|
||||
showRings: showRings,
|
||||
),
|
||||
child: Stack(
|
||||
children: shots.map((shot) {
|
||||
@@ -132,6 +135,7 @@ class _TargetOverlayPainter extends CustomPainter {
|
||||
final double? groupingDiameter;
|
||||
final List<Shot>? referenceImpacts;
|
||||
final double zoomScale;
|
||||
final bool showRings;
|
||||
|
||||
_TargetOverlayPainter({
|
||||
required this.shots,
|
||||
@@ -146,12 +150,15 @@ class _TargetOverlayPainter extends CustomPainter {
|
||||
this.groupingDiameter,
|
||||
this.referenceImpacts,
|
||||
this.zoomScale = 1.0,
|
||||
this.showRings = false,
|
||||
});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
// Draw target center indicator
|
||||
_drawTargetCenter(canvas, size);
|
||||
if (showRings) {
|
||||
_drawTargetCenter(canvas, size);
|
||||
}
|
||||
|
||||
// Draw grouping circle
|
||||
if (groupingCenterX != null && groupingCenterY != null && groupingDiameter != null && shots.length > 1) {
|
||||
@@ -371,6 +378,7 @@ class _TargetOverlayPainter extends CustomPainter {
|
||||
groupingCenterY != oldDelegate.groupingCenterY ||
|
||||
groupingDiameter != oldDelegate.groupingDiameter ||
|
||||
referenceImpacts != oldDelegate.referenceImpacts ||
|
||||
zoomScale != oldDelegate.zoomScale;
|
||||
zoomScale != oldDelegate.zoomScale ||
|
||||
showRings != oldDelegate.showRings;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user