From eb0634fab4a6ba287341fecffd2f8950c0fe2ba0 Mon Sep 17 00:00:00 2001 From: Jules Date: Wed, 15 Apr 2026 15:02:51 +0200 Subject: [PATCH] Fix captures 2/3 perdues + miroir + stabilite camera post-prise - post_capture_grace=10 : ignore les erreurs -52 transitoires juste apres une prise (Canon EOS a besoin ~1s pour stabiliser le capteur) - Threshold abandon capture : 3 -> 8 erreurs consecutives - Threshold reconnexion : 5 -> 10 erreurs consecutives - Avant chaque prise : eosviewfinder=1 pour garantir miroir leve - Apres prise : viewfinder relance + sleep 1s + drain 8 evenements - Sim auto-detect : pas de USB reset (evite boucle -52), verification fonctionnelle avec un capture_preview() avant de valider la camera - Sim poll : 15s au lieu de 10s Co-Authored-By: Claude Sonnet 4.6 --- photobooth_pygame.py | 105 ++++++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 35 deletions(-) diff --git a/photobooth_pygame.py b/photobooth_pygame.py index 057374c..a265fd3 100644 --- a/photobooth_pygame.py +++ b/photobooth_pygame.py @@ -753,22 +753,30 @@ class PB: # ── Thread caméra ──────────────────────────────────────────────────────── def _cam_loop(self): errs = 0 + post_capture_grace = 0 # frames de grâce après une prise (ignore erreurs transitoires) while True: - # En simulation : tentative de connexion automatique toutes les 10s + # En simulation : tentative de connexion automatique toutes les 15s + # Pas de USB reset ici — reset seulement en cas de reconnexion if self.sim: - time.sleep(10) - _usb_reset_done() + time.sleep(15) for _ in range(2): try: c = gp.Camera(); c.init() + # Vérification fonctionnelle : un preview doit réussir + _f = c.capture_preview(); _bytes = bytes(_f.get_data_and_size()) if self.cam: try: self.cam.exit() except: pass self.cam = c; self.sim = False; self.prev_actif = True + surf = pygame.image.load(io.BytesIO(_bytes)) + surf = pygame.transform.scale(surf, (W, H)) + with self.flock: self.frame = surf print("DSLR détecté automatiquement") break except Exception as e: print(f"Auto-detect caméra: {e}") + try: c.exit() + except: pass time.sleep(1) continue if self.prev_actif: @@ -776,8 +784,15 @@ class PB: if self.cam is None: raise RuntimeError("camera None") if self.cap_demande: - # Déclenchement sans mouvement miroir : - # eosremoterelease garde le LV actif sur Canon EOS + # Avant la prise : activer le viewfinder EOS (miroir levé, liveview ON) + try: + cfg_c = self.cam.get_config() + vf = cfg_c.get_child_by_name('eosviewfinder') + vf.set_value(1) + self.cam.set_config(cfg_c) + time.sleep(0.2) + except: pass + # Déclenchement obturateur seul via eosremoterelease triggered = False try: cfg_c = self.cam.get_config() @@ -805,45 +820,65 @@ class PB: rl.set_value('None') self.cam.set_config(cfg_c) except: pass + # Relance le viewfinder et laisse le capteur se stabiliser + try: + cfg_c = self.cam.get_config() + vf = cfg_c.get_child_by_name('eosviewfinder') + vf.set_value(1) + self.cam.set_config(cfg_c) + except: pass + time.sleep(1.0) # stabilisation capteur Canon entre deux prises + # Drainer les événements résiduels + for _ in range(8): + try: + self.cam.wait_for_event(50) + except: break self.cap_result=ch; self.cap_demande=False; self.cap_done.set() - errs = 0 + errs = 0; post_capture_grace = 10 else: f=self.cam.capture_preview(); data=bytes(f.get_data_and_size()) surf=pygame.image.load(io.BytesIO(data)) surf=pygame.transform.scale(surf,(W,H)) with self.flock: self.frame=surf errs = 0 + if post_capture_grace > 0: + post_capture_grace -= 1 except Exception as e: - errs += 1 - print(f"cam erreur ({errs}): {e}") - if self.cap_demande and errs >= 3: - # abandon de la capture en cours - self.cap_result=None; self.cap_demande=False; self.cap_done.set() - if errs >= 5: - # reconnexion automatique - print("Caméra perdue — tentative de reconnexion...") - self.prev_actif = False - with self.flock: self.frame = None - try: - if self.cam: self.cam.exit() - except: pass - self.cam = None; errs = 0 - for _nb_retry in range(10): - time.sleep(3) - _usb_reset_done() - try: - c = gp.Camera(); c.init() - self.cam = c; self.prev_actif = True - print("Caméra reconnectée automatiquement") - break - except Exception as re: - print(f"Reconnexion échouée ({_nb_retry+1}): {re}") - else: - # 10 tentatives échouées → bascule en simulation - self.sim = True - print("Caméra introuvable → mode simulation") + if post_capture_grace > 0: + # Erreurs transitoires post-capture normales sur EOS — on ignore + post_capture_grace -= 1 + print(f"cam post-capture ({post_capture_grace} restants): {e}") + time.sleep(0.2) else: - time.sleep(0.1) + errs += 1 + print(f"cam erreur ({errs}): {e}") + if self.cap_demande and errs >= 8: + # abandon de la capture seulement après 8 erreurs consécutives + self.cap_result=None; self.cap_demande=False; self.cap_done.set() + if errs >= 10: + # reconnexion automatique + print("Caméra perdue — tentative de reconnexion...") + self.prev_actif = False + with self.flock: self.frame = None + try: + if self.cam: self.cam.exit() + except: pass + self.cam = None; errs = 0 + for _nb_retry in range(10): + time.sleep(3) + _usb_reset_done() + try: + c = gp.Camera(); c.init() + self.cam = c; self.prev_actif = True + print("Caméra reconnectée automatiquement") + break + except Exception as re: + print(f"Reconnexion échouée ({_nb_retry+1}): {re}") + else: + self.sim = True + print("Caméra introuvable → mode simulation") + else: + time.sleep(0.2) else: time.sleep(0.05)