Millie : Bibliothèque de traitement d'images (C++)
Date de publication : 5/05/2007 , Date de mise à jour : 5/05/2007
Je vais présenter dans ce petit article la bibliothèque de traitement et d'analyse des images : Millie
(Multifunctional Library for Image processing). Cette bibliothèque est toujours en cours de développement
I. Description du projet
II. Opérations actuellement disponibles
III. Installation et téléchargement
III-A. Compilation Sous Windows
III-B. Compilation sous Linux
III-C. Options de compilation
IV. Quelques exemples
IV-A. Chargement et sauvegarde d'images
IV-B. Convolution
IV-C. Passage dans le domaine HSL
V. Passage dans le domaine de Fourier
V-A. Allée et retour
V-B. Un filtre passe-bas
V-C. Un filtre passe-haut
V-D. Flou gaussien dans l'espace de Fourier
V-E. Flou de bougé
VI. Filtre médian
VI. Opérateur de Nagao
VIII. Filtres morphologiques
VIII-A. Erosion
VIII-B. Dilatation
IX. Ajout de bruit
IX-A. Bruit gaussien
IX-B. Bruit uniforme
X. Filtre de Perona Malik
XI. Au pays des threads
XI-A. Convolution multithreadée
XI-B. Perona Malik
XII. Exemples de création de filtres
I. Description du projet
Millie est une bibliothèque portable de traitement et d'analyse des images réalisée
en C++ et fait pour ce langage. Cette bibliothèque est sous licence GPL.
Cette bibliothèque ne compte pas révolutionner le genre,
mais la conception de celle-ci avait été originalement faite afin que les personnes cherchant à
implémenter ou à comprendre des algorithmes de traitement des images
puissent s'inspirer de ces sources.
La bibliothèque se veut simple à utiliser et simple à comprendre (ce n'est pas toujours le cas).
Actuellement, je suis en train de revoir un peu la conception
pour permettre l'ajout de filtre multithread à partir de la version monothread
le plus simplement possible.
Pour un fonctionnement optimal, la bibliothèque nécessite pour la compilation de disposer
des bibliothèques suivantes : SDL (chargement et sauvegarde de BMP), SDL_Image
(chargement d'autres formats), fftw (pour appliquer des transformées de Fourier),
pthread (pour le multi-thread). Il est cependant possible de les désactiver.
II. Opérations actuellement disponibles
Pour l'instant, la bibliothèque, avec toutes les bibliothèques associées, permet de :
- Charger des images BMP
- Sauvegarder des images BMP
- Sauvegarder des images JPG
- Définir des noyaux de convolution
- Appliquer des noyaux de convolution
- Etendre les bords des images (extension constante, extension nulle,
extrapolation simple)
- Effectuer des rotations
- Effectuer des flips horizontaux et verticaux
- Conversion d'image RGB en HSL ou YUV (et vice et versa)
- Filtre de Nagao
- Filtre de Canny
- Filtre médian
- Seuillage binaire
- Génération de bruit gaussien et de bruit uniforme
Elle permet également d'effectuer des opérations dans le domaine de Fourier :
- appliquer une transformée de Fourier à une image
- Appliquer des filtres dans l'espace de Fourier (flou gaussien, filtre passe-bas,
passe-haut, passe-bas de type butterworth, passe-haut de type butterworth)
- convertir le module d'une image complexe en une image normale
De nombreux opérations basées sur les équations de diffusion :
- diffusion par la méthode de Tikhonov
- diffusion par la méthode des hypersurface
- filtre de choc (normal, gaussienne, complexe)
- filtre de Perona et Malik (plusieurs implémentations possibles
Ainsi que quelques opérateurs morphologiques :
- érosion
- dilation
- ouverture
- fermeture
De plus, certains opérateurs ont également des équivalents multithreadés :
- Filtres de Perona et Malik
- Convolution
III. Installation et téléchargement
Sous linux/Unix, il vous est possible de tout recupèrer via la commande :
svn co http://subversion.developpez.com/projets/Millie/ . dans le repértoire désiré.
Il est également possible de le récuperer de cette manière sous Windows en utilisant
un client SVN.
III-A. Compilation Sous Windows
Pour windows, il y a un unique fichier Code::blocks qu'il vous faudra utiliser.
III-B. Compilation sous Linux
Sous linux, il vous faut effectuer les commandes suivantes :
./ autogen.sh
./ configure
make
|
III-C. Options de compilation
Il est possible d'effectuer quelques règlages lors de la compilation.
Ajouter le flag _MILLIE_WITH_SDLIMAGE_ (donc -D_MILLIE_WITH_SDLIMAGE_)
pour activer la bibliothèque SDL_Image
Ajouter le flag _MILLIE_WITHOUT_SDL_ pour désactiver SDL.
Si vous appelez alors une fonction qui utilisant SDL (par exemple pour le chargement
des images), une exception sera lançée.
Ajouter le flag _MILLIE_WITHOUT_FFTW_ pour désactiver fftw.
Ajouter le flag _MILLIE_DANGEROUS_OPTIMIZATIONS_ pour ajouter des optimisations
dangereuses. Par exemple, pour les buffers, il y a des tests d'accès hors zone et lancer
d'exception le cas échéant. Vous pouvez désactiver ces tests et ces exceptions
en activant ce flag.
IV. Quelques exemples
IV-A. Chargement et sauvegarde d'images
Voici un premier exemple qui montre le chargement et la sauvegarde
d'images BMP en niveau de gris :
using namespace Millie;
int main (void )
{
ImageGray im;
try
{
ImageIO:: loadBMPRedComponent (im, " lenna.bmp " );
}
catch (Exception & e)
{
std:: cerr< < e.what ()< < std:: endl;
return EXIT_FAILURE;
}
try
{
ImageIO:: saveBMP (im, " extendc.bmp " );
}
catch (Exception & e)
{
std:: cerr< < e.what ()< < std:: endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
|
Il est également possible de charger une image couleur JPG, par exemple :
using namespace Millie;
int main (void )
{
ImageRGB im;
try
{
ImageIO:: loadJPG (im, " lenna.jpg " );
}
catch (Exception & e)
{
std:: cerr< < e.what ()< < std:: endl;
return EXIT_FAILURE;
}
try
{
ImageIO:: saveBMP (im, " extendc.bmp " );
}
catch (Exception & e)
{
std:: cerr< < e.what ()< < std:: endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
|
IV-B. Convolution
Une convolution se fait en deux étapes. Une étape où l'on définie le noyau,
et une étape où on appliquer la convolution.
Par exemple, si l'on souhaite appliquer un filtre de Sobel :
using namespace Millie;
int main (void )
{
ImageRGB im;
try
{
ImageIO:: loadJPG (im, " lenna.jpg " );
}
catch (Exception & e)
{
std:: cerr< < e.what ()< < std:: endl;
return EXIT_FAILURE;
}
float fKernel[] = {
- 1 ,0 ,1 ,
- 2 ,0 ,2 ,
- 1 ,0 ,1 } ;
Kernel k (3 ,3 ,1 ,1 , fKernel);
convolveOperator (save, im, k);
try
{
ImageIO:: saveBMP (save, " extendc.bmp " );
}
catch (Exception & e)
{
std:: cerr< < e.what ()< < std:: endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
|
Voici un exemple :
Qui donne en résultat :
Evidemment, il est également possible d'appliquer la fonction convolveOperator
sur des images en niveau de gris.
Vous devez savoir que lorsque l'on applique une convolution, il y a des problèmes
sur les bords pour calculer les valeurs de la convolution. La fonction convolveOperator
que l'on a vu tronque les bords. Pour parer le problème, il faut utiliser des BorderExtender
KernelMDIF kernelMDIF;
BorderExtenderNull extenderNull;
convolveOperator (save, im, kernelMDIF, extenderNull);
BorderExtenderCopy extenderCopy;
convolveOperator (save, im, kernelMDIF, extenderCopy);
|
Voici un exemple avec KernelLaplace sur l'image du papillon :
IV-C. Passage dans le domaine HSL
Voici quelques exemples de passage dans le domaine HSL (Hue saturation light)
ImageHSL hsl;
RGBToHSL (hsl, im);
hsl.addToSaturation (50 );
HSLToRGB (save, hsl);
|
ImageHSL hsl;
RGBToHSL (hsl, im);
hsl.addToHue (80 );
HSLToRGB (save, hsl);
|
V. Passage dans le domaine de Fourier
V-A. Allée et retour
Voici un exemple d'un passage dans le domaine de Fourier. De conversion
du module vers une image RGB et la transformée inverse.
ImageComplex c (3 );
ImageRGB module;
DFT:: forwardCompute (c, im);
ModuleImageComplexToVisibleImage (module, c);
DFT:: backwardCompute (save, c);
|
V-B. Un filtre passe-bas
Voici un exemple d'application de filtre passe-bas dans le domaine de Fourier
ImageComplex c (3 );
ImageComplex cOut (3 );
CMaskFactoryLowPass lowpass (50 );
DFT:: forwardCompute (c, im);
cfilterOperator (cOut, c, lowpass);
DFT:: backwardCompute (save, cOut);
|
V-C. Un filtre passe-haut
ImageComplex c (3 );
ImageComplex cOut (3 );
CMaskFactoryHighPass highpass (40 );
DFT:: forwardCompute (c, im);
cfilterOperator (cOut, c, highpass);
DFT:: backwardCompute (save, cOut);
|
V-D. Flou gaussien dans l'espace de Fourier
ImageComplex c (3 );
ImageComplex cOut (3 );
CMaskFactoryGaussianBlur gauss (0 .1 );
DFT:: forwardCompute (c, im);
cfilterOperator (cOut, c, gauss);
DFT:: backwardCompute (save, cOut);
|
V-E. Flou de bougé
ImageComplex c (3 );
ImageComplex cOut (3 );
CMaskFactoryMotionBlur motion (0 .1 , 1 ,1 );
DFT:: forwardCompute (c, im);
cfilterOperator (cOut, c, motion);
DFT:: backwardCompute (save, cOut);
|
VI. Filtre médian
Voici l'image d'origine :
medianFilterOperator (save, im, 2 );
|
Voici un autre exemple. On applique 3 fois le filtre médian :
medianFilterIterativeOperator (save, im, 2 , 3 );
|
VI. Opérateur de Nagao
Cet opérateur s'utilise très simplement :
VIII. Filtres morphologiques
Les filtres d'érosions, de dilatation, de fermeture et d'ouverture sont implémentés. D'origine,
le noyau choisi est de la forme 0,1,0,1,1,1,0,1,0
VIII-A. Erosion
VIII-B. Dilatation
dilateOperator (save, im);
|
IX. Ajout de bruit
IX-A. Bruit gaussien
gaussianNoiseGenerator (save, im, 200 , 0 );
|
IX-B. Bruit uniforme
uniformNoiseGenerator (save, im, 100 );
|
X. Filtre de Perona Malik
SimplePeronaMalikFilter filter;
filter.compute (save, im, 5 , 0 .1 , 20 );
|
Voici un exemple face au bruit gaussien précédent :
NeighbourPeronaMalikFilter filter;
filter.compute (save, im, 5 , 0 .1 , 50 );
|
Il existe la version équivalente à base de Solver et de Flow.
NeighbourPeronaMalikFlow flow (lambda);
PeronaMalikSolver solver;
solver.compute (out, in, flow, dt, nbiter);
|
XI. Au pays des threads
Actuellement, seulement quelques opérateurs ont un équivalent multithreadé. J'ai
effectué des tests de performances sur des stations Sun sous Solaris.
Avec un bi-processeur et un quadri-processeur.
Sur le bi-processeur, avec deux threads, les opérations ont tendance à être
deux fois plus rapide, ce qui est trop bon.
Sur le quadri-processeur, avec quatre threads, les opérations vont à peu près 3 à 3.5 fois plus
vite. Ce qui est intéressant et non négligeable.
XI-A. Convolution multithreadée
MTconvolveOperator (save, im, kernel);
MTconvolveOperator (save, im, kernel, 4 );
|
XI-B. Perona Malik
MTNeighbourPeronaMalikFilter filter (5 );
filter.compute (save, im, 5 , 0 .1 , 50 );
|
Ou la version équivalente à base de Solver
NeighbourPeronaMalikFlow flow (lambda);
MTPeronaMalikSolver solver (3 );
solver.compute (out, in, flow, dt, 50 );
|
XII. Exemples de création de filtres
Voici un exemple de création du filtre de Flip vertical pour voir comment ça fonctionne :
void Millie:: verticalFlipOperator (Image& out, const Image& in)
{
if (out.getNumComponents () ! = in.getNumComponents ())
throw IllegalArgument (" verticalFlipOperator " );
out.resize (in.getWidth (), in.getHeight ());
int largeur = out.getWidth ();
int hauteur = out.getHeight ();
for (int canal= 0 ; canal< out.getNumComponents (); canal+ + )
for (int j = 0 ; j< hauteur; j+ + )
for (int i = 0 ; i< largeur; i+ + )
out.setPixel (i,hauteur- j, canal, in.getPixel (i,j, canal));
}
|
Les sources présentées sur cette page sont libres de droits
et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation
constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ©
2006 Florent HUMBERT. Aucune reproduction, même partielle, ne peut être
faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc.
sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à
trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.