OpenCV
La bibliothèque de référence pour la vision par ordinateur. Traitement
d'image, lecture de vidéo, détection, suivi, transformations
géométriques — tout ce qui dépasse la simple manipulation de fichier
(où Pillow suffit). Implémentée en C++, exposée en Python via
cv2.
À quoi ça sert
Là où Pillow ouvre et enregistre des fichiers image, OpenCV fait du traitement de pixels et de la vision par ordinateur :
- Lire/écrire vidéo — depuis un fichier, une webcam, un flux IP, et générer une vidéo en sortie.
- Filtrage et convolutions — flou gaussien, détection de bords (Canny), morphologie (érosion, dilatation), seuillage adaptatif.
- Transformations géométriques — rotation, perspective, warping, calibration de caméra.
- Détection « classique » — visages (Haar cascades), couleurs (HSV), formes (Hough), features (ORB, SIFT).
- Suivi d'objets — algorithmes de tracking intégrés (KCF, CSRT…).
- Pré/post-traitement pour le deep learning — souvent utilisé avant ou après YOLO / PyTorch pour préparer les frames et dessiner les sorties.
cv2.imread() renvoie une image au format
BGR (Bleu, Vert, Rouge), pas RGB. C'est un
héritage historique d'OpenCV (les capteurs caméra de l'époque).
Conséquence : si tu affiches une image OpenCV avec
matplotlib ou la passes à un modèle
qui attend du RGB (la grande majorité), les couleurs sont
inversées. Solution :
cv2.cvtColor(img, cv2.COLOR_BGR2RGB).
Un exemple d'usage
Lire une vidéo, détecter les contours frame par frame, sauver le résultat. C'est l'archétype d'usage OpenCV — chaîne lecture → traitement → écriture.
import cv2
cap = cv2.VideoCapture("input.mp4")
fps = int(cap.get(cv2.CAP_PROP_FPS))
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
out = cv2.VideoWriter("edges.mp4", fourcc, fps, (w, h))
while True:
ok, frame = cap.read()
if not ok:
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 200) # détection de bords
color = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR) # remettre 3 canaux
out.write(color)
cap.release(); out.release()
Le pattern read → traiter → write est universel en
OpenCV. Tu peux substituer Canny par n'importe quoi —
un appel à YOLO, un modèle PyTorch, un seuillage couleur — et garder
la même structure.
How-to : installer et utiliser OpenCV
-
Installer OpenCV
Le paquet pip s'appelle
opencv-python, mais l'import restecv2. Avec UV :bashuv add opencv-pythonSur un serveur sans interface graphiqueSur un container Docker ou un serveur headless, préfère
opencv-python-headless: même API mais sans les dépendances GUI (Qt) → installation plus légère, image Docker plus petite. Ne pas installer les deux, sinon conflit.pythonimport cv2 print(cv2.__version__) -
Lire et afficher une image
pythonimport cv2 img = cv2.imread("photo.jpg") # renvoie un array NumPy BGR print(img.shape, img.dtype) # (H, W, 3) uint8 # Convertir en RGB pour afficher avec matplotlib rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # … ou en niveaux de gris pour des algos gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) cv2.imwrite("out.png", img) # sauvegarder -
Redimensionner, recadrer, transformer
python# Resize (attention : (largeur, hauteur), inverse de PIL) small = cv2.resize(img, (300, 200)) # Crop avec slicing NumPy (img est un ndarray) crop = img[50:450, 100:500] # Rotation autour du centre h, w = img.shape[:2] M = cv2.getRotationMatrix2D((w/2, h/2), angle=45, scale=1.0) rotated = cv2.warpAffine(img, M, (w, h)) -
Filtrage et seuillage
python# Flou gaussien (lisse l'image) blur = cv2.GaussianBlur(img, (5, 5), sigmaX=0) # Détection de bords Canny gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) edges = cv2.Canny(gray, 100, 200) # Seuillage : tout pixel > 127 devient 255, sinon 0 _, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # Seuillage adaptatif (ajusté par zone, meilleur sur photo) adaptive = cv2.adaptiveThreshold( gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) -
Lire une vidéo ou la webcam
python# Fichier vidéo cap = cv2.VideoCapture("video.mp4") # Webcam (0 = première caméra) cap = cv2.VideoCapture(0) while True: ok, frame = cap.read() if not ok: break # … traiter frame … cv2.imshow("webcam", frame) if cv2.waitKey(1) & 0xFF == ord("q"): break cap.release() cv2.destroyAllWindows() -
Dessiner des annotations
Particulièrement utile après une détection YOLO pour visualiser le résultat :
python# Rectangle (BGR : ici rouge en BGR = (0, 0, 255)) cv2.rectangle(img, (50, 50), (200, 150), color=(0, 0, 255), thickness=2) # Texte cv2.putText(img, "chien", (55, 45), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) # Cercle cv2.circle(img, center=(150, 100), radius=30, color=(255, 0, 0), thickness=-1) # rempli -
Détection couleur (segmentation HSV)
Classique : isoler tout ce qui est d'une certaine couleur dans une image. On passe en HSV pour que la « couleur » soit un seul paramètre stable :
pythonimport numpy as np hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # Masque pour tout ce qui est "rouge" (deux plages en HSV) lower1 = np.array([0, 120, 70]) upper1 = np.array([10, 255, 255]) mask = cv2.inRange(hsv, lower1, upper1) # Appliquer le masque sur l'image originale result = cv2.bitwise_and(img, img, mask=mask)
Aide-mémoire
import cv2
img = cv2.imread("in.jpg") # BGR uint8
cv2.imwrite("out.png", img)
cap = cv2.VideoCapture("v.mp4")
ok, frame = cap.read(); cap.release()
cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
cv2.resize(img, (w, h))
cv2.GaussianBlur(img, (5, 5), 0)
cv2.Canny(gray, 100, 200)
cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
cv2.rectangle(img, p1, p2, (b, g, r), thickness)
cv2.putText(img, txt, org, font, scale, color, thick)
cv2.circle(img, center, r, color, thick)
OpenCV et le reste de l'écosystème
- NumPy — toute image OpenCV est un array NumPy. Toutes les opérations NumPy (slicing, masques, broadcasting) sont valides sur une image.
-
Pillow — complémentaire.
Pillow est plus simple pour ouvrir/sauver/redimensionner ;
OpenCV prend le relais pour le traitement d'image et la vidéo.
Aller-retour avec
np.array(pil_img)etcv2.cvtColor(arr, cv2.COLOR_RGB2BGR). - YOLO / PyTorch — OpenCV est souvent le préprocesseur (resize, normalisation) et le post-processeur (dessiner les bounding boxes) du pipeline. YOLO Ultralytics accepte directement une frame OpenCV en input.
-
matplotlib — pour
afficher une image OpenCV dans un notebook, il faut convertir
BGR → RGB avant
plt.imshow, sinon les couleurs sont inversées. -
FastAPI — pour recevoir
une image en POST et la traiter avec OpenCV : on lit les bytes
et on décode avec
cv2.imdecode(np.frombuffer(...), 1). -
Streamlit — affiche
directement une image OpenCV avec
st.image(img, channels="BGR")(sinon couleurs inversées, encore et toujours).
Si tu te poses la question, fais un test mental : « j'ai besoin de manipuler des fichiers image (resize, format) » → Pillow suffit. « J'ai besoin de filtres, de détection, de vidéo, de masques » → OpenCV. En pratique sur un projet ML vision, les deux cohabitent : Pillow pour le chargement avant un modèle PyTorch, OpenCV pour annoter et lire des vidéos.
Pour aller plus loin
- Site officiel : opencv.org
- Tutoriels Python officiels : docs.opencv.org/4.x/d6/d00/tutorial_py_root.html
- Référence API (cv2) : docs.opencv.org/4.x
- OpenCV-Python Cookbook (PyImageSearch) : pyimagesearch.com