Question

J'ai essayé de faire de mon propre opérateur de convolution au lieu d'utiliser celui intégré celui qui est livré avec Java. J'ai appliqué l'opérateur de convolution intégrée sur cette imagelien

En utilisant l'opérateur de convolution intégré avec un filtre gaussien, j'ai obtenu cette image.lien

Maintenant, j'exécute la même image en utilisant mon code

public static int convolve(BufferedImage a,int x,int y){
 int red=0,green=0,blue=0;
      float[] matrix = { 
 0.1710991401561097f, 0.2196956447338621f, 0.1710991401561097f, 
 0.2196956447338621f, 0.28209479177387814f, 0.2196956447338621f, 
 0.1710991401561097f, 0.2196956447338621f, 0.1710991401561097f, 
 };
      for(int i = x;i<x+3;i++){
          for(int j = y;j<y+3;j++){
              int color = a.getRGB(i,j);
              red += Math.round(((color >> 16) & 0xff)*matrix[(i-x)*3+j-y]);
              green += Math.round(((color >> 8) & 0xff)*matrix[(i-x)*3+j-y]);
              blue += Math.round(((color >> 0) & 0xff)*matrix[(i-x)*3+j-y]);

          }
      }

    return (a.getRGB(x, y)&0xFF000000) | (red << 16) | (green << 8) | (blue);
}

Et le résultat que j'ai obtenu est le suivant.lien

Aussi comment puis-je optimiser le code que j'ai écrit. L'opérateur de convolution intégré prend 1 ~ 2 secondes tandis que mon code même s'il ne sert pas le but exact comme il est supposé prendre 5 à 7 secondes!

J'ai accidentellement tourné mon image source pendant le téléchargement. Veuillez donc ignorer cela.

Était-ce utile?

La solution

Tout d'abord, vous convertiez inutilement (et à tort) votre résultat de Float en int à chaque cycle de la boucle. Ton red, green et blue devrait être de type flottant et ne doit être remis entier qu'après la convolution (lorsqu'il est converti en RVB):

  float red=0.0f, green = 0.0f, blue = 0.0f
  for(int i = x;i<x+3;i++){
      for(int j = y;j<y+3;j++){
          int color = a.getRGB(i,j);
          red += ((color >> 16) & 0xff)*matrix[(i-x)*3+j-y];
          green += ((color >> 8) & 0xff)*matrix[(i-x)*3+j-y];
          blue += ((color >> 0) & 0xff)*matrix[(i-x)*3+j-y];

      }
  }

return (a.getRGB(x, y)&0xFF000000) | (((int)red) << 16) | (((int)green) << 8) | ((int)blue);

Le saignement des couleurs dans votre résultat est causé parce que vos coefficients matrix sont faux:

0.1710991401561097f + 0.2196956447338621f + 0.1710991401561097f + 
0.2196956447338621f + 0.28209479177387814f + 0.2196956447338621f +
0.1710991401561097f + 0.2196956447338621f + 0.1710991401561097f =

1.8452741

La somme des coefficients dans une matrice de convolution floue doit être de 1,0. Lorsque vous appliquez cette matrice à une image, vous pouvez obtenir des couleurs supérieures à 255. Lorsque cela se produit, les canaux "saignent" dans le canal suivant (bleu au vert, etc.). Une image complètement verte avec cette matrice entraînerait:

 green = 255 * 1.8452741 ~= 471 = 0x01D7;
 rgb = 0xFF01D700;

Qui est un vert moins intense avec un soupçon de rouge.

Vous pouvez résoudre ce problème en divisant les coefficients par 1.8452741, mais vous voulez vous assurer que:

 (int)(255.0f * (sum of coefficients)) = 255

Sinon, vous devez ajouter un chèque qui limite la taille des canaux à 255 et ne les laissez pas enrouler. Par exemple:

if (red > 255.0f)
   red = 255.0f;

Concernant l'efficacité / optimisation:
Il se peut que la différence de vitesse puisse s'expliquer par ce casting et l'appel de mathématiques inutiles, mais un candidat plus probable est la façon dont vous accédez à l'image. Je ne suis pas assez familier avec BufferedImage et Raster pour vous conseiller sur la façon la plus efficace d'accéder au tampon d'image sous-jacent.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top