Julien Jorge

Mon CV en ligne, en plus divertissant que la version papier.

Filtres graphiques

Présentation

Il y avait un truc qui me trottait dans la tête depuis plusieurs années, une idée en tâche de fond que j'ai enfin pu concrétiser. L'idée, toute simple, est d'implémenter des algorithmes de traitement d'image. D'une part parce que ce n'était pas une chose qui me semblait évidente, d'autre part parce que le traitement d'image peut parfois être long et que je trouve intéressant d'améliorer le temps d'exécution d'un algorithme. Comme j'avais un peu de temps libre en la mi-janvier de cette année 2005, j'ai posé les base du programme et je me suis lancé sur l'Internet à la recherche d'informations sur ce domaine.

Les bases

L'image de base
L'image de test considérée sera ce joli dessin de Sangoku.

Premièrement, on ne va pas s'embêter avec tout un tas de format d'images. L'objectif étant d'implémenter des algorithmes de transformation, des filtres, des opérations. Donc on ne prendra que des bitmaps en 24 bpp en entrée, on sauvegardera dans ce même format et on manipulera les pixels ARGB (avec A=255 par défaut).

Ensuite, on ne perd pas de temps à faire une interface inutilement jolie. On prendra en paramètre du programme un fichier texte, facilement éditable, qui contiendra les informations dont on aura besoin.

Enfin, on va uniformiser l'utilisation des filtres. On définira les paramètres à l'instanciation de la classe et on appliquera toujours le filtre de la même façon ; genre une simple méthode « appliquer à telle image ». On utilisera un générateur, une « factory », pour générer les filtres à partir de leur nom.

L'écriture de la classe gérant les fichiers bitmap est très rapide, d'autant que j'avais déjà manipulé ce format d'image auparavant. Puis viens la définition du script passé en entrée, avec dans l'ordre :

Avec des commentaires insérables un peu n'importe où. Il ne reste plus qu'à modéliser les filtres : une classe abstraite avec une méthode virtuelle « appliquer() » définie par les classes filles et c'est parti, on peut commencer à écrire des algorithmes.

J'ai aussi implémenté le filtre de flou de vitesse (zoom) en tant que plugin pour VirtualDub. Ce sera présenté en bas de page.

Les filtres implémentés

Certains filtres ne rendent pas super bien via les aperçus suivants. Cliquez sur les images pour les voir en taille réelle. Les algorithmes on généralement une complexité linéaire en fonction du nombre de pixels de l'image de destination. Je ne présente pas ci dessous les filtres effectuant une opération logique (bit à bit) entre deux images.

Accentuer

Résultat de l'application du filtre
Résultat du filtre « accentuer ».

Ce filtre accentue les détails de l'image.

Un filtre basé sur une matrice 5 x 5. Très simple à mettre en œuvre. Les filtres à base de matrices héritent d'un classe gérant l'application de la matrice à l'image, elles n'ont juste à définir le contenu de leur matrice. Pas de grandes difficultés mais une procédure un peu lente.

Adoucir

Résultat de l'application du filtre
Résultat du filtre « adoucir ».

Ce filtre adoucit les détails de l'image par un léger flou. C'est encore un filtre à base de matrice.

Flou

Résultat de l'application du filtre
Résultat du filtre « flou ».

Un autre filtre basé sur une matrice, qui rend une image floue.

Contours

Résultat de l'application du filtre
Résultat du filtre « contours ».

Encore un filtre basé sur une matrice. Celui-ci détecte les contours de l'image.

Redimensionnement « taille de pixel »

Résultat de l'application du filtre
Résultat du filtre « redimensionnement taille de pixel ».

Certainement la méthode de redimensionnement la plus intuitive, et aussi la plus rapide.

Redimensionnement par interpolation linéaire

Résultat de l'application du filtre
Résultat du filtre « redimensionnement linéaire ».

Un redimensionnement d'image qui suppose la couleur des pixels de l'image de destination en moyennant les couleurs dans l'image source.

Le résultat sur de grands redimensionnements de petites images est un peu décevant, la moyenne des pixels ayant tendance à virer au gris sur de grandes distances. Il est par contre tout à fait satisfaisant sur des images quelconques.

Flou de vitesse (zoom)

Résultat de l'application du filtre
Résultat du filtre « flou de vitesse ».

Les pixels les plus éloignés du centre (à préciser en paramètre) ont l'air de se rapprocher de nous.

L'effet n'étant pas très parlant sur Sangoku, je vous mets une photo d'une situation plus adaptée.

Incrustation par transparence

Résultat de l'application du filtre
Résultat du filtre « incrustation par transparence ».

On ajoute sur l'image initiale le motif (image du motif) avec une opacité à 25 %. Très facile.

Rotation

Résultat de l'application du filtre
Résultat du filtre « rotation ».

Ce filtre tourne l'image d'un angle donné, en adaptant la taille de l'image de destination.

Pour l'exemple, un angle de 30° est appliqué dans le sens horaire, un bleu est utilisé en couleur de remplissage.

Il a fallut un petit peu de trigonométrie et un peu de réflexion pour trouver comment calculer la nouvelle taille du support. Les rotations modulo 90° sont optimisées pour ne pas utiliser d'opérations de trigonométrie.

Pixelisation

Résultat de l'application du filtre
Résultat du filtre « pixelisation ».

Ce filtre fait de gros pixels. Rien de bien compliqué.

Négatif

Résultat de l'application du filtre
Résultat du filtre « negatif ».

Un non logique sur chaque pixel.

Inversion verticale

Résultat de l'application du filtre
Résultat du filtre « inversion verticale ».

Retournement vertical de l'image. On échange les pixel d'une moitié d'image avec leurs symétriques.

Inversion horizontale

Résultat de l'application du filtre
Résultat du filtre « inversion horizontale ».

Retournement horizontal de l'image. On échange les pixel d'une moitié d'image avec leurs symétriques.

Niveaux de gris

Résultat de l'application du filtre
Résultat du filtre « niveaux de gris ».

On remplace chaque composante de chaque pixel par la valeur de la luminosité du pixel (256 niveaux de gris mais on reste en 32 bpp). La difficulté été de trouver sur le web un moyen de calculer la luminosité d'un pixel. La formule est L = 0,715160 x R + 0,212671 x V + 0,072169 x B

Si vous aimez les calculs entiers avec divisions par décalage vous apprécierez la formule L = (R x 183 + V x 54 + B x 18) / 256, mais vous l'auriez certainement trouvé seul.

Bump mapping

Résultat de l'application du filtre
Résultat du filtre « bump mapping ».

Un spot d'un rayon de 400 pixels, pointé sur le centre de l'image et une petite texture pour le relief. Bon évidemment l'intérêt du bump mapping dans la 2D et plutôt limité, mais ça reste intéressant à coder.

Flou de vitesse pour VirtualDub

Peut-être avez-vous déjà eu l'occasion d'utiliser ce merveilleux logiciel qu'est VirtualDub ? Il s'agit d'un logiciel de traitement de vidéos, pour lequel il est possible d'écrire des filtres sous la forme de plugins. J'ai repris le filtre de flou de vitesse présenté ci-dessus pour en faire un plugin. Le résultat, bien que pas du tout optimisé, est satisfaisant : voyez la vidéo avant et la vidéo après.

Ce qui est amusant, c'est qu'avec la méthode utilisée pour appliquer le filtre, je peux faire un plugin pour chacun des filtres présentés dans la partie du même nom.

Téléchargement

Le code des filtres, pour Windows comme pour Linux.

Le code source du plugin pour VirtualDub, ou encore le plugin seul.