Mode Découverte Gratuit (Accès 1-Clic)

Vous profitez d'un accès libre aux premières leçons de ce cours. Créez un compte gratuit pour enregistrer votre progression et accéder aux quiz !

Créer un compte gratuit

Manipulation des Pixels et Espaces de Couleur

Illustration 1

Illustration 2

Manipulation des Pixels et Espaces de Couleur

Introduction : L'Image Numérique comme Matrice

En vision par ordinateur, une image n'est rien de plus qu'une structure de données. Plus précisément, OpenCV représente les images comme des tableaux (arrays) NumPy. Pour une image en couleur, cette structure est généralement tridimensionnelle : hauteur, largeur et canaux de couleur. Pour une image en niveaux de gris, elle est bidimensionnelle : hauteur et largeur.

Chaque élément de ce tableau est un *pixel

  • (Picture Element), qui contient l'information de couleur à un point spécifique de l'image. La convention de coordonnées dans OpenCV place l'origine (0,0) dans le coin supérieur gauche, avec l'axe Y pointant vers le bas et l'axe X pointant vers la droite. Il est crucial de se rappeler que l'accès se fait via [ligne, colonne] ou [y, x].

Une particularité fondamentale d'OpenCV est son ordre par défaut pour les canaux de couleur : BGR (Bleu, Vert, Rouge), et non le plus commun RVB (Rouge, Vert, Bleu). Cette convention historique est due aux premiers fabricants de caméras et a été conservée pour des raisons de rétrocompatibilité.

I. Accès et Manipulation des Pixels

La capacité d'accéder et de modifier des pixels individuels ou des groupes de pixels est la base de nombreuses opérations de traitement d'images.

1. Accès à un Pixel Individuel

Pour lire la valeur d'un pixel situé aux coordonnées (x, y), on utilise l'indexation NumPy. Par exemple, pour une image img:
pixel_value = img[y, x]

Le résultat pixel_value sera un tableau contenant les valeurs des canaux B, G et R pour ce pixel, typiquement des entiers non signés sur 8 bits (uint8), allant de 0 à 255. Par exemple, [255, 0, 0] représente un pixel bleu pur.

2. Modification d'un Pixel Individuel

De la même manière, on peut assigner une nouvelle valeur à un pixel :
img[y, x] = [B_new, G_new, R_new]

Par exemple, pour rendre le pixel en (100, 50) blanc :
img[50, 100] = [255, 255, 255]

*Avertissement sur la performance :

  • Bien que l'accès direct soit simple, il est extrêmement inefficace de l'utiliser dans des boucles for pour traiter une image entière en Python. Les opérations vectorisées de NumPy sont des ordres de grandeur plus rapides. Utilisez l'accès direct uniquement pour des modifications ciblées et de petite échelle.

3. Région d'Intérêt (Region of Interest

  • ROI)

Souvent, nous ne voulons travailler que sur une partie de l'image. OpenCV, grâce à NumPy, rend cela très simple avec le 'slicing' (tranchage). Une ROI est simplement une sous-matrice de l'image principale.

Pour extraire une ROI rectangulaire, on spécifie les coordonnées du coin supérieur gauche (y1, x1) et du coin inférieur droit (y2, x2) :
roi = img[y1:y2, x1:x2]

L'un des aspects les plus puissants (et potentiellement dangereux) est que la ROI n'est pas une copie, mais une *vue

  • sur l'image originale. Toute modification apportée à la ROI modifiera directement l'image source. Pour obtenir une copie indépendante, il faut utiliser la méthode .copy() :
    roi_copy = img[y1:y2, x1:x2].copy()

II. Les Espaces de Couleur

L'espace BGR est adapté à l'affichage sur écran, mais il n'est pas toujours le plus pertinent pour l'analyse d'image. D'autres espaces de couleur séparent les informations de manière plus utile pour certaines tâches. La conversion entre espaces est une opération fondamentale réalisée par la fonction cv2.cvtColor().

1. L'Espace Niveaux de Gris (Grayscale)

L'espace de niveaux de gris réduit l'information de couleur à une seule dimension : l'*intensité lumineuse

  • ou luminance. Cela simplifie de nombreux algorithmes (ex: détection de contours, reconnaissance de formes) en réduisant la complexité des données.

La conversion de BGR en niveaux de gris n'est pas une simple moyenne des trois canaux. Elle utilise une moyenne pondérée pour tenir compte de la perception de la luminosité par l'œil humain, qui est plus sensible au vert qu'au bleu. La formule standard (ITU-R BT.709) est :

