From 3ae9ceebc18f062b08e255813c4e5357292bac78 Mon Sep 17 00:00:00 2001 From: qguillaume Date: Fri, 5 Jun 2026 17:38:25 +0200 Subject: [PATCH] fix: lenteur de l appli capture screen --- lib/features/capture/capture_screen.dart | 115 +++++++++++++++++++++-- 1 file changed, 109 insertions(+), 6 deletions(-) diff --git a/lib/features/capture/capture_screen.dart b/lib/features/capture/capture_screen.dart index 2b68103c..b1fa3d8e 100644 --- a/lib/features/capture/capture_screen.dart +++ b/lib/features/capture/capture_screen.dart @@ -16,7 +16,8 @@ import '../session/session_provider.dart'; import 'widgets/image_source_button.dart'; import '../../services/image_crop_service.dart'; import '../../services/opencv_target_service.dart'; // AJOUT : Pour la détection périodique - +import 'package:image/image.dart' as img; +import 'package:path_provider/path_provider.dart'; class CaptureScreen extends StatefulWidget { const CaptureScreen({super.key}); @@ -120,11 +121,60 @@ class _CaptureScreenState extends State with SingleTickerProvider } } - // AJOUT : Démarre la détection périodique du parallélisme toutes les 2 secondes void _startAlignmentDetection() { _detectionTimer?.cancel(); - _detectionTimer = Timer.periodic(const Duration(seconds: 2), (_) { - _analyzeCurrentFrame(); + _detectionTimer = null; + + // OPTIMISATION : startImageStream au lieu de takePicture + // On analyse 1 frame toutes les 3 secondes via le stream natif + DateTime? _lastAnalysis; + + _cameraController!.startImageStream((CameraImage cameraImage) async { + if (_isAnalyzingFrame) return; + final now = DateTime.now(); + if (_lastAnalysis != null && + now.difference(_lastAnalysis!).inSeconds < 3) return; + _lastAnalysis = now; + _isAnalyzingFrame = true; + + try { + // Convertir la CameraImage en fichier temporaire pour OpenCV + final tempDir = await getTemporaryDirectory(); + final tempPath = + '${tempDir.path}/frame_analysis.jpg'; + + // Conversion YUV420 → JPEG via le package image + final img.Image? converted = _convertCameraImage(cameraImage); + if (converted == null) { + _isAnalyzingFrame = false; + return; + } + + await File(tempPath) + .writeAsBytes(img.encodeJpg(converted, quality: 60)); + + final result = await _opencvService.detectTarget(tempPath); + + try { await File(tempPath).delete(); } catch (_) {} + + if (mounted && _showLiveCamera) { + setState(() { + if (!result.success) { + _alignmentStatus = null; + } else { + final bool isCentered = + result.centerX > 0.25 && result.centerX < 0.75 && + result.centerY > 0.25 && result.centerY < 0.75; + final bool isSizedCorrectly = result.radius > 0.15; + _alignmentStatus = isCentered && isSizedCorrectly; + } + }); + } + } catch (e) { + debugPrint('Erreur analyse frame: $e'); + } finally { + _isAnalyzingFrame = false; + } }); } @@ -132,11 +182,64 @@ class _CaptureScreenState extends State with SingleTickerProvider void _stopAlignmentDetection() { _detectionTimer?.cancel(); _detectionTimer = null; + // AJOUT : Stopper le stream proprement + try { + if (_cameraController != null && + _cameraController!.value.isStreamingImages) { + _cameraController!.stopImageStream(); + } + } catch (_) {} _alignmentStatus = null; } + // AJOUT : Conversion CameraImage (YUV420) vers img.Image + img.Image? _convertCameraImage(CameraImage cameraImage) { + try { + final int width = cameraImage.width; + final int height = cameraImage.height; + + // Réduction de résolution pour l'analyse : on prend 1 pixel sur 2 + // (suffisant pour détecter les cercles, beaucoup plus rapide) + final int targetW = width ~/ 2; + final int targetH = height ~/ 2; + + final yPlane = cameraImage.planes[0]; + final uPlane = cameraImage.planes[1]; + final vPlane = cameraImage.planes[2]; + + final image = img.Image(width: targetW, height: targetH); + + for (int y = 0; y < targetH; y++) { + for (int x = 0; x < targetW; x++) { + final int srcX = x * 2; + final int srcY = y * 2; + + final int yIndex = srcY * yPlane.bytesPerRow + srcX; + final int uvIndex = + (srcY ~/ 2) * uPlane.bytesPerRow + (srcX ~/ 2) * uPlane.bytesPerPixel!; + + final int yVal = yPlane.bytes[yIndex]; + final int uVal = uPlane.bytes[uvIndex] - 128; + final int vVal = vPlane.bytes[uvIndex] - 128; + + // Conversion YUV → RGB + final int r = (yVal + 1.402 * vVal).clamp(0, 255).toInt(); + final int g = (yVal - 0.344136 * uVal - 0.714136 * vVal).clamp(0, 255).toInt(); + final int b = (yVal + 1.772 * uVal).clamp(0, 255).toInt(); + + image.setPixelRgb(x, y, r, g, b); + } + } + + return image; + } catch (e) { + debugPrint('Erreur conversion frame: $e'); + return null; + } + } + // AJOUT : Capture une frame et analyse le parallélisme via OpenCV - Future _analyzeCurrentFrame() async { + Future _analyzeCurrentFrame() async {/* // Verrou : on n'analyse pas si une analyse est déjà en cours if (_isAnalyzingFrame) return; if (_cameraController == null || !_cameraController!.value.isInitialized) return; @@ -177,7 +280,7 @@ class _CaptureScreenState extends State with SingleTickerProvider debugPrint('Erreur analyse frame: $e'); } finally { _isAnalyzingFrame = false; - } + }*/ } Future _handleGallerySelection() async {