Procesamento de imagens digitais

6 respostas
A

Olá pessoal do fórum, estou tentando e não estou conseguindo, talvez alguém possa me ajudar. Minha imagem está cheinha de ruídos de modo que não sá nem para entender. Transformo uma imagem em BufferedImage e depois numa matriz bidimensional (chamada de pixelatual[w][h]).
Utilizando essa matriz, aplico o filtro de Sobel (abaixo é o 3º) que me retorna um BufferedImage. O método de sobel chama o método que transforma a matriz[][] em BufferedImage (é o 4º). Quando exibo a img na tela (é o 1º), ela fica cheia de ruídos. Já olhei o código de pé à cabeça, mas não entendi onde está o problema. Segue abaixo os métodos (comentados) que utilizo. Alguém pode me ajudar por que esses ruídos aparecem?

1º)
//este método coloca a imagem no painel (ImagePanel)

public void porImagemNaTela(BufferedImage bufi) {
        try {
            AtualizarTela();//limpa o painel
            Graphics g = bufi.getGraphics();
            ImagePanel p = new ImagePanel();
            p.setBufferedImage(bufi);
            p.paintComponent(g);
            PainelCentral.add(p, new BorderLayout().CENTER);
            limiar_jSlider1.setVisible(true);
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, " Houve exceção do tipo " + e.getMessage() + " no método porImagemNaTela.");
        }
    }

2º)
//aqui eu chamo o método que aplica o filtro de Sobel que retorna um BufferedImage e depois chamo o método que exibe na tela

private void ItemFiltroSobelActionPerformed(java.awt.event.ActionEvent evt) {                                                
  // TODO add your handling code here:


   BufferedImage bufi = new pdi.Filtro.FiltroSobel().FiltroSobel(pixelAtual);


   //após fazer a alteração, eu exibo na no JPanel

   porImagemNaTela(bufi);//este método expliquei acima
   setVisible(true);

}

3º)
// método que utilizo para aplicar o filtro de Sobel (recebe uma imagem bidimensional e retorna um BufferedImage) e chamar o método que transforma a matriz[][] em BufferedImage

public java.awt.image.BufferedImage FiltroSobel(int[][] pixelAtual){
        pdi.Pixel p = new pdi.Pixel();
        int Gx, Gy;
        
        //pego o bufferedImage a fim de conseguir a largura a altura da imagem
 
        //obtendo largura e altura da imagem
        int w = pixelAtual.length, h = pixelAtual[0].length;
        
        for(int j=0; j<h-1; j++){ 
            for(int i=0; i<w-1;i++){
                if(i!=0){
                    if(j!=0){
                        Gx = (((-1)*pixelAtual[i-1][j-1]+ (-2)*pixelAtual[i-1][j] + (-1)*pixelAtual[i-1][j+1])/4 -
                               (pixelAtual[i+1][j-1] + 2*pixelAtual[i +1][j] + 1*pixelAtual[i+1][j+1])/4)/2;
                        
                        Gy = (((-1)*pixelAtual[i-1][j-1] + (-2)*pixelAtual[i][ j -1] + (-1)*pixelAtual[i+1][j-1])/4-
                                (pixelAtual[i-1][j+1]  + 2*pixelAtual[i][ j+1 ] + pixelAtual[i+1][j+1])/4)/2;

                           pixelAtual[i][j] =   pixelAtual[i][j] = (int) Math.sqrt(Gx*Gx + Gy*Gy);//Gx*Gx + Gy*Gy;

                    }
                }
            }
        }
        
        
        return p.setPixelEscalaDeCinza(pixelAtual);
      }

4º)

// transforma matriz bidimensional em BufferesImage

public BufferedImage setPixelEscalaDeCinza(int[][] mtzImg) {
        int largura = mtzImg.length;
          int altura = mtzImg[0].length;

         BufferedImage image = new BufferedImage(largura, altura,  BufferedImage.TYPE_BYTE_GRAY);

          WritableRaster raster = image.getRaster();
          for (int h = 0; h < largura; h++) {
              for (int w = 0; w < altura; w++) {
                  raster.setSample(h, w, 0, mtzImg[h][w]);
              }
          }

         return image;
    }