\(Y = 0.2126 \times R + 0.7152 \times G + 0.0722 \times B\)

OpenCV utilise une formule similaire, souvent citée comme :

\(Y = 0.299 \times R + 0.587 \times G + 0.114 \times B\)

En code, la conversion est directe :
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

L'image résultante aura une forme (hauteur, largeur), sans dimension de canal.

2. L'Espace HSV (Hue, Saturation, Value)

L'espace Teinte, Saturation, Valeur (HSV) est un modèle de couleur plus intuitif pour la perception humaine et extrêmement utile en vision par ordinateur, notamment pour la détection et le suivi d'objets colorés.

  • **Hue (Teinte

  • H) :*

  • Représente la couleur 'pure' (rouge, jaune, vert, etc.). Elle est modélisée comme un angle sur un cercle chromatique, allant de 0 à 360 degrés. Dans OpenCV, pour s'adapter à un format 8-bit (0-255), la teinte est mappée sur l'intervalle [0, 179]. Ainsi, chaque unité représente 2 degrés.

  • *Saturation (S) :

  • Indique la 'pureté' de la couleur. Une saturation de 0 correspond à un niveau de gris (couleur 'délavée'), tandis qu'une saturation maximale correspond à la couleur la plus pure. Elle est mappée sur [0, 255].

  • **Value (Valeur

  • V) :*

  • Correspond à la luminosité de la couleur. Une valeur de 0 est toujours noire. Elle est également mappée sur [0, 255].

L'avantage majeur de l'espace HSV est la décorrélation de l'information de couleur de l'information d'intensité. La Teinte (H) et la Saturation (S) restent relativement stables sous des changements de luminosité, qui sont principalement capturés par la Valeur (V). Cela rend les algorithmes de segmentation par couleur beaucoup plus robustes aux variations d'éclairage.

La conversion se fait comme suit :
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

3. Visualisation des Canaux

Pour mieux comprendre comment l'information est répartie, il est instructif de séparer une image en ses canaux constitutifs. La fonction cv2.split() permet de le faire.

b, g, r = cv2.split(img)

Chaque variable (b, g, r) est maintenant une image 2D en niveaux de gris. Dans l'image b, les pixels blancs ou clairs correspondent aux zones où la composante bleue était forte dans l'image originale. On peut également les réassembler avec cv2.merge().

merged_img = cv2.merge([b, g, r])

Cette technique est aussi applicable à l'espace HSV. La visualisation du canal H (Teinte) est particulièrement intéressante : elle montre une carte où l'intensité de gris correspond à un angle de couleur spécifique. Le canal S (Saturation) mettra en évidence les zones de couleurs vives par rapport aux zones ternes. Le canal V (Valeur) ressemblera beaucoup à la version en niveaux de gris de l'image.

💡 Exemples Concrets

Accéder et Modifier un Pixel

Ce code charge une image, lit la valeur du pixel aux coordonnées (100, 100), puis modifie ce pixel pour le rendre vert pur.

import cv2
import numpy as np

Créer une image noire de 300x300

image = np.zeros((300, 300, 3), dtype='uint8')

Coordonnées (x=100, y=100)

(x, y) = (100, 100)

Lire la valeur du pixel (sera [0, 0, 0] initialement)

(b, g, r) = image[y, x]
print(f'Valeur du pixel en ({x}, {y}) : B={b}, G={g}, R={r}')

Modifier le pixel pour le rendre vert

image[y, x] = [0, 255, 0]

Vérifier la nouvelle valeur

(b, g, r) = image[y, x]
print(f'Nouvelle valeur du pixel : B={b}, G={g}, R={r}')

cv2.imshow('Pixel Vert', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Extraire une Région d'Intérêt (ROI)

Cet exemple charge une image, sélectionne une région rectangulaire (une ROI), et colle cette région à un autre endroit de l'image. Cela démontre comment le slicing peut être utilisé pour la manipulation d'image.

import cv2

Charger une image (remplacez 'image.jpg' par le chemin de votre image)

image = cv2.imread('image.jpg')

Définir la ROI (coin sup-gauche: (x=50, y=60), taille: 100x120)

Slicing: [y1:y2, x1:x2]

roi = image[60:60+120, 50:50+100]

Coller la ROI à un autre endroit (coin sup-gauche: (x=200, y=210))

image[210:210+120, 200:200+100] = roi

cv2.imshow('Image avec ROI dupliquée', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Conversion d'Espaces de Couleur et Séparation des Canaux

Le code suivant convertit une image BGR en Niveaux de Gris et en HSV. Ensuite, il sépare les canaux de l'image BGR originale et les affiche individuellement.

import cv2
import numpy as np

Charger une image

image_bgr = cv2.imread('image.jpg')

Conversion en niveaux de gris

image_gray = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2GRAY)

Conversion en HSV

image_hsv = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2HSV)

