OpenCV avec Python : Introduction au Traitement d'Images
Initiez-vous au traitement d'images avec OpenCV et Python : espaces de couleurs, filtres, contours, seuillage, détection de visages et lecture de flux webcam.
InSkillCoach
OpenCV avec Python : Introduction au Traitement d’Images
OpenCV (Open Source Computer Vision Library) est la bibliothèque de référence en vision par ordinateur. Avec son interface Python, elle permet de lire, transformer et analyser des images et des vidéos en quelques lignes : filtrage, détection de contours, reconnaissance de visages, traitement de flux webcam en temps réel. Ce guide couvre les opérations fondamentales que tout projet de traitement d’images utilise, avec des exemples complets et exécutables.
Installation
OpenCV s’installe via le package opencv-python, qui inclut les modules principaux :
pip install opencv-python
# Si vous avez besoin des modules supplémentaires (contrib)
pip install opencv-contrib-python
Vérification :
import cv2
print(cv2.__version__)
# 4.10.0 (ou version plus récente)
Notez que le module s’importe sous le nom cv2, quel que soit le nom du package installé. OpenCV représente les images comme des tableaux NumPy, installé automatiquement en dépendance.
Lire, afficher et sauvegarder une image
import cv2
# Lecture d'une image depuis le disque
image = cv2.imread("photo.jpg")
# imread ne lève PAS d'exception si le fichier est introuvable : il renvoie None
if image is None:
raise FileNotFoundError("Impossible de lire photo.jpg")
# Une image est un tableau NumPy : (hauteur, largeur, canaux)
print(image.shape)
# (720, 1280, 3)
print(image.dtype)
# uint8 (valeurs de 0 à 255)
# Affichage dans une fenêtre
cv2.imshow("Ma photo", image)
cv2.waitKey(0) # attend une touche (0 = indéfiniment)
cv2.destroyAllWindows() # ferme toutes les fenêtres
# Sauvegarde (le format est déduit de l'extension)
cv2.imwrite("photo_copie.png", image)
Le contrôle if image is None est indispensable : oublier cette vérification est la première cause d’erreurs cryptiques chez les débutants.
Espaces de couleurs : le piège du BGR
Attention au piège classique : OpenCV charge les images en BGR (bleu, vert, rouge) et non en RGB. Si vous affichez une image OpenCV avec Matplotlib sans conversion, les rouges et les bleus sont inversés.
import cv2
image = cv2.imread("photo.jpg")
# Conversion BGR vers RGB (nécessaire pour Matplotlib, Pillow, etc.)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# Conversion en niveaux de gris (un seul canal)
gris = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
print(gris.shape)
# (720, 1280) : plus de dimension couleur
# Conversion en HSV (teinte, saturation, valeur)
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
L’espace HSV est précieux pour isoler une couleur, car la teinte y est indépendante de la luminosité :
import numpy as np
# Isoler les zones bleues de l'image
borne_basse = np.array([100, 100, 50]) # teinte, saturation, valeur minimales
borne_haute = np.array([130, 255, 255])
masque = cv2.inRange(hsv, borne_basse, borne_haute)
# Appliquer le masque : seules les zones bleues restent visibles
resultat = cv2.bitwise_and(image, image, mask=masque)
Redimensionner et recadrer
import cv2
image = cv2.imread("photo.jpg")
hauteur, largeur = image.shape[:2]
# Redimensionnement à des dimensions précises
petite = cv2.resize(image, (640, 360))
# Redimensionnement par facteur (ici : moitié) en conservant les proportions
moitie = cv2.resize(image, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)
# Recadrage : une image est un tableau NumPy, on découpe donc par tranches
# Syntaxe : image[y1:y2, x1:x2]
recadree = image[100:400, 200:600]
cv2.imwrite("recadree.jpg", recadree)
Pour réduire une image, l’interpolation cv2.INTER_AREA donne le meilleur résultat ; pour l’agrandir, préférez cv2.INTER_CUBIC ou cv2.INTER_LINEAR.
Dessiner sur une image
Les fonctions de dessin modifient l’image en place. Les couleurs sont en BGR :
import cv2
image = cv2.imread("photo.jpg")
# Rectangle : coins opposés, couleur BGR, épaisseur (-1 = rempli)
cv2.rectangle(image, (50, 50), (250, 200), (0, 255, 0), 2)
# Cercle : centre, rayon
cv2.circle(image, (400, 300), 60, (255, 0, 0), 3)
# Ligne
cv2.line(image, (0, 0), (640, 360), (0, 0, 255), 2)
# Texte
cv2.putText(image, "Detection", (50, 40),
cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), 2)
cv2.imwrite("annotee.jpg", image)
Flous et filtres
Le flou gaussien est la brique de base du prétraitement : il atténue le bruit avant une détection de contours ou un seuillage.
import cv2
image = cv2.imread("photo.jpg")
# Flou gaussien : le noyau (15, 15) doit avoir des dimensions impaires
flou = cv2.GaussianBlur(image, (15, 15), 0)
# Flou médian : très efficace contre le bruit "poivre et sel"
median = cv2.medianBlur(image, 5)
# Filtre bilatéral : lisse les zones plates en préservant les contours
bilateral = cv2.bilateralFilter(image, 9, 75, 75)
Plus le noyau est grand, plus le flou est prononcé. Un noyau (5, 5) suffit généralement comme prétraitement.
Détection de contours : Canny et findContours
L’algorithme de Canny détecte les contours (les zones de fort changement d’intensité) :
import cv2
image = cv2.imread("photo.jpg")
gris = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Réduire le bruit avant la détection
gris_flou = cv2.GaussianBlur(gris, (5, 5), 0)
# Canny : les deux seuils contrôlent la sensibilité
# En dessous de 50 : rejeté ; au-dessus de 150 : contour sûr
contours_canny = cv2.Canny(gris_flou, 50, 150)
cv2.imwrite("canny.jpg", contours_canny)
findContours va plus loin : il extrait les contours sous forme de listes de points, exploitables pour mesurer, compter ou encadrer des objets :
# findContours attend une image binaire (résultat de Canny ou d'un seuillage)
contours, _ = cv2.findContours(contours_canny,
cv2.RETR_EXTERNAL, # contours externes seulement
cv2.CHAIN_APPROX_SIMPLE) # compression des points
print(f"Nombre de contours trouvés : {len(contours)}")
# Encadrer chaque contour suffisamment grand
for contour in contours:
aire = cv2.contourArea(contour)
if aire > 500: # ignorer le bruit
x, y, w, h = cv2.boundingRect(contour)
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imwrite("objets_detectes.jpg", image)
Seuillage
Le seuillage transforme une image en niveaux de gris en image binaire (noir et blanc), étape préalable à de nombreuses analyses :
import cv2
gris = cv2.imread("document.jpg", cv2.IMREAD_GRAYSCALE)
# Seuillage simple : tout pixel > 127 devient 255, sinon 0
_, binaire = cv2.threshold(gris, 127, 255, cv2.THRESH_BINARY)
# Seuillage d'Otsu : le seuil optimal est calculé automatiquement
_, otsu = cv2.threshold(gris, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# Seuillage adaptatif : seuil calculé localement, idéal pour un
# document photographié avec un éclairage inégal
adaptatif = cv2.adaptiveThreshold(gris, 255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2)
Détection de visages avec les cascades de Haar
OpenCV embarque des classificateurs pré-entraînés pour détecter visages, yeux ou sourires. Voici un détecteur de visages complet :
import cv2
# Chargement du classificateur pré-entraîné fourni avec OpenCV
cascade_visages = cv2.CascadeClassifier(
cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
)
image = cv2.imread("groupe.jpg")
if image is None:
raise FileNotFoundError("Impossible de lire groupe.jpg")
# La détection travaille sur une image en niveaux de gris
gris = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# detectMultiScale renvoie un rectangle (x, y, largeur, hauteur) par visage
visages = cascade_visages.detectMultiScale(
gris,
scaleFactor=1.1, # réduction de l'image à chaque passe (10 %)
minNeighbors=5, # plus haut = moins de faux positifs
minSize=(40, 40), # taille minimale d'un visage en pixels
)
print(f"{len(visages)} visage(s) détecté(s)")
# 3 visage(s) détecté(s)
# Encadrer chaque visage
for (x, y, w, h) in visages:
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imwrite("visages_detectes.jpg", image)
cv2.imshow("Visages", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
Ajustez minNeighbors si la détection produit trop de faux positifs (augmentez-le) ou manque des visages (diminuez-le). Les cascades de Haar sont rapides mais sensibles à l’orientation : elles détectent surtout les visages de face.
Lire un flux vidéo ou la webcam
Une vidéo n’est qu’une suite d’images : on lit les images une à une dans une boucle. L’exemple suivant détecte les visages en direct sur la webcam :
import cv2
cascade_visages = cv2.CascadeClassifier(
cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
)
# 0 = première webcam ; remplacez par "video.mp4" pour un fichier
capture = cv2.VideoCapture(0)
if not capture.isOpened():
raise RuntimeError("Impossible d'ouvrir la webcam")
while True:
# ret vaut False si la lecture échoue (fin de fichier, webcam débranchée)
ret, frame = capture.read()
if not ret:
break
gris = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
visages = cascade_visages.detectMultiScale(gris, 1.1, 5, minSize=(40, 40))
for (x, y, w, h) in visages:
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow("Webcam - appuyez sur Q pour quitter", frame)
# waitKey(1) : attendre 1 ms ; quitter si la touche Q est pressée
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Libérer la webcam et fermer les fenêtres
capture.release()
cv2.destroyAllWindows()
Pour aller plus loin : le module DNN
Les cascades de Haar datent de 2001. Pour des détections plus précises et plus robustes, OpenCV intègre un module de réseaux de neurones profonds (cv2.dnn) capable de charger des modèles pré-entraînés aux formats ONNX, TensorFlow ou Caffe :
import cv2
# Exemple : charger un modèle de détection au format ONNX
# net = cv2.dnn.readNetFromONNX("modele_detection.onnx")
Les pistes naturelles après ce guide : la détection de visages par DNN (modèle YuNet intégré à OpenCV via cv2.FaceDetectorYN), la détection d’objets avec YOLO, et l’estimation de pose. Le principe reste le même que dans ce guide : lire l’image, la prétraiter, l’analyser, dessiner le résultat.
Bonnes pratiques
- Vérifiez toujours le retour de
imreadet decapture.read(): OpenCV renvoieNoneouFalseau lieu de lever une exception. - N’oubliez jamais la conversion BGR/RGB quand vous échangez des images avec Matplotlib, Pillow ou un modèle de deep learning.
- Prétraitez avant d’analyser : niveaux de gris puis flou gaussien améliorent presque toujours Canny et le seuillage.
- Libérez les ressources :
capture.release()etcv2.destroyAllWindows()en fin de traitement vidéo. - Travaillez sur des copies (
image.copy()) quand vous dessinez, pour conserver l’originale intacte. - Filtrez par aire (
cv2.contourArea) aprèsfindContourspour éliminer le bruit.
Conclusion
Vous disposez maintenant des fondations du traitement d’images avec OpenCV : chargement et sauvegarde, espaces de couleurs (et le piège BGR), redimensionnement, filtres, détection de contours avec Canny et findContours, seuillage, détection de visages par cascades de Haar et traitement d’un flux webcam en temps réel. Ces opérations couvrent la grande majorité des besoins d’un premier projet de vision par ordinateur.
Pour approfondir, consultez la documentation officielle d’OpenCV et ses tutoriels Python, puis explorez le module DNN pour passer aux détections par apprentissage profond.
À propos de InSkillCoach
Expert en formation et technologies
Coach spécialisé dans les technologies avancées et l'IA, porté par GNeurone Inc.
Certifications:
- AWS Certified Solutions Architect – Professional
- Certifications Google Cloud
- Microsoft Certified: DevOps Engineer Expert
- Certified Kubernetes Administrator (CKA)
- CompTIA Security+
Commentaires
Les commentaires sont alimentés par GitHub Discussions
Connectez-vous avec GitHub pour participer à la discussion