La boîte à Tutoriels de Christopher PECAUD

Top

Traitement d'images avec Delphi

Laisser un commentaire

SOMMAIRE

I Introduction
II Comment récupérer les valeurs RGB de chaque pixel contenu dans l’image ?
III Conversion d’une image couleur en niveaux de gris
IV Définition d'un histogramme
V Création d’un histogramme avec Delphi

I Introduction

Dans ce premier tutoriel consacré au traitement d’images, je vais vous montrer comment utiliser les fonctions Delphi pour réaliser des fonctions de traitement d’images. Nous allons dans un premier temps, voir comment il est possible de récupérer la valeur des pixels, et de les traiter. Nous verrons ensuite commet réaliser un histogramme sur une image en niveau de gris.

II Comment récupérer les valeurs RGB de chaque pixel contenu dans l’image ?

Tout d’abord tout ce dont on a besoin pour lire le contenu d’une image se trouve dans l’unité Windows. Il faut donc rajouter dans la partie uses la référence à cette unité.

Uses …, Windows, …;

Maintenant nous allons pouvoir tout mettre en œuvre pour lire chaque pixel. Pour ce faire on a besoin d’un type de données qui va pointer sur chaque pixel et qui va nous retourner sa valeur RGB. C’est-à-dire un triplet de valeur correspondant à ses valeurs en rouge, vert et bleu :

pRGBTripleArray = ^TRGBTripleArray;
TRGBTripleArray = ARRAY[0..PixelCountMax-1] of TRGBTriple;
                

Ces valeurs vont être stockées dans un tableau. Pour créer un tableau de type pRGBTripleArray, il faut déclarer la ligne suivante :

HistogramTab : pRGBTripleArray;

Pour lire les informations contenues dans une image il faut utiliser l’algorithme suivant :

                Pour i := HauteurImage – 1 jusqu’à 0 faire
                  Debut
                  Lire une ligne de pixels
                  Fin			  			
                

Cet algorithme suffit pour récupérer dans un tableau ce que nous voulons. Il faut que l’on crée un tableau de type pRGBTripleArray qui va reccueillir :
La fonction qui permet de lire une ligne de pixels à partir d’une image est Scanline
Cette fonction fait partie de la bibliothèque de fonctions Graphics
Elle s’utilise de la manière suivante :

                Row := Bitmap.scanLine[j]; 
                

Cette opération est simple, mais elle est le point de depart de tout traitement d’images. Nous verrons par la suite que les choses se compliquent. D’ailleurs nous allons étudier la création d’un histogramme à partir d’une image en niveau de gris.

III Conversion d’une image couleur en niveaux de gris

Cette opération consiste à convertir chaque intensité de couleur de pixel en niveaux de gris. Il existe 256 niveaux de gris. Donc pour obtenir un niveau de gris à partir d’un triplet RGB vous devez effectuer l’opération suivante :

                nvGris := (RgbtRed + RgbtGreen + RgbtBlue) DIV 3; 
                

L’algorithme de cette opération devient le suivant :

Pour i := HauteurImage – 1 jusqu’à 0 faire
  Debut
  Lire une ligne de pixels dans tableau tabRGB
  Lire une ligne de pixels dans tableau tabGray
  Pour j:= LargeurImage – 1 jusqu’à 0 faire
    Debut
    Pour chaque pixel
      nvGris := (indexRouge+indexVert+indexBleu) DIV 3
      //affecter aux composantes du tableau tabGray le niveau de gris calculé 
      RgbtRed:=nvGris
      RgbtGreen:=nvGris
      RgbtBlue:=nvGris
    Fin		
 Fin
                

Voici le code correspondant :

procedure TFrmImageFile.ConversionnvGris;
var
   Gray   : INTEGER;
   i      : INTEGER;
   j      : INTEGER;
   rowRGB : pRGBTripleArray;
   rowGRAY: pRGBTripleArray;
