Détection de codes-barres et QR codes en temps réel avec OpenCV et pyzbar

Prérequis système

La lecture automatisée de codes-barres et de QR codes constitue un mécanisme fondamental dans de nombreuses applications industrielles et grand public. Pour mettre en place un scanner optique fonctionnel en Python, l'association de la bibliothèque de vision par ordinateur OpenCV avec le décodeur pyzbar offre une soltuion robuste. Avant d'initialiser le flux vidéo, il convient d'installer les dépendances nécessaires via le gestionnaire de paquets Python :

pip install opencv-python pyzbar numpy

Note : Sur certains systèmes d'exploitation comme Linux, l'installation de la bibliothèque native zbar (par exemple via sudo apt-get install libzbar0) peut être requise pour que pyzbar fonctionne correctement.

Architecture du script de détection

Pour garantir une gestion propre des ressources matérielles et une lisibilité optimale, l'implémentation suivante adopte une approche procédurale. Le script capture le flux de la webcam, analyse chaque image pour y déceler des motifs de codes, et superpose dynamiquement les informations décodées.

import cv2
import numpy as np
from pyzbar.pyzbar import decode

def initialize_scanner():
    """
    Configure le flux vidéo et lance la boucle d'analyse.
    """
    # Ouverture du périphérique de capture par défaut
    video_stream = cv2.VideoCapture(0)
    
    # Définition explicite de la résolution HD
    video_stream.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
    video_stream.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

    if not video_stream.isOpened():
        raise RuntimeError("Échec de l'initialisation de la caméra.")

    try:
        while True:
            is_valid, current_frame = video_stream.read()
            if not is_valid:
                print("Interruption du flux vidéo.")
                break

            # Identification des codes présents dans l'image courante
            scanned_items = decode(current_frame)

            for item in scanned_items:
                # Extraction des métadonnées et conversion de l'encodage
                decoded_text = item.data.decode('utf-8')
                code_category = item.type
                
                # Journalisation des informations dans la console
                print(f"Type: {code_category} | Valeur: {decoded_text} | Qualité: {item.quality}")

                # Récupération des sommets du polygone englobant
                contour_points = item.polygon
                
                # Tracé du cadre autour du code détecté
                if len(contour_points) == 4:
                    vertices = np.array([np.int32(contour_points)])
                    cv2.polylines(
                        current_frame, 
                        [vertices], 
                        isClosed=True, 
                        color=(0, 200, 100), # Couleur verte au format BGR
                        thickness=2
                    )

                # Calcul de la position pour l'affichage du texte
                x, y, width, height = item.rect
                text_position = (x, max(10, y - 15)) # Décalage vers le haut avec limite minimale

                # Incrustation du résultat décodé sur l'image
                cv2.putText(
                    img=current_frame,
                    text=decoded_text,
                    org=text_position,
                    fontFace=cv2.FONT_HERSHEY_TRIPLEX,
                    fontScale=0.6,
                    color=(0, 200, 100),
                    thickness=2,
                    lineType=cv2.LINE_AA
                )

            # Affichage de la fenêtre de rendu
            cv2.imshow('Analyseur Optique', current_frame)

            # Écoute des événements clavier (attente d'1 ms)
            key_event = cv2.waitKey(1) & 0xFF
            # Fermeture du programme par appui sur la touche Échap (ESC)
            if key_event == 27:
                break

    finally:
        # Libération garantie des ressources allouées
        video_stream.release()
        cv2.destroyAllWindows()

if __name__ == "__main__":
    initialize_scanner()

Décryptage des opérations techniques

Acquisition et configuration vidéo
L'instanciation de cv2.VideoCapture(0) établit la connexion avec la première caméra détectée. Contrairement à l'utilisation de valeurs magiques, les constantes cv2.CAP_PROP_FRAME_WIDTH et cv2.CAP_PROP_FRAME_HEIGHT permettent d'ajuster la définition de l'image de manière explicite et maintenable. Le bloc try...finally assure que la méthode release() sera exécutée quoi qu'il arrive, évitant ainsi le verrouillage du périphérique par le système d'exploitation.

Extraction des données avec pyzbar
La fonction decode() parcourt le tableau multidimensionnel représentant l'image (fourni par NumPy) et renvoie un tableau d'objets. Chaque occurrence détectée expose plusieurs attributs cruciaux :

  • data : Le contenu binaire du code, qui doit être décodé en chaîne de caractères UTF-8.
  • type : La norme identifiée (par exemple, QRCODE ou EAN13).
  • rect : Une structure définissant la boîte englobante orthogonale (coordonnées x, y, largeur, hauteur).
  • polygon : Une liste de tuples représentant les coordonnées exactes des quatre coins du code, particulièrement utile pour les codes soumis à une rotation ou une perspective.

Analyse graphique et interface utilisateur
Pour matérialiser visuellement la détection, le script utilise deux primitives d'OpenCV. La fonction cv2.polylines trace une ligne continue reliant les sommets du polygone, formant un cadre précis autour de l'élément scanné. Parallèlement, cv2.putText projette la chaîne de caractères décodée directement sur le flux. L'ajout du paramètre cv2.LINE_AA (anti-aliasing) adoucit les contours de la typographie, tandis que la coordonnée Y est calculée dynamiquement (max(10, y - 15)) pour empêcher le texte de sortir de l'écran lorsque le code est situé tout en haut de l'image.

Contrôle de la boucle événementielle
L'interface graphique OpenCV nécessite une actualisation constante. La fonction cv2.waitKey(1) bloque l'exécution pendant une milliseconde pour traiter les événements de la fenêtre. En appliquant un masque binaire (& 0xFF), le script isole le code ASCII de la touche pressée. La valeur 27 correspondant à la touche Échap déclenche la sortie de la boucle while, initiant ainsi la procédure de nettoyage.

Étiquettes: Python OpenCV pyzbar vision-par-ordinateur flux-video

Publié le 29 juin à 22h27