# Reconnaissance CRNN (`app/recognizer.py`) ## Le modèle `crnn_vgg16_bn` (bibliothèque [doctr](https://github.com/mindee/doctr)) : un CNN (VGG16) qui extrait des features le long de l'image, suivi d'un RNN qui prédit une séquence de caractères — architecture standard pour la reconnaissance de texte en une ligne (pas besoin de segmenter les caractères un par un). Poids de départ : pré-entraînés par Mindee sur des textes imprimés génériques, puis **fine-tunés** sur nos propres crops de lignes LCD (voir `docs/TRAINING.md`). C'est ce fine-tuning qui constitue le "modèle IA développé" attendu par le §8.4 du cahier des charges, par opposition à un OCR générique utilisé tel quel. ## `load_model(model_path=None, device=None)` Charge les poids depuis `models/crnn_fuel_pump_best.pt` (chemin par défaut). Échoue explicitement (`FileNotFoundError`/`ImportError`) plutôt que de se rabattre silencieusement sur autre chose — un module de vérification de paiement ne doit pas tourner avec un modèle absent sans que ce soit visible. ## `recognize_screen(model, screen_crop, device, n_lines=3)` 1. Découpe l'écran en lignes (`preprocessing.split_lcd_lines`). 2. Pour chaque ligne, dans l'ordre : prétraitement (`preprocess_crop`) puis prédiction (`predict_line`). 3. Associe chaque ligne à un champ (`prix`, `volume`, `prix_litre`) par sa **position** (voir `FIELD_NAMES` dans `preprocessing.py`) — pas par analyse du contenu. C'est la différence clé avec l'ancien pipeline OCR générique, qui devait deviner quel nombre était quoi. Retourne une liste de `{"field": ..., "text": ..., "confidence": ...}`, un élément par ligne détectée. ## `preprocess_crop` / `_resize_preserve_aspect` — le bug corrigé cette session Redimensionne chaque ligne à une hauteur fixe (32px) **en conservant le ratio d'aspect**, puis normalise les valeurs de pixels. **Pourquoi c'est écrit deux fois** (ici et dans `train/finetune_doctr.py`) : le modèle doit voir, à l'entraînement et à l'inférence, des images prétraitées de la **même façon**. Avant correction, l'entraînement étirait les images à une largeur fixe (déformant les chiffres), alors que l'inférence préservait le ratio — le modèle apprenait donc sur des formes différentes de celles qu'il voyait réellement en production. Si l'un des deux fichiers est modifié à l'avenir, vérifier que l'autre reste cohérent. ## Limites connues - Le decoder CTC de doctr peut produire des caractères hors du vocabulaire numérique attendu (ex. "9AAm" au lieu de "20000" observé pendant les tests) quand la ligne d'entrée est trop bruitée/mal découpée — normal vu la taille du jeu d'entraînement (voir `docs/LIMITATIONS.md`), pas un bug de code. - Aucune contrainte n'est imposée sur le vocabulaire de sortie (le modèle pourrait techniquement prédire des lettres) — une piste d'amélioration serait de contraindre le décodage aux chiffres/virgule/point uniquement.