HOWTO · Python

OpenCV Dilate

Dans cet article, nous allons expliquer les concepts de transformation morphologique tels que l'érosion et la dilatation que nous utilisons pour ajouter et supprimer des pixels de la limite d'un objet donné dans une image dans OpenCV.

Sur cette page

Utilisez cv2.dilate pour étendre les zones claires du premier plan d’une image. Dans OpenCV, la dilatation examine le voisinage de chaque pixel et étend le premier plan selon un noyau structurant. Cette opération s’applique aussi bien aux images en niveaux de gris qu’aux images binaires ; l’exemple ci-dessous utilise une image en niveaux de gris avec un pixel clair afin de rendre l’effet facile à observer.

Ce que fait la dilatation dans OpenCV

Les opérations morphologiques traitent une image à l’aide d’un noyau, également appelé élément structurant. Dans une image binaire, les pixels du premier plan sont généralement représentés en blanc (255) et ceux de l’arrière-plan en noir (0). La dilatation attribue à chaque pixel de sortie la valeur maximale dans le voisinage défini par le noyau. Les zones claires s’étendent donc, et des composantes claires proches peuvent se rejoindre. L’érosion utilise plutôt la valeur minimale du voisinage : les zones claires rétrécissent.

Le voisinage se déplace sur l’image, un peu comme la fenêtre locale utilisée pour la convolution 2D, mais la dilatation prend le maximum du voisinage au lieu de calculer une somme pondérée. Pour une image en niveaux de gris, cette opération éclaircit aussi les zones locales ; elle ne se limite pas à un masque composé de deux valeurs. La page sur la convolution liée ici est disponible en anglais dans les destinations fournies.

Appliquer une dilatation avec Python et OpenCV

Cet exemple autonome utilise une petite image en niveaux de gris comportant un pixel clair et un voisinage rectangulaire de 3 × 3. Il fait appel à cv2.dilate si OpenCV et NumPy sont installés ; sinon, une solution de repli fondée sur la bibliothèque standard applique la même règle du maximum dans le voisinage, afin que l’exemple puisse tout de même s’exécuter.

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

import importlib.util

image = [
    [0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0],
    [0, 0, 255, 0, 0],
    [0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0],
]

if importlib.util.find_spec("cv2") and importlib.util.find_spec("numpy"):
    import cv2
    import numpy as np

    kernel = np.ones((3, 3), dtype=np.uint8)
    dilated = cv2.dilate(np.array(image, dtype=np.uint8), kernel, iterations=1).tolist()
else:
    dilated = [
        [
            max(image[y][x] for y in range(max(0, row - 1), min(5, row + 2))
                for x in range(max(0, col - 1), min(5, col + 2)))
            for col in range(5)
        ]
        for row in range(5)
    ]

print(dilated)
[[0, 0, 0, 0, 0], [0, 255, 255, 255, 0], [0, 255, 255, 255, 0], [0, 255, 255, 255, 0], [0, 0, 0, 0, 0]]

Pour un traitement à partir d’un fichier, chargez une image source en niveaux de gris avec cv2.imread("input.png", cv2.IMREAD_GRAYSCALE), puis vérifiez que la valeur renvoyée n’est pas None avant d’appeler cv2.dilate. Un chemin incorrect ou un fichier non pris en charge peut produire None ; il est alors impossible d’effectuer une opération morphologique sur cette valeur pour obtenir une image. Conservez des tableaux distincts pour l’entrée et la sortie si vous devez les comparer ensuite.

Effet du noyau et du nombre d’itérations sur la dilatation

Le noyau définit le voisinage et sa forme. Un noyau plus grand examine une zone plus étendue et agrandit généralement davantage les éléments clairs. Un noyau rectangulaire convient à une expansion uniforme horizontalement et verticalement ; un noyau elliptique ou en forme de croix modifie la géométrie du voisinage. Choisissez ses dimensions et sa forme en fonction des espaces et des éléments à modifier, puis examinez le résultat sur des images représentatives.

L’argument iterations répète l’opération de dilatation. Augmenter sa valeur accentue l’expansion : les espaces étroits peuvent se fermer et les zones proches se rejoindre. Commencez par une seule itération et un petit noyau, puis ne modifiez qu’un réglage à la fois. Un résultat visuellement plus marqué n’est pas forcément meilleur : une expansion excessive peut effacer les détails fins.

Comparer la dilatation à l’érosion, à l’ouverture et à la fermeture

L’érosion rétrécit les zones claires du premier plan ; la dilatation les étend. L’ouverture applique d’abord une érosion, puis une dilatation. Selon le noyau et l’image, elle peut supprimer de petits détails clairs tout en conservant les structures plus grandes. La fermeture applique d’abord une dilatation, puis une érosion ; elle peut combler de petits espaces sombres dans des structures claires. Ces séquences ne garantissent pas de restituer chaque pixel d’origine : leurs effets dépendent de l’élément structurant et des éléments présents dans l’image.

Utilisez l’ouverture si vous cherchez à supprimer de petits éléments clairs parasites, ou la fermeture si vous voulez combler de petits trous ou des interruptions sombres dans un premier plan clair. Pour des objets sombres sur un fond clair, déterminez d’abord quelle polarité doit correspondre au premier plan ; vous devrez peut-être inverser l’image avant d’appliquer le même raisonnement.

Comprendre la polarité du premier plan et le résultat

La dilatation de base d’OpenCV étend les valeurs de pixel les plus élevées. Dans une image binaire claire sur fond sombre, le premier plan blanc s’étend sur l’arrière-plan noir voisin. Dans une photographie de texte sombre sur une page blanche, c’est la page claire qui porte les valeurs élevées : la dilatation étend donc la page et peut faire paraître le texte sombre plus fin. Le résultat peut ainsi sembler contraire à l’idée intuitive de « faire grossir l’objet ».

Si vous souhaitez agrandir le texte sombre lui-même, inversez l’image en niveaux de gris, dilatez l’image inversée, puis inversez à nouveau le résultat. Pour une image couleur, chaque canal est traité comme une donnée d’image ; utilisez un masque à un seul canal, en niveaux de gris ou binaire, si le premier plan visé est une forme ou une étiquette plutôt qu’une intensité de couleur.

Vérifier les problèmes courants d’entrée et d’affichage

Vérifiez que l’image source a bien été chargée avant le traitement et que les dimensions du noyau conviennent aux détails de l’image. Un noyau large ou un grand nombre d’itérations peut fusionner des composantes distinctes ou supprimer des espaces étroits. Si le résultat semble inchangé, vérifiez que le premier plan choisi est plus clair que son environnement et que le voisinage du noyau inclut des pixels proches pertinents pour la modification. La taille et la forme du noyau déterminent les valeurs locales prises en compte ; aucun seuil minimal ne stipule que le noyau doit être aussi grand que les éléments modifiés.

OpenCV lit les images couleur dans l’ordre des canaux BGR, tandis que Matplotlib interprète un tableau à trois canaux comme du RGB. Convertissez une image BGR avec cv2.cvtColor(image, cv2.COLOR_BGR2RGB) avant de l’afficher avec matplotlib.pyplot.imshow ; pour les tableaux en niveaux de gris, passez cmap="gray" afin d’utiliser une palette de gris. Une différence de couleurs à l’affichage affecte la visualisation, pas le calcul de la dilatation.