begin
   Screen.Cursor := crHourGlass;
   Bitmap.PixelFormat := pf24Bit;
   TRY
      for j := Bitmap.Height - 1 downto 0 do
      begin
         rowRGB := Bitmap.Scanline[j];
         rowGRAY := Bitmap.ScanLine[j];
         for i := Bitmap.Width-1 downto 0 do
         begin
            With rowRGB[i] do
               Gray := (RgbtRed + RgbtGreen + RgbtBlue) DIV 3;
            With rowGray[i] do
            begin
               RgbtRed := Gray;
               RgbtGreen := Gray;
               RgbtBlue := Gray;
            end;
         end;
      end;
   finally
      Screen.Cursor := crDefault;
   end;
   Image1.Picture.Graphic := bitmap;
end;

Cette opération va nous permettre maintenant d’étudier dans la partie suivante de ce tutoriel la création de l’histogramme d’une image en niveau de gris.

IV Définition d’un histogramme

L’histogramme d’une image est une fonction donnant, par exemple, le nombre de pixels à un niveau de gris particulier en fonction du niveau de gris.

Un histogramme peut-être vu comme une fonction de densité de probabilité discrète pour une image individuelle dans le sens suivant : Chaque essai pour l’expérience de probabilité est la sélection d’un pixel au hasard à partir de l’image, et l’événement mesuré est le niveau de gris du pixel choisi.

Quand la fonction de densité de probabilité mesurée pour chaque niveau de gris est multipliée par le nombre de pixels dans l’image, les valeurs obtenues sont celles de l’histogramme.

L’histogramme ne contient aucune information relative à l’emplacement des pixels ni sur la proximité relative de deux pixels. Par contre, l’information qu’il contient peut concerner notamment la brillance apparente et le contraste d’une image, et il est utilisé en traitement d’images pour manipuler ces caractéristiques d’une image.

Une fois que l’histogramme d’une image est connu, les niveaux de gris de l’image peuvent être manipulés pour changer l’histogramme de la manière souhaité. On peut par exemple souhaiter améliorer le contraste, changer le niveau de brillance ou faire correspondre l’histogramme à celui d’une autre image. On rappelle que toute technique de modification de niveaux de gris, dont la modification d’histogramme est un exemple, est basée sur la création d’une correspondance (« mapping ») en anglais) entre les niveaux de gris de l’image originale et les niveaux de gris correspondant dans l’image modifiée.

Dans des applications limitées, l’analyse d’histogramme pour déterminer des seuils a aussi été utilisée. L’histogramme est calculé pour les valeurs d’intensité de l’image et analysé pour déterminer l’établissement d’un seuil permettant de séparer un objet du fond. Souvent les objets, cellules, chromosomes, …, sont tels qu’ils ont des valeurs caractéristiques très différentes de celles du fond. Ce type d’analyse est applicable dans ces cas plus généraux qu’un initialement envisagée.

V Création d’un histogramme avec Delphi

Nous allons prendre, comme base, la technique de base que l’on a énoncé au chapitre précédent, concernant la récupération des valeurs des pixels dans un tableau. En effet dans le cas présent, il va falloir remplir un tableau à deux dimensions ImageMap[x, y] , qui va nous permettre de récupérer les valeurs d’intensité en niveaux de gris de chaque pixel, Ce tableau va nous permettre ensuite de . Il sera ensuite possible de réaliser certain s traitements de base sur l’histogramme lui même, mais ce ne sera pas abordé dans ce tutoriel. L’algorithme que l’on va utiliser pour l’établissement de l’histogramme est le suivant :

Pour i := LargeurImage – 1 jusqu’à 0 faire
  Début
  Lire une ligne de pixels
  Pour j := LongueurImage jusqu’à 0 faire
    Début
    Pour chaque pixel faire
      ImageMap[j, i] := valeur intensité rouge
      index := valeur intensité rouge
      HistTab[index] := HistTab[index] + 1
      Tester ImageMap [j,i] si supérieur à MaxColor
      Tester ImageMap [j,i] si inférieur à MinColor
    Fin
Fin
                