Aguardando resposta…

6 Respostas

T

Você está trabalhando com int, será que não precisaria trabalhar com float? Você conferiu suas contas?

A

Acabei de dar uma olhada nos resultado da seguinte atribuição:

pixelAtual[i][j] =  (int) Math.sqrt(Gx*Gx + Gy*Gy);//Gx*Gx + Gy*Gy;

                            // retorna a raiz quadrada:
                            JOptionPane.showMessageDialog(null, "   valor da raiz quadrada: " + Math.sqrt(Gx*Gx + Gy*Gy));

                           // retorna um inteiro da raiz quadrada
                            JOptionPane.showMessageDialog(null, "   int do valor da raiz quadrada: " + (int) Math.sqrt(Gx*Gx + Gy*Gy));

Os resultados foram os seguites:
- com Math.sqrt(GxGx + GyGy) eu tenho números reais e NaN;
- com (int) Math.sqrt(GxGx + GyGy) eu tenho os inteiros dos reais acima, mas tenho 0 (zero) para NaN.
Ou seja, a imagem ficou meio que binária porque existem muitos NaN (que transformados em inteiros) ficam muitos zeros (ruídos).

Como posso solucionar isso?
Lembrando que minha matriz é de inteiros porque eu tenho valores de 0 a 255 para transformar em BufferedImage.

T

Vou explicar quais são os problemas de você fazer suas contas com inteiros.

Você queria calcular sqrt (GxGx + GyGy).

Suponha que GxGx + GyGy seja maior que o valor que cabe em um int (2^31). Se isso ocorrer, então o valor resultante será NEGATIVO, e então a raiz quadrada irá retornar um NaN (Not-A-Number), já que não se pode tirar raízes quadradas de números negativos.

Quando você faz um cast de NaN para int, o valor é zero, e é por isso que apareceu um monte de zeros.

OK?

T

Portanto, para evitar problemas com contas, Gx e Gy devem ser float logo de cara, para evitar esses problemas de overflow silencioso que o Java tem. (O C# opta por não ter esse “overflow silencioso”, o que torna a computação mais lenta mas mais previsível.)

A

ok, entendi!
Deixou de haver overflow, porém está dando valores exorbitantes, veja:
Declarei:

float Gx, Gy;

Pixel atual não está recebendo valores entre 0 e 255. O seguinte código

pixelAtual[i][j] =  (int) Math.sqrt(Gx*Gx + Gy*Gy);

me retorna 24887285, 25120433, etc.

Acredito que o bug está em

Gx = (((-1)*pixelAtual[i-1][j-1]+ (-2)*pixelAtual[i-1][j] + (-1)*pixelAtual[i-1][j+1])/4 -
                               (pixelAtual[i+1][j-1] + 2*pixelAtual[i +1][j] + 1*pixelAtual[i+1][j+1])/4)/2;
                        
                        Gy = (((-1)*pixelAtual[i-1][j-1] + (-2)*pixelAtual[i][ j -1] + (-1)*pixelAtual[i+1][j-1])/4-
                                (pixelAtual[i-1][j+1]  + 2*pixelAtual[i][ j+1 ] + pixelAtual[i+1][j+1])/4)/2;

                        pixelAtual[i][j] =  (int) Math.sqrt(Gx*Gx + Gy*Gy);
Logo, darei uma olhada melhor no método de Sobel. Se você  que o erro está em outra parte da implementação, por obséquio,  uma dica.
A
Consegui!

Além daquele overflow do Java, também tinha um problema no preenchimento da matriz pixelAtual. Veja:

//tirei isto:
   pixelAtual = p.getPixel(arquivoJFileChooser.getSelectedFile().toString());


  //e pus isto:
  pixelAtual = new Pixel().getPixelEscCinza(arquivoJFileChooser.getSelectedFile().getAbsolutePath());

Vlw!

Criado 18 de maio de 2009
Ultima resposta 19 de mai. de 2009
Respostas 6
Participantes 2