Sélectif ?>

Sélectif

Le principal problème des filtres gaussiens c’est qu’ils génèrent du flou. Cela est souvent très gênant sur le contour où le flou est très visible.

Pour remédier à cela, le filtre que je présente ici tient compte de la pente pour générer un filtre qui dépendra des contours. Le filtre est alors adapté à la région qu’il va filtrer.

Pour calculer les coefficients du filtre on considère la fonction :

d(i,j,k,l) = |I(i,j) - I(k,l)|

I(i,j) correspond à l’intensité du point (i,j). d(i,j,i,j) = 1/2 et il s’agit d’une exception à la formule qui calcule en fait la pente.

 

Ensuite les coefficients sont calculés comme suit :

h(m,n) = (1/d(i,j,i+m,j+n)) / (Somme sur (n,m) de (1/d(i,j,i+m,j+n)))

 

En d’autres termes, plus la pente est importante, plus la contribution d’un point sera faible. (n,m) correspond aux voisins. On divise le coefficient de filtrage par la somme de la matrice de filtrage de tel sorte que la somme de la matrice de filtrage fasse 1 et que donc l’intensité ne soit pas modifiée.

image avant utilisation du filtre adaptatif

image avant utilisation du filtre adaptatif

image après deux utilisation du filtre adaptatif

image aprés deux utilisation du filtre adaptatif

 

Voici le code C qui permet de réaliser ce filtre :

/**************************************************************/
/* Ce filtre est un filtre qui préserve les contours en       */
/* s'adaptant aux dérivées des points autour du point en      */
/* traitement. pdest et psrc doivent avoir la même taille.    */
void image_edge_protect(image *pdest, image *psrc)
{ int32 vx,vy;
 int i,j;
 float res_r, res_g, res_b;
 pix vpix,cpix;
 /* definition di filtre utilise (en forme de cloche => gaussien) */
 float filter_red  [3][3];
 float filter_green[3][3];
 float filter_blue [3][3];
 float filter_red_sum, filter_green_sum, filter_blue_sum;

 /* si les préconditions ne sont pas remplies, on quitte */
 if((pdest == NULL) || (psrc == NULL) ||
    (psrc->width != pdest->width) || (psrc->height != pdest->height))
   return;

 for(vy = 0;vy < psrc->height; vy++)
 {
   for(vx = 0;vx < psrc->width; vx++)
   {
     filter_red_sum = filter_green_sum = filter_blue_sum = 0.0;
     /* recupere le point que l'on traite */
     cpix = get_pix(psrc, vx, vy);
     /* fabrique la matrice de convolution en fonction des variations */
     /* de l'intensité (fabrique le filtre local)                     */
     for(j=0;j<3;j++)
       for(i=0;i<3;i++)
        {
         if((j == 1) && (i == 1))
         {
           filter_red  [1][1] = 0.5;
           filter_green[1][1] = 0.5;
           filter_blue [1][1] = 0.5;
         } else {
           vpix = get_pix(psrc, vx-(3>>1)+i, vy-(3>>1)+j);
                 
            res_r = ((float)COL_RED  (cpix)) - ((float)COL_RED  (vpix));
           if(res_r < 0.0) res_r = -res_r;
           if(res_r != 0)
             filter_red  [j][i] = 1.0/res_r;
           else
             filter_red  [j][i] = 1.0;
           
            res_g = ((float)COL_GREEN(cpix)) - ((float)COL_GREEN(vpix));
           if(res_g < 0.0) res_g = -res_g;
           if(res_g != 0)
             filter_green[j][i] = 1.0/res_g;
           else
             filter_green[j][i] = 1.0;
           
            res_b = ((float)COL_BLUE (cpix)) - ((float)COL_BLUE (vpix));
           if(res_b < 0.0) res_b = -res_b;
           if(res_b != 0)
             filter_blue [j][i] = 1.0/res_b;
           else
             filter_blue [j][i] = 1.0;
         }
         filter_red_sum   += filter_red  [j][i];
         filter_green_sum += filter_green[j][i];
         filter_blue_sum  += filter_blue [j][i];
        }
     for(j=0;j<3;j++)
       for(i=0;i<3;i++)
        {
         if(filter_red_sum != 0.0)
           filter_red  [j][i] /= filter_red_sum;
         if(filter_green_sum != 0.0)
           filter_green[j][i] /= filter_green_sum;
         if(filter_blue_sum != 0.0)
           filter_blue [j][i] /= filter_blue_sum;
       }
     /* on applique le filtre calculé */
     res_r = 0.0;
     res_g = 0.0;
     res_b = 0.0;
     for(j=0;j<3;j++)
       for(i=0;i<3;i++)
        {
           vpix = get_pix(psrc, vx-(3>>1)+i, vy-(3>>1)+j);
          res_r += (float)COL_RED  (vpix) * filter_red  [j][i];
          res_g += (float)COL_GREEN(vpix) * filter_green[j][i];
          res_b += (float)COL_BLUE (vpix) * filter_blue [j][i];
        }

     /* on sature le résultat */
     res_r = (res_r > 255.0)? 255.0 : ((res_r < 0.0)? 0.0:res_r);
     res_g = (res_g > 255.0)? 255.0 : ((res_g < 0.0)? 0.0:res_g);
     res_b = (res_b > 255.0)? 255.0 : ((res_b < 0.0)? 0.0:res_b);

     /* on place le résultat dans l'image destination */      
     put_pix_alpha_replace(pdest, vx, vy, COL(
       (uint8)res_r,(uint8)res_g,(uint8)res_b));
   }
 }
}
/**************************************************************/
Les commentaires sont clos.