Affichage des conversions

cv2.imshow('Original BGR', image_bgr)
cv2.imshow('Niveaux de Gris', image_gray)
cv2.imshow('HSV', image_hsv)

Note: L'affichage direct de l'image HSV n'est pas visuellement interprétable

Séparation des canaux BGR

b, g, r = cv2.split(image_bgr)

Affichage des canaux individuels

cv2.imshow('Canal Bleu', b)
cv2.imshow('Canal Vert', g)
cv2.imshow('Canal Rouge', r)

cv2.waitKey(0)
cv2.destroyAllWindows()

🧠 Exercices Pratiques

*Exercice 1

  • : Écrivez un script Python qui charge une image, puis dessine un carré de 50x50 pixels de couleur rouge pur dans le coin supérieur droit de l'image. Laissez une marge de 10 pixels par rapport aux bords de l'image.

*Solution : import cv2
import numpy as np

Charger une image

image = cv2.imread('image.jpg')

Obtenir les dimensions de l'image

(h, w) = image.shape[:2]

Définir la couleur rouge en BGR

red_color = [0, 0, 255]

Définir les coordonnées du carré

Coin supérieur droit : (x=w-1, y=0)

Marge de 10px

x_start = w

  • 50

  • 10
    y_start = 10
    x_end = w

  • 10
    y_end = 10 + 50

Utiliser le slicing pour colorer la région

image[y_start:y_end, x_start:x_end] = red_color

cv2.imshow('Carre Rouge', image)
cv2.waitKey(0)
cv2.destroyAllWindows()*

*Exercice 2

  • : Expliquez pourquoi le canal V (Valeur) d'une image HSV ressemble fortement à sa version en niveaux de gris. Quelle est la principale différence conceptuelle entre les deux ?

*Solution : Le canal V (Valeur) d'une image HSV représente la luminosité ou l'intensité de chaque pixel, indépendamment de sa couleur. De même, une image en niveaux de gris représente l'intensité lumineuse perçue (luminance) de chaque pixel. C'est pourquoi visuellement, ils sont très similaires.

La différence conceptuelle principale réside dans leur calcul et leur contexte :
1. *Niveaux de Gris (Grayscale)

  • : C'est une représentation complète de l'image en une seule dimension. Elle est calculée via une moyenne pondérée des canaux R, G, B ( \(Y = 0.299R + 0.587G + 0.114B\) ) pour correspondre à la perception humaine de la luminosité.
  • *Canal V (Value)

  • : C'est l'une des trois composantes de l'espace HSV. Sa formule de calcul est plus simple : \(V = \max(R, G, B)\) . Il représente simplement l'intensité du canal le plus brillant des trois. Bien que corrélé à la luminance, ce n'est pas une mesure perceptive aussi précise. Son but est de séparer l'intensité des informations de Teinte et de Saturation au sein d'un modèle de couleur complet, et non d'être une représentation finale en soi.*

📝 À Retenir

  • Une image dans OpenCV est un tableau NumPy, avec un ordre de canaux par défaut BGR (Bleu, Vert, Rouge).
  • L'accès aux pixels se fait avec la notation image[y, x], et le 'slicing' NumPy permet d'extraire efficacement des Régions d'Intérêt (ROI).
  • Les opérations en boucle sur les pixels sont lentes ; les opérations vectorielles NumPy sont à privilégier pour la performance.
  • L'espace de couleur Niveaux de Gris réduit l'image à une seule dimension d'intensité, simplifiant de nombreux algorithmes.
  • L'espace de couleur HSV sépare l'information de couleur (Teinte, Saturation) de l'information de luminosité (Valeur), ce qui le rend très robuste pour la segmentation par couleur sous des conditions d'éclairage variables.

© 2026 DzSmartEduc Learning Platform

تواصل معنا على واتساب 17h00 - 22h00 • 7j/7