Pergunta

Eu tenho tentado fazer meu próprio operador de convolução em vez de usar o embutido que vem com Java. Apliquei o operador de convolução embutido nesta imagemlink

Usando o operador de convolução embutido com filtro gaussiano, recebi essa imagem.link

Agora eu corro a mesma imagem usando meu código

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 o resultado que tive é isso.link

Além disso, como otimizo o código que escrevi. O operador de convolução incorporado leva 1 ~ 2 segundos, enquanto meu código, mesmo que não esteja atendendo ao objetivo exato, como é, está levando de 5 a 7 segundos!

Eu acidentalmente gire minha imagem de origem enquanto carrego. Então, por favor, ignore isso.

Foi útil?

Solução

Primeiro de tudo, você está desnecessariamente (e incorretamente) convertendo o resultado do float em INT em cada ciclo do loop. Sua red, green e blue deve ser do tipo flutuante e deve ser lançado de volta ao número inteiro somente após a convolução (quando convertido de volta ao 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);

O sangramento das cores em seu resultado é causado porque seus coeficientes em matrix está errado:

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

1.8452741

A soma dos coeficientes em uma matriz de convolução embaçada deve ser 1,0. Quando você aplica essa matriz a uma imagem, você pode obter cores acima de 255. Quando isso acontece, os canais "sangram" no próximo canal (azul para verde, etc.). Uma imagem completamente verde com esta matriz resultaria em:

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

Que é um verde menos intenso com uma pitada de vermelho.

Você pode consertar isso dividindo os coeficientes por 1.8452741, mas você quer ter certeza de que:

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

Caso contrário, você precisa adicionar uma verificação que limita o tamanho dos canais a 255 e não os deixe envolver. Por exemplo:

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

Em relação à eficiência/otimização:
Pode ser que a diferença de velocidade possa ser explicada por esse elenco desnecessário e chamando de matemática, mas um candidato mais provável é a maneira como você está acessando a imagem. Não estou familiarizado o suficiente com a BufferEdImage e a Raster para aconselhá -lo sobre a maneira mais eficiente de acessar o buffer de imagem subjacente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top