Voici donc les points les plus importants qui vont nous permettre de réaliser la création d’un histogramme. Maintenant passons à la programmation de ce petit algorithme. Il faut d’abord déclarer un tableau ImageMap dynamiquement et l’initialiser :

                Var ImageMap : array of array of byte ;
                

Le type byte nous suffit, puisque nous avons que 256 niveaux de gris dans une image. Et l’initialisation se fait comme suit :

                Setlength(ImageMap, ImageColumns, ImageArrows) ;
                

La variable index reçoit la valeur d’intensité rouge du pixel. En effet pour une image en niveau de gris, les valeur d’intensité rouge, verte et bleue sont identiques. Donc on a :

index := row[j].rgbtRed;

et on a aussi :

inc(HistTab[index]) ;


ceci permet d’incrémenter d’une unité le nombre de pixels correspondant à l’index de niveau de gris. Maintenant que l’opération de remplissage du tableau HistTab est réalisé, il vous reste à réaliser l’opération d’affichage graphique de ces valeurs. Je vous laisse réaliser cette opération à votre convenance. Il est de plus possible de réalisé des opérations sur cet histogramme comme le moyennage, mais nous n’en parlerons pas dans ce tutoriel, le but de celui-ci est de vous donner les bases de programmation concernant le traitement des images.

Je vous donne le code complet de la procédure InitialiseTab :

procedure THistogram.InitialiseTab;
var i, j : integer;
    index : byte;
    Row : pRGBTripleArray;
begin

   SetLength(ImageMap, TabColumns, TabArrows);
   for j := TabArrows - 1 downto 0 do
      begin
      Row := Bitmap.scanLine[j];
         for i := TabColumns - 1 downTo 0 do
             begin
             with row[i] do
             begin
             ImageMap[i][j] := rgbtRed;
             index := rgbtRed;
             end;
             GetHistogramTab(index);
             if ImageMap[i][j] > MaxColor then
                 MaxColor := ImageMap[i][j];
             if ImageMap[i][j] < MinColor then
                 MinColor := ImageMap[i][j];
             end;


      end;



end;

Et maintenant voici la procédure GetHistogramTab :

procedure THistogram.GetHistogramTab(index: byte);
var i, j : integer;
begin

inc(HistTab[index]);


end;

Et maintenant, voici voici la procédure qui dessine l'histogramme :

procedure THistogram.Paint;
var i : integer;
begin
inherited Paint;
HauteurGraphMax := Height ;
EchelleY := HauteurGraphMax / GetMaxCount;


with Canvas do
  begin
  Pen.Color := ClBlack;
  Brush.Color := ClWhite;
  FillRect(Rect(0, 0, Width, Height));
  MoveTo(16, 10);
  LineTo(16, Round(GetMaxCount * EchelleY));
  LineTo(MaxColor+16, Round(GetMaxCount * EchelleY));
  for i := 0 to GetMaxCount do
  begin
  if ((i mod 50) = 0) then
     TextOut(0, Round((GetMaxCount * EchelleY) - (i * EchelleY)), 
                IntTostr(i));
  end;
  //Mise en place des légendes du graphe
  TextOut(0, Round(GetMaxCount * EchelleY)-16, '0');
  TextOut(0, 0, IntToStr(GetMaxCount));
  TextOut(MaxColor, Round(GetMaxCount * EchelleY)-16, IntToStr(MaxColor));
  TextOut(20,10,'Statistique :');
  TextOut(20,30,'Valeur Min :' + IntTostr(GetMinCount) + '     Nv. Gris :' + 
                                IntTosTr(AbsMinColor));
  TextOut(20,50,'Valeur Max :' + IntTostr(GetMaxCount) + '     Nv. Gris :' + 
                                IntTosTr(AbsMaxColor));

  end;

for i := 0 to MaxColor do
  begin
  Canvas.MoveTo(16 + i, Round(GetMaxCount * EchelleY)-16);
  Canvas.LineTo(16 + i, Round((GetMaxCount * EchelleY) - 
                              (HistTab[i]  * EchelleY))-16);

  end;


end;