File : morphological.adb


--                              -*- Mode: Ada -*-

-- Filename        : morphological.adb

-- Description     : Package d'opérateurs morphologiques


-- Package d'opérators morphologiques


with Open_Image.Greyscale_Image;
use Open_Image.Greyscale_Image;

with Open_Image;use Open_Image;

Package body Morphological is

   -- Définition d'un pixel, en autorisant l'attribution d'un pixel en dehors de

   -- l'image, le pixel n'est alors pas définit

   procedure Set_Pixel_Unbounded(M : in out Unbounded_image ; X,Y:in Integer; Value : in pixel_value_type) is
   begin
      if X>=1 and X<=Integer(Columns(M)) then
         if Y>=1 and Y<=Integer(Rows(M)) then
            Set_Pixel(M,Column_Index_Type(X),Row_Index_Type(Y),value);

         end if;
      end if;
   end;

   -- Récupération d'un pixel en attribuant une valeur lorsque le pixel

   -- est en dehors de l'image

   function Get_Pixel_unbounded(Img:in Unbounded_Image;X,Y: in Integer ;Default:in Pixel_Value_Type) return Pixel_Value_Type is
    RetVal : pixel_value_type := default;
   begin
      if X>=1 and X<=Integer(Columns(Img)) then
         if Y>=1 and Y<=Integer(rows(Img)) then
            Retval := Get_Pixel(Img,Column_Index_Type(X),Row_Index_Type(Y));
         end if;
      end if;
      return Retval;
   end;

   function Max(X,Y:in pixel_value_type) return pixel_value_type is
   begin
      if X>Y then
         return X;
      else
         return Y;
      end if;
   end;

   function Min(X,Y:in pixel_value_type) return pixel_value_type is
   begin
      if X<Y then
         return X;
      else
         return Y;
      end if;
   end;


   function GetMax(M : in unbounded_image;Pattern : in unbounded_image; X: in Column_Index_Type ; Y:in row_index_type ) return pixel_value_type is
      PatternMaxpx : Pixel_Value_Type := 255;
      Retval : pixel_value_type:= 0;
   begin
      -- Initialisation De La Premiere Variable

      for I in 1..Columns(Pattern) loop
         for J in 1..rows(Pattern) loop
            -- teste si on est dans la matrice

            if Get_Pixel(pattern,i,j)=Patternmaxpx then
               Retval := Max(Retval,Get_Pixel_unbounded(M,Integer(X+I-1),Integer(Y+J-1),0));
            end if;
         end loop;
      end loop;
      return Retval;
   end;




   function Dilate(Imgin : in Unbounded_image ;Pattern : in Unbounded_image ) return Unbounded_Image is
      RetImg : unbounded_image;
      Pixvalue,alt : Pixel_Value_type;

   begin
      Retimg := Imgin; -- Par copie

      for j in 1..Rows(Imgin) loop
         for i in 1..Columns(Imgin) loop

            -- Récupération de l'altitude maximale

            Alt := GetMax(imgin,pattern,I,J);

            for K in 1..rows(Pattern) loop
               for L in 1..columns(Pattern) loop
                  Pixvalue := Get_Pixel_unbounded(retimg,Integer(i+L-1),Integer(j+K-1),0);
                  if Get_Pixel(Pattern,L,k) = 255 then
                     set_pixel_unbounded(retimg,Integer(I+L-1),Integer(J+K-1),Max(pixvalue,Alt));
                  end if;
               end loop;
            end loop;


         end loop;
      end loop;
      return Retimg;
   end;




   function Inverse(Imgin : in Unbounded_Image) return Unbounded_Image is
      Retval : Unbounded_Image;
   begin
      Set_Size(Retval,Columns(Imgin),Rows(Imgin));
      for I in 1..Columns(Imgin) loop
         for J in 1..Rows(Imgin) loop
            Set_Pixel(Retval,I,J,255-Get_Pixel(Imgin,I,J));
         end loop;
      end loop;
      return Retval;
   end;

   function "-"(Left,Right:in Unbounded_Image) return Unbounded_Image is
      Retval : Unbounded_Image;
   begin
      if Columns(Left)/=Columns(Right) or Rows(Left)/=Rows(Right) then
         raise Invalid_Size;
      end if;
      Set_Size(Retval,Columns(left),Rows(left));
      for I in 1..Columns(left) loop
         for J in 1..Rows(left) loop
            if Integer(Get_Pixel(left,I,J))-Integer(Get_Pixel(right,I,J))>=0 then
              Set_Pixel(Retval,I,J,Max(0,Get_Pixel(left,I,J)-Get_Pixel(right,I,J)));
            else
               Set_Pixel(Retval,I,J,0);
            end if;

         end loop;
      end loop;
      return Retval;
   end;

   function "+"(Left,Right:in Unbounded_Image) return Unbounded_Image is
      Retval : Unbounded_Image;
   begin
      if Columns(Left)/=Columns(Right) or Rows(Left)/=Rows(Right) then
         raise Invalid_Size;
       end if;
      Set_Size(Retval,Columns(left),Rows(left));
      for I in 1..Columns(left) loop
         for J in 1..Rows(left) loop
            if Integer(Get_Pixel(left,I,J))+Integer(Get_Pixel(right,I,J))>255 then
               Set_Pixel(Retval,I,J,255);
            else
               Set_Pixel(Retval,I,J,Max(0,Get_Pixel(left,I,J)+Get_Pixel(right,I,J)));
            end if;
         end loop;
      end loop;
      return Retval;
   end;

   -- L'erosion est une dilatation en utilisant une inversion

   function Erode(Imgin : in Unbounded_image ;Pattern : in Unbounded_image) return Unbounded_Image is
      Retval : Unbounded_Image;
   begin
      Retval := Inverse(Dilate(Inverse(Imgin),Pattern));
      return Retval;
   end;


   function TopHat(Imgin: in Unbounded_image ; Pattern : in Unbounded_image ) return Unbounded_Image is
     Retval : Unbounded_Image;
   begin
      Retval := Imgin-Dilate(Erode(Imgin,pattern),Pattern);
      return Retval;
    end;


   function Closing(Imgin: in Unbounded_image ; Pattern : in Unbounded_image )
                   return Unbounded_image
   is
      Result : Unbounded_image;
   begin
      return Erode(Dilate(Imgin,Pattern),Pattern);
   end Closing;


  function Opening(Imgin: in Unbounded_image ; Pattern : in Unbounded_image )
                   return Unbounded_image
   is
      Result : Unbounded_image;
   begin
      return Dilate(Erode(Imgin,Pattern),Pattern);
   end Opening;


   -- Optimized Version for square patterns ..




   -- Fonction utilisée pour les opérateur morphologiques accélérés

   -- Les Fonctions accélérées fonctionnent avec des patterns rectangulaires

   function  GetMax( M : in Unbounded_Image ; PatternSizeX : in Column_Index_Type; PatternSizeY : in Row_Index_Type ; X : Column_Index_Type; Y : Row_Index_Type ) return Pixel_Value_Type is
      Retval : pixel_value_type:= 0;
   begin
      for I in 1..PatternSizeX loop
         for J in 1..PatternSizeY loop
            Retval := Max(Retval,Get_Pixel_unbounded(M,Integer(X+I-1),Integer(Y+J-1),0));
         end loop;
      end loop;
      return Retval;
   end ;




   -- faster execution

   function Dilate(Imgin : in Unbounded_Image ; SizeX, SizeY : in Integer ) return Unbounded_Image is
      RetImg : unbounded_image;
      Pixvalue,alt : Pixel_Value_type;
   begin
      Retimg := Imgin; -- Par copie

      for j in 1..Rows(Imgin) loop
         for i in 1..Columns(Imgin) loop

            -- Récupération de l'altitude maximale

            Alt := GetMax(imgin,Column_Index_Type(SizeX), Row_Index_Type(SizeY),I,J);
            for K in 1..Row_Index_Type(SizeY) loop
               for L in 1..Column_Index_Type(SizeX) loop
                  Pixvalue := Get_Pixel_unbounded(retimg,Integer(i+L-1),Integer(j+K-1),0);
                  set_pixel_unbounded(retimg,Integer(I+L-1),Integer(J+K-1),Max(pixvalue,Alt));
               end loop;
            end loop;

         end loop;
      end loop;
      return Retimg;
   end;

   function Dilate(Imgin : in Unbounded_Image ; Size : in Integer ) return Unbounded_Image is
      RetImg : unbounded_image;
   begin
      Retimg := Dilate(Imgin,Size,1);
      Retimg := Dilate(Retimg, 1,Size);
      return Retimg;
   end;


   -- L'erosion est une dilatation en utilisant une inversion

   function Erode(Imgin : in Unbounded_image ;Size : in Integer ) return Unbounded_Image is
      Retval : Unbounded_Image;
   begin
      Retval := Inverse(Dilate(Inverse(Imgin),Size));
      return Retval;
   end;


   function TopHat(Imgin: in Unbounded_image ; Size : in Integer ) return Unbounded_Image is
     Retval : Unbounded_Image;
   begin
      Retval := Imgin-Dilate(Erode(Imgin,size),size);
      return Retval;
    end;

   function Closing(Imgin : in Unbounded_Image; Size : in Integer)
                   return Unbounded_Image
   is
      Result : Unbounded_image;
   begin
      return Erode(Dilate(Imgin,Size),Size);
   end Closing;

   function Opening(Imgin : in Unbounded_Image; Size : in Integer)
                   return Unbounded_Image
   is
      Result : Unbounded_image;
   begin
      return Dilate(Erode(Imgin,Size),Size);
   end Opening;


end Morphological;