Bonjour,
Etant donné que la documentation sur les opérateurs morphologiques d'érosion et de dilatation sur des images en couleurs est assez difficile à trouver, je vais vous expliquer le principe.
La diffusion et l'érosion s'effectue suivant un noyau, en général, quand on voit ces opérateurs, on travaille avec des images binaires :
Par exemple, l'érosion :
La dilatation :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 Avant Apres 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0
A chaque pixel, on pose un "noyau" dessus composé de 0 et de 1. Typiquement, le noyau classique est :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 Avant Apres 0 0 0 0 0 0 1 1 0 0 0 1 1 0 0 1 1 1 1 0 0 1 1 1 0 1 1 1 1 1 0 0 1 0 0 0 1 1 1 0
Pour la dilatation,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 0 1 0 1 1 1 0 1 0
On centre le noyau de tel façon à ce qu'il recouvre le pixel de destination (x,y) à changer, si l'un des pixels de l'image d'origine dispose d'un 1 là où il y a un 1 dans le noyau, alors l'image de destination (x,y) vaudra 1.
On fait l'inverse pour l'érosion.
On suppose que l'on dispose d'un objet Kernel qui dispose des opérations suivantes :
L'algorithme naif pour une image binaire va s'écrire comme ça :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 getWidth() : donne la largeur getHeight() : donne la hauteur getLeftPadding() : donne le nombre de pixel à gauche à partir du centre (ici, c'est 1) getRightPadding() : idem mais pour la droite getBottomPadding() : idem mais pour en bas getTopPadding() : idem mais pour en haut getOriginX() : donne le centre horizontal du noyau en commencant à 0 (donc ici 1) getOriginY() : donne le centre vertical
Pour la dilatation par exemple :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 fonction dilatation(Image in, Kernel k) /*on ne traite pas les bords*/ Image out de taille : largeur -(k.getRightPadding() + k.getLeftPadding() hauteur - (k.getTopPadding() + k.getBottomPadding()) Pour chaque canaux de out et de in faire : Pour j = k.getTopPadding() à hauteur - k.getBottomPadding()-1 Pour i = leftpadding à largeur - k.getRightPadding()-1 { float value = 0; Pour kj = 0 à k.getHeight()-1 Pour ki =0 à k.getWidth()-1 { out.setPixel( i - leftpadding, j - toppadding, 0); /*si l'un des pixels du noyau à 1 correspond à un pixel à 1 de l'image, la futur valeur sera égale à 1*/ Si kernel(ki, kj) * image.getPixel(i + ki - kernel.getXOrigin(), j+ kj - kernel.getYOrigin()) == 1 Alors value = 1; out.setPixel(i - leftpadding, j - toppadding, value); } }
Cette méthode fonctionne bien pour des images binaires, mais pas pour des images qui dispose de plusieurs niveaux de gris, la méthode général est la suivante :
Pour l'érosion :
1. Pour chaque pixel de la source, placer le noyau sur l'image centré sur le pixel (i,j)
2. Pour chaque pixel du noyau (positionné), soustraire la valeur du noyau * le pixel décalé au pixel central (i,j)
3. Déterminer le minimum de toutes ces valeurs
4. Ajouter le minimum au pixel central (i,j)
Algorithme avec une notation C++ :
Pour la dilatation :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 out.resize(largeur - (rightpadding + leftpadding), hauteur - (toppadding+bottompadding)); for(int j = toppadding; j< hauteur - bottompadding; j++) { for(int i = leftpadding; i< largeur - rightpadding; i++) { for(int kj = 0; kj< khauteur; kj++) for(int ki = 0; ki< klargeur; ki++) { buffer[klargeur * kj + ki] = image.getPixel(i,j, canal) - kernel(ki, kj) * image.getPixel(i + ki - kernel.getXOrigin(), j+ kj - kernel.getYOrigin(), canal); } float mini = getMinimum(buffer); out.setPixel(i - leftpadding, j - toppadding, canal, mini + image.getPixel(i,j, canal)); }
1. Pour chaque pixel de la source (i,j), placer le noyau sur l'image centré sur le pixel
2. Pour chaque pixel du noyau (positionné), soustraire la valeur du pixel central (i,j) au produit noyau * le pixel décalé
3. Déterminer le maximum de toutes ces valeurs
4. Ajouter le maximum au pixel central (i,j)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 out.resize(largeur - (rightpadding + leftpadding), hauteur - (toppadding+bottompadding)); for(int j = toppadding; j< hauteur - bottompadding; j++) { for(int i = leftpadding; i< largeur - rightpadding; i++) { for(int kj = 0; kj< khauteur; kj++) for(int ki = 0; ki< klargeur; ki++) { buffer[klargeur * kj + ki] = -image.getPixel(i,j, canal) + kernel(ki, kj) * image.getPixel(i + ki - kernel.getXOrigin(), j+ kj - kernel.getYOrigin(), canal); } float maxi = getMaximum(buffer); out.setPixel(i - leftpadding, j - toppadding, canal, maxi + image.getPixel(i,j, canal)); }
Classiquement, on utilise le noyau :
Voici un exemple :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 0 1 0 1 1 1 0 1 0
Source :
Erosion :
Dilatation :
![]()
Partager