Domanda

Ho cercato di creare il mio operatore di convoluzione invece di usare quello integrato fornito con Java. Ho applicato l'operatore di convoluzione integrato su questa immaginecollegamento

Usando l'operatore di convoluzione integrato con filtro gaussiano ho ottenuto questa immagine.collegamento

Ora eseguo la stessa immagine usando il mio codice

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);
}

E il risultato che ho ottenuto è questo.collegamento

Inoltre come ottimizzare il codice che ho scritto. L'operatore di convoluzione integrato richiede 1 ~ 2 secondi mentre il mio codice anche se non serve allo scopo esatto come si suppone, sta impiegando 5 ~ 7 secondi!

Ho ruotato accidentalmente la mia immagine di origine durante il caricamento. Quindi per favore ignoralo.

È stato utile?

Soluzione

Prima di tutto, sei inutilmente (e erroneamente) convertendo il tuo risultato da galleggiante a int ad ogni ciclo del ciclo. Tuo red, green e blue dovrebbe essere di tipo galleggiante e dovrebbe essere restituito al numero intero solo dopo la convoluzione (quando viene convertito in RGB):

  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);

Il sanguinamento dei colori nel tuo risultato è causato perché i tuoi coefficienti in matrix sono sbagliati:

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

1.8452741

La somma dei coefficienti in una matrice di convoluzione offuscata dovrebbe essere 1.0. Quando si applica questa matrice a un'immagine, è possibile ottenere colori che sono più di 255. Quando ciò accade i canali "sanguinano" nel canale successivo (blu a verde, ecc.). Un'immagine completamente verde con questa matrice comporterebbe:

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

Il che è un verde meno intenso con un pizzico di rosso.

Puoi risolverlo dividendo i coefficienti 1.8452741, ma vuoi assicurarti che:

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

In caso contrario, è necessario aggiungere un controllo che limita le dimensioni dei canali a 255 e non lasciarli in giro. Per esempio:

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

Per quanto riguarda l'efficienza/ottimizzazione:
Potrebbe essere che la differenza di velocità possa essere spiegata da questo inutile casting e chiamando Math.round, ma un candidato più probabile è il modo in cui si accede all'immagine. Non ho abbastanza familiarità con BufferedImage e Raster per consigliarti sul modo più efficiente per accedere al buffer di immagini sottostante.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top