Python et traitement d`images

Transcription

Python et traitement d`images
Python et traitement d’images
L’objectif de ce court document est de présenter quelques aspects simples du traitement d’images
sous Python, et de donner quelques pistes pour aller plus avant.
Plusieurs modules existent pour faire du traitement d’images sous Python, dont PIL et skimage.
Pour rester dans la continuité de la formation proposée l’an dernier, nous nous appuierons ici
sur Numpy, Scipy et matplotlib (même si certaines fonctions de Scipy impliquent que PIL soit
chargé).
1
Pour commencer
1.1
Ouvrir et écrire des images sur disque
Le code 1 présente une manière d’ouvrir et d’afficher des images présentes sur le disque.
# −∗− c o d i n g : u t f −8 −∗−
from s c i p y import m i s c
#module d ’ a f f i c h a g e
import m a t p l o t l i b . p y p l o t
as
plt
# o u v e r t u r e d ’ une i m a g e c o u l e u r
i = misc . imread ( ’ i s i m a . p n g ’ )
#A f f i c h a g e
en u t i l i s a n t
p l t . imshow ( i )
#L e s a x e s s o n t s u p p r i m é s
plt . axis ( ’ off ’)
p l t . show ( )
une
sur
figure
le
disque
matplotlib
# o u v e r t u r e d ’ une i m a g e en n i v e a u x de g r i s s u r l e d i s q u e
j = misc . imread ( ’ h a n d . j p g ’ )
#La p a l e t t e e s t m i s e à l a p a l e t t e en n i v e a u x de g r i s
p l t . imshow ( j , cmap=p l t . cm . g r a y )
p l t . a x i s ( ’ o f f ’ ) #Ote l e s a x e s
p l t . show ( )
Listing 1 – Ouverture et affichage d’une image. Deux exemples.
Ces images étant alors stockées comme des tableaux, le module Numpy peut naturellement être
utilisé pour les traiter.
1.2
Ecrire dans le tableau
Le code 2 montre comment créer une image directement en écrivant des valeurs dans les pixels
du tableau (figure 1)
1
# −∗− c o d i n g : u t f −8 −∗−
import m a t p l o t l i b . p y p l o t
import numpy a s np
import math
as
plt
#C r é a t i o n d ’ i m a g e en p a r c o u r a n t
i m a g e = np . z e r o s ( ( 2 5 6 , 2 5 6 ) )
n l , nc = i m a g e . s h a p e
for
plt
plt
plt
plt
l
in
les
pixels
range ( nl ) :
f o r c i n r a n g e ( nc ) :
i m a g e [ l ] [ c ] = l ∗math . c o s ( c ) ∗math . s i n ( l )
. imshow ( image , cmap=p l t . cm . g r a y )
. t i t l e ( ’ E x e m p l e de c r e a t i o n d une
. a x i s ( ’ o f f ’ ) #Ote l e s a x e s
. show ( )
image ’)
Listing 2 – Ouverture et affichage d’une image. Deux exemples.
Figure 1 – Application du code 2
1.3
Accès à la grille des pixels
Il est possible d’avoir facilement accès à la grille des pixels de l’image, sous forme de tableau,
et de faire des traitements matriciels directs sur les images. Le code 3 décrit comment :
– appliquer un masque binaire sur une image donnée, à partir de la définition de ce masque
sous forme d’une formule calculée sur la grille des pixels.
– accéder à une série de pixels pour afficher des valeurs prédéfinies
2
# −∗− c o d i n g : u t f −8 −∗−
from s c i p y import m i s c
import m a t p l o t l i b . p y p l o t
import numpy a s np
as
plt
# o u v e r t u r e d ’ une i m a g e c o u l e u r
j = misc . imread ( ’ h a n d . j p g ’ )
#r é c u p e r a t i o n d e s
n l , nc = j . s h a p e
sur
le
dimensions
#r e c u p e r a t i o n d ’ une g r i l l e a y a n t
X, Y = np . o g r i d [ 0 : n l , 0 : nc ]
la
dimension
#c r é a t i o n d ’ un masque c i r c u l a i r e
masque = (X − n l / 2 ) ∗∗ 2 + (Y − nc /
plt
plt
plt
plt
disque
2)
de
l ’ image
∗∗ 2 > n l
∗ nc / 8
. imshow ( masque , cmap=p l t . cm . g r a y )
. title ( ’ masque ’)
. axis ( ’ off ’)
. show ( )
# Application
j [ masque ]=0
du masque
# A c c è s a une z o n e de l a
j [160:210 ,530:565]=255
sur
l ’ image
grille
#La p a l e t t e e s t m i s e à l a p a l e t t e
p l t . imshow ( j , cmap=p l t . cm . g r a y )
plt . t i t l e ( ’ image avec m a s q u e s ’)
plt . axis ( ’ off ’)
en
niveaux
de
gris
p l t . show ( )
Listing 3 – Accès aux pixels.
2
2.1
Manipulations de base
Transformations géométriques élémentaires
Il est très aisé d’appliquer des transformations géométriques élémentaires (linéaires) sur des
images. Le code 4 et la figure 2 présentent quelques exemples (région d’intérêt, rotations, symétrie,
zoom) et introduit également un exemple de présentation sous la forme de tableaux d’images.
les fonctions utilisées proviennent à la fois de numpy et de scipy (import de ndimage, ensemble
de fonctions pour le traitement d’images multidimensionnelles). Dans cette série de fonctions, on
trouvera également par exemple la définition de transformations affines ou géométriques génériques,
3
# −∗− c o d i n g : u t f −8 −∗−
from s c i p y import m i s c
from s c i p y import ndimage
import m a t p l o t l i b . p y p l o t a s
import numpy a s np
plt
# o u v e r t u r e d ’ une i m a g e c o u l e u r
j = misc . imread ( ’ h a n d . j p g ’ )
#r e c u p e r a t i o n d e s
n l , nc = j . s h a p e
sur
le
disque
dimensions
# D é f i n i t i o n d ’ une z o n e d i n t é r ê t
f , tab = p l t . s u b p l o t s ( 2 ,
s h a r e y=True )
j_roi = j [160:210 ,530:565]
t a b [ 0 ] . imshow ( j _ r o i , cmap=p l t . cm . g r a y )
tab [ 0 ] . s e t _ t i t l e ( ’ r e g i o n d i n t e r e t ’ )
tab [ 0 ] . a x i s ( ’ o f f ’ )
# v i s u a l i s a t i o n p r é c i s e de l a z o n e d ’ i n t é r ê t
t a b [ 1 ] . imshow ( j _ r o i , cmap=p l t . cm . g r a y , i n t e r p o l a t i o n =’ n e a r e s t ’ )
tab [ 1 ] . s e t _ t i t l e ( ’ p i x e l s ’ )
tab [ 1 ] . a x i s ( ’ o f f ’ )
p l t . show ( )
# s y m é t r i e haut−b a s
f , ax = p l t . s u b p l o t s ( 2 , 2 )
ax [ 0 , 0 ] . imshow ( j , cmap=p l t . cm . g r a y )
ax [ 0 , 0 ] . a x i s ( ’ o f f ’ )
ax [ 0 , 0 ] . s e t _ t i t l e ( ’ o r i g i n a l e ’ )
j _ f l i p = np . f l i p u d ( j )
ax [ 0 , 1 ] . imshow ( j _ f l i p , cmap=p l t . cm . g r a y )
ax [ 0 , 1 ] . a x i s ( ’ o f f ’ )
ax [ 0 , 1 ] . s e t _ t i t l e ( ’ s y m e t r i e ’ )
# rotations
j _ t o u r n e e = ndimage . r o t a t e ( j , 3 0 )
ax [ 1 , 0 ] . imshow ( j _ t o u r n e e , cmap=p l t . cm . g r a y )
ax [ 1 , 0 ] . a x i s ( ’ o f f ’ )
ax [ 1 , 0 ] . s e t _ t i t l e ( ’ r o t a t i o n 1 ’ )
j _ t o u r n e e 2 = ndimage . r o t a t e ( j , 3 0 , r e s h a p e=F a l s e )
ax [ 1 , 1 ] . imshow ( j _ t o u r n e e 2 , cmap=p l t . cm . g r a y )
ax [ 1 , 1 ] . a x i s ( ’ o f f ’ )
ax [ 1 , 1 ] . s e t _ t i t l e ( ’ r o t a t i o n 2 ’ )
p l t . show ( )
#zoom a v e c d i f f é r e n t s f a c t e u r s s u r c h a q u e
j_zoom = ndimage . zoom ( j , [ 3 , 5 ] )
p l t . imshow ( j_zoom , cmap=p l t . cm . g r a y )
plt . t i t l e ( ’ h o m o t h e t i e ’)
plt . axis ( ’ off ’)
p l t . show ( )
axe
Listing 4 – Quelques transformations géométriques
2.2
Mesures radiométriques
Des mesures statistiques peuvent facilement être effectuées sur les images, en utilisant des
fonctions définies à cet effet. Le code 5 présente quelques exemples de ces fonctions. En particulier,
il décrit le calcul et l’affichage de l’histogramme. L’histogramme d’une image numérisée comportant
n pixels, dont les niveaux de gris sont compris dans [0,L-1] est la fonction discrète :
h : [0, L − 1] → R
i
i 7→
n
h(i) donne une approximation de la probabilité d’occurrence de i. Le tracé de h(i) fournit une
description globale de l’apparence de l’image (figure 3) , qui bien que globale, permet quelques
possibilités en traitement d’images. A partir de cet histogramme, de nombreux outils de traitement
d’images peuvent être définis (segmentation par seuillage, réhaussement de contraste, modélisation
de la distribution des niveaux de gris par mélange de gaussiennes...).
4
Figure 2 – Exemple de résultat du code 4
# −∗− c o d i n g : u t f −8 −∗−
from s c i p y import m i s c
from s c i p y import ndimage
import m a t p l o t l i b . p y p l o t a s
import numpy a s np
plt
j = misc . imread ( ’ h a n d . j p g ’ )
#h i s t o g r a m m e de l ’ i m a g e
n b i n s = 256
h = ndimage . h i s t o g r a m ( j , 0 , 2 5 5 , n b i n s )
plt . plot (h)
plt . t i t l e ( ’ h i s t o g r a m m e de l image ’)
plt . xlabel ( ’ niveau de gris ’)
plt . ylabel ( ’ o c c u r r e n c e s ’)
p l t . show ( )
# s t a t i s t i q u e s s i m p l e s s u r l ’ image
print " l a m o y e n n e d e s n i v e a u x d e g r i s d e l ’ i m a g e
print " l e m a x d e s n i v e a u x d e g r i s d e l ’ i m a g e e s t
print " l e m a x d e s n i v e a u x d e g r i s d e l ’ i m a g e e s t
g = ndimage . c e n t e r _ o f _ m a s s ( j )
print " l e c e n t r e d e m a s s e d e s
niveaux
de
gris
e s t " , j . mean ( )
" , j . max ( )
" , j . min ( )
est
en
" ,
g
Listing 5 – Quelques mesures radiométriques sur les images.
2.3
Filtrage
Le filtrage est un domaine important du traitement d’images. Il peut être réalisé dans le domaine
spatial (des pixels) ou fréquentiel (via une transformée de Fourier).
Le terme spatial se réfère à l’ensemble des pixels composant l’image. Tout traitement spatial
peut s’exprimer comme
5
Figure 3 – Quelques exemples d’histogrammes
J(x, y) = T [I(x, y)]
où I est l’image originale, J l’image traitée, et T est un opérateur sur I, défini sur un voisinage
de (x, y). Si ce voisinage est de taille 1, T agit pixel par pixel, et on parle alors d’analyse point à
point. On récupère alors entre autres les méthodes d’analyse d’histogramme, auxquelles on adjoint
toute transformation mathématique i 7→ T (i) (logarithmique, exponentielle, ...).
Nous envisageons dans la suite un voisinage de taille strictement supérieure à 1, centré en (x, y).
et dans ce cadre il existe des filtres linéaires et non linéaires.
Les filtres linéaires sont fondés sur l’hypothèse de linéarité du système d’acquisition. Les filtres
dits passe-bas atténuent ou éliminent les hautes fréquences spatiales dans l’image, en laissant les
basses fréquences intactes. Au contraire, un filtre passe haut laisse intactes les hautes fréquences,
et atténue les basses. Enfin, les filtres passe-bande atténuent ou éliminent une bande de fréquences
donnée.
Quel que soit le type de filtrage spatial linéaire envisagé, la démarche est identique. Il s’agit
de définir autour d’un pixel (x, y) un voisinage W de taille N impaire, centré en (x, y), dont les
coefficients sont par exemple pour N = 3 :
w−1,−1
w0,−1
w1,−1
w−1,0
w0,0
w1,0
w−1,1
w0,1
w1,1
Le filtrage consiste alors simplement en le balayage de l’image par le masque, et en l’affectation au
pixel (x, y) du niveau de gris résultant de la combinaison linéaire des pixels voisins pondérés par
les coefficients du filtre :
1
1
X
X
wi,j I(x − i, y − j)
i=−1 j=−1
6
Le filtrage non linéaire, quant à lui, est également réalisé à partir de voisinages centrés, mais
agit directement à partir des niveaux de gris I(x + i, y + j) par une transformation non linéaire
(max,min, médiane...) ou issue du traitement du signal par exemple (cf. 7 pour un exemple, basé
sur le module scipy.signal).
Les figures 4 et 5 donnent deux exemples de filtrage passe haut (détection de contour : Sobel)
et passe bas (filtrage moyenneur). Les codes 7 et ?? présentent quelques exemples de filtrage. A
noter que bon nombre de fonctions implémentent déjà le filtrage sans qu’il soit nécessaire de définir
explicitement le masque ou les opérations.
1
0
-1
2
0
-2
1
0
-1
-1
-2
-1
0
0
0
1
1
1
Figure 4 – Filtres de Sobel vertical et horizontal
1
9
1
9
1
9
1
9
1
9
1
9
1
9
1
9
1
9
Figure 5 – Filtre moyenneur
7
# −∗− c o d i n g : u t f −8 −∗−
import s c i p y a s s p
from s c i p y import m i s c
from s c i p y import s i g n a l
import numpy a s np
from s c i p y import ndimage
import m a t p l o t l i b . p y p l o t a s
plt
j = misc . imread ( ’ l e n a g r a y . p n g ’ )
# f i l t r e l i n é a i r e : norme du g r a d i e n t a p p r o c h e p a r un
p l t . f i g u r e ( f i g s i z e =(20 ,5) )
dx = ndimage . s o b e l ( j , 0 )
# dérivée horizontale
dy = ndimage . s o b e l ( j , 1 )
#
dérivée verticale
mag = np . h y p o t ( dx , dy )
# norme du g r a d i e n t
mag ∗= 2 5 5 . 0 / np . max ( mag )
# normalisation
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
. subplot (141)
. imshow ( j , cmap=p l t . cm . g r a y )
. title ( ’ originale ’)
. axis ( ’ off ’)
. subplot (142)
. imshow ( dx , cmap=p l t . cm . g r a y )
. t i t l e ( ’ Sobel en x ’)
. axis ( ’ off ’)
. subplot (143)
. imshow ( dy , cmap=p l t . cm . g r a y )
. t i t l e ( ’ Sobel en y ’)
. axis ( ’ off ’)
. subplot (144)
. imshow ( mag , cmap=p l t . cm . g r a y )
. t i t l e ( ’ norme du g r a d i e n t ’)
. axis ( ’ off ’)
. s u b p l o t s _ a d j u s t ( wspace =0.02 ,
. show ( )
#f i l t r e s p a s s e bas
j _ l i s s e e = ndimage .
j _ l i s s e e 2 = ndimage .
j _ l i s s e e 3 = ndimage .
hspace =0.02 ,
gaussiens
gaussian_filter ( j ,
gaussian_filter ( j ,
gaussian_filter ( j ,
filtrage
t o p =1 , bottom =0 ,
de
Sobel
l e f t =0 ,
( cf .
masque d a n s
document )
r i g h t =0.9)
s i g m a =3)
s i g m a =5)
s i g m a =11)
f , tab = p l t . s u b p l o t s ( 2 , 2 ,
s h a r e y=True )
t a b [ 0 , 0 ] . imshow ( j , cmap=p l t . cm . g r a y )
tab [ 0 , 0 ] . s e t _ t i t l e ( ’ o r i g i n a l e ’ )
tab [ 0 , 0 ] . a x i s ( ’ o f f ’ )
t a b [ 0 , 1 ] . imshow ( j _ l i s s e e , cmap=p l t . cm . g r a y , i n t e r p o l a t i o n =’ n e a r e s t ’ )
tab [ 0 , 1 ] . s e t _ t i t l e ( ’ g a u s s i e n 3 ’ )
tab [ 0 , 1 ] . a x i s ( ’ o f f ’ )
t a b [ 1 , 0 ] . imshow ( j _ l i s s e e 2 , cmap=p l t . cm . g r a y , i n t e r p o l a t i o n =’ n e a r e s t ’ )
tab [ 1 , 0 ] . s e t _ t i t l e ( ’ g a u s s i e n 5 ’ )
tab [ 1 , 0 ] . a x i s ( ’ o f f ’ )
t a b [ 1 , 1 ] . imshow ( j _ l i s s e e 3 , cmap=p l t . cm . g r a y , i n t e r p o l a t i o n =’ n e a r e s t ’ )
tab [ 1 , 1 ] . s e t _ t i t l e ( ’ g a u s s i e n 1 1 ’ )
tab [ 1 , 1 ] . a x i s ( ’ o f f ’ )
p l t . show ( )
#R é d u c t i o n de b r u i t : f i l t r a g e non l i n é a i r e median e t f i l t r a g e
j = misc . imread ( ’ h a n d . j p g ’ )
f , ax = p l t . s u b p l o t s ( 2 , 2 ,
s h a r e x=True )
jbruitee = j +
0 . 9 ∗ j . s t d ( ) ∗ np . random . random ( j . s h a p e )
j m e d i a n = ndimage . m e d i a n _ f i l t e r ( j b r u i t e e , 3 )
j d i f f = j m e d i a n−j b r u i t e e
jWiener = sp . s i g n a l . w i e n e r ( j b r u i t e e )
ax [ 0 , 0 ] . imshow ( j b r u i t e e , cmap=p l t . cm . g r a y )
ax [ 0 , 0 ] . s e t _ t i t l e ( ’ o r i g i n a l e b r u i t e e ’ )
ax [ 0 , 0 ] . a x i s ( ’ o f f ’ )
ax [ 0 , 1 ] . imshow ( j m e d i a n , cmap=p l t . cm . g r a y )
ax [ 0 , 1 ] . s e t _ t i t l e ( ’ f i l t r a g e m e d i a n ’ )
ax [ 0 , 1 ] . a x i s ( ’ o f f ’ )
ax [ 1 , 0 ] . imshow ( j d i f f , cmap=p l t . cm . g r a y )
ax [ 1 , 0 ] . s e t _ t i t l e ( ’ d i f f e r e n c e ’ )
ax [ 1 , 0 ] . a x i s ( ’ o f f ’ )
ax [ 1 , 1 ] . imshow ( j W i e n e r , cmap=p l t . cm . g r a y )
ax [ 1 , 1 ] . s e t _ t i t l e ( ’ F i l t r a g e d e W i e n e r ’ )
ax [ 1 , 1 ] . a x i s ( ’ o f f ’ )
non
linéaire
p l t . show ( )
de
Wiener
Listing 6 – Quelques exemples de filtrage.
8
# −∗− c o d i n g : u t f −8 −∗−
from s c i p y import ndimage
import m a t p l o t l i b . p y p l o t a s
import numpy a s np
import math
plt
#i m a g e de s y n t h è s e : r e c t a n g l e
im = np . z e r o s ( ( 2 5 6 , 2 5 6 ) )
tourné
im [ 1 0 0 : − 1 0 0 , 5 0 : − 5 0 ] = 1
im = ndimage . r o t a t e ( im , 3 0 )
im = ndimage . g a u s s i a n _ f i l t e r ( im ,
s x = ndimage . s o b e l ( im ,
s y = ndimage . s o b e l ( im ,
s o b = np . h y p o t ( sx , s y )
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
de 30
degrés
8)
a x i s =0)
a x i s =1 ,)
. f i g u r e ( f i g s i z e =(16 , 5) )
. subplot (151)
. imshow ( im , cmap=p l t . cm . g r a y )
. axis ( ’ off ’)
. t i t l e ( ’ image de s y n t h e s e ’)
. subplot (152)
. imshow ( sx , cmap=p l t . cm . g r a y )
. axis ( ’ off ’)
. t i t l e ( ’ Sobel en x ’)
. subplot (153)
. imshow ( sy , cmap=p l t . cm . g r a y )
. t i t l e ( ’ Sobel en y ’)
. axis ( ’ off ’)
. subplot (154)
. imshow ( sob , cmap=p l t . cm . g r a y )
. axis ( ’ off ’)
. t i t l e ( ’ filtre de Sobel ’)
im += 0 . 1 ∗ np . random . random ( im . s h a p e )
s x = ndimage . s o b e l ( im , a x i s =0 , mode=’ c o n s t a n t ’ )
s y = ndimage . s o b e l ( im , a x i s =1 , mode=’ c o n s t a n t ’ )
s o b = np . h y p o t ( sx , s y )
plt
plt
plt
plt
. subplot (155)
. imshow ( sob , cmap=p l t . cm . g r a y )
. axis ( ’ off ’)
. t i t l e ( ’ S o b e l sur i m a g e b r u i t e e ’ ,)
p l t . s u b p l o t s _ a d j u s t ( wspace =0.02 ,
p l t . show ( )
hspace =0.02 ,
t o p =1 , bottom =0 ,
l e f t =0 ,
r i g h t =0.9)
Listing 7 – Détection de contour par filtrage de Sobel.
2.4
morphologie mathématique
La morphologie mathématique est un outil mathématique permettant au départ d’explorer la
structure géométrique des objets dans une image. Le développement de techniques basées sur ces
outils a ensuite permis d’élargir le champ de ses applications, par exemple dans le domaine du
réhaussement de contraste ou du filtrage.
Vu sous son angle "reconnaissance des formes", le traitement d’images vise à extraire d’une image
donnée des informations de type géométrique (localisation, périmètre, aire, orientation), permettant
de distinguer certains objets dans une scène. La plus grande partie des traitements de ce type
nécessitent le design d’un opérateur de forme, possédant un certain nombre de propriétés attendues
(invariance par translation,...) et permettant de discriminer un objet particulier.
Plusieurs problèmes se posent alors, et notamment le fait que les objets sont opaques, et que
donc l’information de forme n’est pas additive. En fait, les objets dans une scène se combinent
principalement sous deux formes :
– par union ensembliste (recouvrement d’objets) : X = X1 ∪ X2
– par intersection ensembliste (occlusion) : X = X2 \ X1 = X1C ∩ X2
L’opérateur de forme Ψ à construire doit alors se distribuer sur l’ensemble des unions et des
intersections (équivalent de la linéarité) :
9
– Ψδ (X1 ∪ X2 ) = Ψδ (X1 ) ∪ Ψδ (X2 )
– Ψ (X2 \ X1 ) = Ψ (X1 ) ∩ Ψ (X2 )
La première opération va être appelée dans la suite dilatation morphologique, et la seconde érosion
morphologique. Ces deux opérations sont à la base de la morphologie mathématique, à partir desquelles des opérateurs morphologiques plus complexes vont être construits.
2.4.1
Cas des images binaires
Commençons par quelques définitions de base : pour A, B ⊂ Z2 , dont les composantes sont
notées a = (a1 , a2 ) et b = (b1 , b2 ),
– la translation de A par x = (x1 , x2 ), notée (A)x est (A)x = {c = a + x, a ∈ A}
– la réflexion de B, notée B̂ est B̂ = {x = −b, b ∈ B}
– le complément de A, noté AC est AC = {x, x ∈
/ A}
– la différence de A et B est A \ B = A ∩ B C = {x, x ∈ A, x ∈
/ B}
Ici, A sera une image binaire, et B un opérateur de forme binaire.
Définition 1 La dilatation de A par B, notée A ⊕ B est l’ensemble défini par
A ⊕ B = {x, (B̂)x ∩ A 6= }
Définition 2 L’érosion de A par B, notée A B est l’ensemble défini par
A B = {x, (B)x ⊆ A}
B est l’opérateur de forme, et dans le cadre de la morphologie mathématique on l’appelle l’élément
structurant.
En clair, pour un objet A binaire et un élément structurant B binaire lui aussi et symétrique, les
opérations simples de morphologie mathématique consistent à parcourir l’image et à considérer B
comme un masque binaire : si, centré en (x, y), B intersecte A, alors la valeur du dilaté de A par
B en (x, y) vaut 1, et 0 sinon. De même si B n’est pas tout inclus dans A, la valeur de l’érodé de
A par B en (x, y) vaut 0, et 1 (figure 6). Ainsi, l’érosion rapetisse A, et la dilatation l’étend, selon
B (comme les noms sont bien choisis !)
Il est facile de montrer que l’érosion est la transformation duale de la dilatation par rapport à
la complémentation :A B = (AC ⊕ B)C . Ainsi, il est équivalent d’éroder un objet ou de dilater
son complémentaire.
A partir de la dilatation et de l’érosion, on définit deux opérations : l’ouverture et la fermeture.
Définition 3 L’ouverture de A par B est définie par
A ◦ B = (A B) ⊕ B
Définition 4 La fermeture de A par B est définie par
A • B = (A ⊕ B) B
10
Erosion par un élément structurant circulaire
Dilatation par un élément structurant circulaire
Figure 6 – Exemple de dilatation et d’érosion
L’ouverture généralement lisse les contours d’une image, casse les liens étroits entre objets (les
isthmes), et élimine les petits objets isolés (petits au sens de B). Le lissage et le type de lissage
sont déterminés par la forme et la taille de B. La fermeture tend également à lisser les contours,
mais rassemble les objets proches (au sens de B), élimine les petits trous (au sens de B) et connecte
les contours. La figure 7 présente le résultat de l’ouverture morphologique de l’image précédente,
par un élément structurant circulaire.
Figure 7 – Ouverture morphologique par un élément structurant circulaire
La notion de filtrage prend son importance lorsque l’on considère une forme et une taille adaptée
pour B : la figure 8-a présente un tableau d’Henri Matisse (La femme à l’amphore, 1952, un peu
de culture), la figure 8-b une version dégradée par par un bruit vertical, et la 8-c l’image restaurée,
par ouverture morphologique par un élément structurant adapté.
Le code 8 présente ces opérations élémentaires sur une image binaire, et la figure 9 illustre le
résultat
11
image originale
image bruitée
image restaurée
Figure 8 – Exemple de dilatation et d’érosion
# −∗− c o d i n g : u t f −8 −∗−
import s c i p y a s s p
from s c i p y import m i s c
from s c i p y import s i g n a l
import numpy a s np
from s c i p y import ndimage
import m a t p l o t l i b . p y p l o t a s
plt
#é l é m e n t s t r u c t u r a n t 2D en c r o i x
e l = ndimage . g e n e r a t e _ b i n a r y _ s t r u c t u r e ( 2 ,
1)
#i m a g e de s y n t h è s e b i n a i r e a v e c b r u i t
im= np . z e r o s ( ( 1 2 8 , 1 2 8 ) , d t y p e=np . i n t )
im [ 5 0 : − 5 0 , 3 0 : − 3 0 ] = 1
np . random . s e e d ( 2 )
x , y = ( 1 2 8 ∗ np . random . random ( ( 2 , 1 0 0 ) ) ) . a s t y p e ( np . i n t )
im [ x , y ] = 1
e r o s i o n = ndimage . b i n a r y _ e r o s i o n ( im ) . a s t y p e ( im . d t y p e )
d i l a t a t i o n = ndimage . b i n a r y _ d i l a t i o n ( im ) . a s t y p e ( im . d t y p e )
o u v e r t u r e = ndimage . b i n a r y _ d i l a t i o n ( e r o s i o n ) . a s t y p e ( im . d t y p e )
f e r m e t u r e = ndimage . b i n a r y _ e r o s i o n ( d i l a t a t i o n ) . a s t y p e ( im . d t y p e )
p l t . f i g u r e ( f i g s i z e =(20 ,5) )
plt . subplot (171)
p l t . imshow ( im , cmap=p l t . cm . g r a y )
plt . t i t l e ( ’ o r i g i n a l e ’)
plt . axis ( ’ off ’)
plt . subplot (172)
p l t . imshow ( e r o s i o n , cmap=p l t . cm . g r a y )
plt . t i t l e ( ’ e r o s i o n ’)
plt . axis ( ’ off ’)
plt . subplot (173)
p l t . imshow ( im−e r o s i o n , cmap=p l t . cm . g r a y )
plt . t i t l e ( ’ image - e r o s i o n ’)
plt . axis ( ’ off ’)
plt . subplot (174)
p l t . imshow ( d i l a t a t i o n , cmap=p l t . cm . g r a y )
plt . t i t l e ( ’ d i l a t a t i o n ’)
plt . axis ( ’ off ’)
plt . subplot (175)
p l t . imshow ( d i l a t a t i o n −im , cmap=p l t . cm . g r a y )
plt . t i t l e ( ’ dilatation - image ’)
plt . axis ( ’ off ’)
plt . subplot (176)
p l t . imshow ( o u v e r t u r e , cmap=p l t . cm . g r a y )
plt . t i t l e ( ’ o u v e r t u r e ’)
plt . axis ( ’ off ’)
plt . subplot (177)
p l t . imshow ( f e r m e t u r e , cmap=p l t . cm . g r a y )
plt . t i t l e ( ’ f e r m e t u r e ’)
plt . axis ( ’ off ’)
p l t . s u b p l o t s _ a d j u s t ( w s p a c e = 0 . 0 2 , h s p a c e = 0 . 0 2 , t o p =1 , bottom =0 , l e f t =0 ,
p l t . show ( )
r i g h t =0.9)
Listing 8 – Morphologie mathématique binaire.
12
Figure 9 – Morphologie mathématique binaire
2.4.2
Les images en niveaux de gris
Ici, A = I est l’image et B est un élément structurant en niveaux de gris (une fonction).
Définition 5 La dilatation de A par B est
(A ⊕ B)(s, t) =
{I(s − x, t − y) + B(x, y)}
max
(s−x),(t−y)∈DI ,(x,y)∈DB
où DI (resp. Db ) est le domaine de l’image (resp. de l’élément structurant). On a l’habitude
d’illustrer cette définition sur des fonctions 1D (figure 10-a, où I = f ), pour lesquelles la formule
précédente se réécrit
(A ⊕ B)(s, t) =
max
{I(s − x) + B(x)}
(s−x)∈DI ,x∈DB
Illustration du processus de dilatation
Illustration du processus d’érosion
Figure 10 – Illustration de la dilatation en niveaux de gris (d’après [2])
De même, on peut définir l’érosion d’une image en niveaux de gris par un élément structurant
en niveaux de gris :
Définition 6 L’érosion de A par B est
(A B)(s, t) =
{I(s + x, t + y) − B(x, y)}
min
(s+x),(t+y)∈DI ,(x,y)∈DB
13
et l’illustration correspondante en 1D est décrite sur la figure 10-b.
Ces deux définitions permettent là encore de développer des opérations de morphologie mathématique plus complexes (ouverture, fermeture, mais aussi squelettisation, transformation en tout
ou rien, filtrages..).
3
Etude de cas : Segmentation et quantification
Segmenter une image I, c’est trouver une partition de cette dernière, c’est à dire un ensemble
P = (P1 , P2 , · · · Pg ) de parties non vides de I tel que :
1. (∀k 6= l)Pk ∩ Pl = ∅
2. ∪gi=1 Pi = Ω
3. (∀k)Pk 6= ∅
Ces parties peuvent être trouvées directement ou c’est leurs bords qu’il peut être intéressant de
déterminer. Ainsi, la segmentation d’images s’aborde soit à l’aide d’approches régions (on trouve
les Pi ), soit à l’aide d’approches frontières (on trouve les bords des parties). Il n’est pas question ici
de détailler l’ensemble de ces approches, mais de proposer un outil simple de segmentation d’image,
basé sur l’analyse de l’histogramme.
Le code 9 propose une méthode simple de segmentation : à partir d’une image de synthèse
(blobs créés aléatoirement en binaire, puis bruités et transformés en image en niveaux de gris),
l’histogramme est calculé et un seuil à 50% du max des niveaux de gris est appliqué. La figure
11 donne le résultat correspondant. Le seuillage s’opérant sur l’histogramme, aucune information
spatiale n’est prise en compte (seuls les niveaux de gris au dessus de la moitié du max dans l’image
sont comptés comme dans l’objet). On constate alors des blobs piquetés de noir, et un fond piqueté
en blanc. Il faut alors post traiter cette image, puisque l’on suppose que les blobs (et le fond)
doivent être uniformes. On peut par exemple utiliser des outils de morphologie mathématique,
comme il est proposé dans la seconde partie du code 9, ce qui permet d’obtenir l’image finale
segmentée 12. A partir de cette image, un comptage de composantes connexes peut être effectué à
l’aide de la fonction label (module ndimage) (13)
14
# −∗− c o d i n g : u t f −8 −∗−
import s c i p y a s s p
from s c i p y import m i s c
from s c i p y import s i g n a l
import numpy a s np
from s c i p y import ndimage
import m a t p l o t l i b . p y p l o t a s
from m a t p l o t l i b import ∗
plt
n l = 256
n
= 10
#i m a g e de s y n t h è s e ( b l o b s )
im = np . z e r o s ( ( n l , n l ) )
np . random . s e e d ( 1 )
p o i n t s = n l ∗np . random . random ( ( 2 , n ∗ ∗ 2 ) )
im [ ( p o i n t s [ 0 ] ) . a s t y p e ( np . i n t ) , ( p o i n t s [ 1 ] ) . a s t y p e ( np . i n t ) ] = 1
im = ndimage . g a u s s i a n _ f i l t e r ( im , s i g m a=n l / ( 4 . ∗ n ) )
mask = ( im > im . mean ( ) ) . a s t y p e ( np . f l o a t )
mask += 0 . 1 ∗ im
img = mask + 0 . 2 ∗ np . random . r a n d n ( ∗ mask . s h a p e )
#h i s t o g r a m m e de l ’ i m a g e : r e t o u r n e l ’ h i s t o g r a m m e e t
h i s t , c l a s s e s = np . h i s t o g r a m ( img , b i n s =60)
# c e n t r e s des i n t e r v a l l e s
centres_classes = 0.5∗( c l a s s e s [: −1] + c l a s s e s [ 1 : ] )
#s e u i l l a g e ( au d e s s u s de 0 . 5 de l ’ h i s t o g r a m m e )
i m a g e _ s e u i l l e e = img > 0 . 5
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
. f i g u r e ( f i g s i z e =(30 ,6) )
. subplot (131)
. imshow ( img , cmap=p l t . cm . g r a y )
. i m s a v e ( ’ o r i g i n a l e . p n g ’ , img )
. title ( ’ Originale ’)
. axis ( ’ off ’)
. subplot (132)
. plot ( hist )
. title ( ’ histogramme ’)
. xlabel ( ’ niveau de gris ’)
. ylabel ( ’ o c c u r r e n c e s ’)
. subplot (133)
. imshow ( i m a g e _ s e u i l l e e , cmap=p l t . cm . g r a y )
. title ( ’ image segmentee ’)
. axis ( ’ off ’)
. s u b p l o t s _ a d j u s t ( wspace =0.2 , hspace =0.5 ,
. show ( )
les
intervalles
t o p =1 , bottom = . 1 ,
des
classes
l e f t =0 ,
r i g h t =0.9)
l e f t =0 ,
r i g h t =0.9)
# post traitement s p a t i a l
#o u v e r t u r e p o u r s u p p r i m e r l e s p e t i t s o b j e t s b l a n c s du f o n d
o u v e r t u r e = ndimage . b i n a r y _ o p e n i n g ( i m a g e _ s e u i l l e e )
#f e r m e t u r e de c e t t e i m a g e p o u r r e n d r e homogènes l e s o b j e t s
f e r m e t u r e = ndimage . b i n a r y _ c l o s i n g ( o u v e r t u r e )
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
plt
. f i g u r e ( f i g s i z e =(25 ,6) )
. subplot (121)
. imshow ( o u v e r t u r e , cmap=p l t . cm . g r a y )
. title ( ’ Ouverture ’)
. axis ( ’ off ’)
. subplot (122)
. imshow ( f e r m e t u r e , cmap=p l t . cm . g r a y )
. title ( ’ Fermeture ’)
. axis ( ’ off ’)
. s u b p l o t s _ a d j u s t ( wspace =0.2 , hspace =0.5 ,
. show ( )
#c o m p o s a n t e s c o n n e x e s en 4− c o n n e x i t é
s = [[0 , 1 , 0] , [1 ,1 ,1] , [0 ,1 ,0]]
l a b , n b _ o b j e t s = ndimage . l a b e l ( f e r m e t u r e ,
p l t . imshow ( l a b )
plt . t i t l e ( ’ C o m p o s a n t e s c o n n e x e s ’)
plt . axis ( ’ off ’)
p l t . show ( )
top =.9 ,
bottom =0 ,
s)
Listing 9 – Seuillage d’histogramme.
15
Figure 11 – Seuillage d’histogramme
# −∗− c o d i n g : u t f −8 −∗−
import s c i p y a s s p
from s c i p y import m i s c
from s c i p y import s i g n a l
import numpy a s np
from s c i p y import ndimage
import m a t p l o t l i b . p y p l o t a s
plt
img = m i s c . i m r e a d ( ’ o r i g i n a l e . p n g ’ )
f e r m e t u r e = misc . imread ( ’ f e r m e t u r e . p n g ’ )
print ( fermeture )
s = [[0 , 1 , 0] , [1 ,1 ,1] , [0 ,1 ,0]]
l a b , n b _ o b j e t s = ndimage . l a b e l ( f e r m e t u r e ,
s)
#Q u a n t i f i c a t i o n : t a i l l e e t v a l e u r s d e s i n t e n s i t é s d e s r é g i o n s
t a i l l e s = ndimage . sum ( f e r m e t u r e , l a b , r a n g e ( n b _ o b j e t s + 1 ) )
print ( t a i l l e s )
val_moyennes = ndimage . mean ( img , l a b , r a n g e ( 1 , n b _ o b j e t s + 1 ) )
p r i n t ( val_moyennes )
# s u p e r p o s i t i o n d e s c e n t r e s de ma ss e
c e n t r o i d = ndimage . m e a s u r e m e n t s . c e n t e r _ o f _ m a s s ( f e r m e t u r e , l a b , x r a n g e ( 1 , n b _ o b j e t s +1) )
p l t . imshow ( l a b )
for i in range ( nb_objets ) :
p l t . p l o t ( c e n t r o i d [ i ] [ 1 ] , c e n t r o i d [ i ] [ 0 ] , m a r k e r=’ o ’ )
plt . t i t l e ( ’ C e n t r e s de masse ’)
plt . axis ( ’ off ’)
p l t . show ( )
# s u p p r e s s i o n des p e t i t e s composantes
s e u i l = 1200
masque = t a i l l e s < s e u i l
t r o p _ p e t i t e s = masque [ l a b ]
l a b 2=l a b . c o p y ( )
lab2 [ trop_petites ] = 0
p l t . f i g u r e ( f i g s i z e =(25 ,6) )
plt . subplot (121)
p l t . imshow ( l a b )
plt . t i t l e ( ’ Toutes c o m p o s a n t e s ’)
plt . axis ( ’ off ’)
plt . subplot (122)
p l t . imshow ( l a b 2 )
plt . t i t l e ( ’ Plus g r o s s e s c o m p o s a n t e s ’)
plt . axis ( ’ off ’)
p l t . show ( )
connexes
# Classement des composantes connexes
l a b e l s = np . u n i q u e ( l a b 2 )
l a b 2 = np . s e a r c h s o r t e d ( l a b e l s , l a b 2 )
p l t . imshow ( l a b 2 )
plt . t i t l e ( ’ Plus g r o s s e s c o m p o s a n t e s ’)
plt . axis ( ’ off ’)
p l t . show ( )
#r é g i o n d i n t é r ê t d ’ un o b j e c t donné
zone_x , zone_y = ndimage . f i n d _ o b j e c t s ( l a b ==4) [ 0 ]
r e g i o n = im [ zone_x , zone_y ]
p l t . imshow ( r e g i o n )
Listing 10 – quelques outils de quantification.
16
Figure 12 – Seuillage d’histogramme et post traitement spatial
Figure 13 – Composantes connexes
A partir de l’image précédente, il est possible de mesurer les paramètres géométriques et radiométriques des composantes extraites (tailles, niveaux moyens), de ne retenir que les plus grosses
composantes (figure14 , de les classer par taille, de trouver une composante donnée et sa région,
de calculer les centres de masse ... (cf code 10 et figure 15)
17
Figure 14 – Plus grandes composantes connexes
Figure 15 – centres de masse, région d’une composante
18

Documents pareils