2011-09-16 14 views
7

Estoy leyendo DIP 2nd edition de Gonzalez and Woods y trato de ensuciarme las manos con la máscara Laplacian (página 129 & 130) usando wxImage.implementar laplacian 3x3

float kernel [3][3]= {{1, 1, 1},{1,-8, 1},{1, 1, 1}}; 

aquí es los bucles de procesamiento:

unsigned char r,g,b;      

float rtotal, gtotal, btotal; rtotal = gtotal = btotal = 0.0; 
//ignore the border pixel    

for(int i = 1; i<imgWidth-1; i++) 
{ 

    for(int j = 1; j<imgHeight-1; j++) 
    { 

    rtotal = gtotal=btotal =0.0; 


     for(int y = -1; y<=1;y++) 

     { 

      for(int x = -1; x<=1;x++) 

      { 

      // get each channel pixel value 

      r = Image->GetRed(i+y,j+x); 

      g = Image->GetGreen(i+y,j+x); 

      b = Image->GetBlue(i+y,j+x); 

      // calculate each channel surrouding neighbour pixel value base 

      rtotal += r* kernel[y+1][x+1]; 

      gtotal += g* kernel[y+1][x+1] ; 

      btotal += b* kernel[y+1][x+1]; 

      } 

    } 
      //edit1: here is how to sharpen the image 
      // original pixel - (0.2 * the sum of pixel neighbour) 
      rtotal = loadedImage->GetRed(x,y) - 0.2*rtotal; 

    gtotal = loadedImage->GetGreen(x,y) - 0.2*gtotal; 

    btotal = loadedImage->GetBlue(x,y) - 0.2*btotal; 
    // range checking 

    if (rtotal >255) rtotal = 255; 

     else if (rtotal <0) rtotal = 0; 

    if(btotal>255) btotal = 255; 

     else if(btotal < 0) btotal = 0; 

    if(gtotal > 255) gtotal = 255; 

     else if (gtotal < 0) gtotal =0; 

    // commit new pixel value 

    Image->SetRGB(i,j, rtotal, gtotal, btotal); 

que aplica a la imagen que Polo Norte (imagen gris) y todo lo que consigo es una gota de píxeles blancos y negros!

¿Alguna idea de dónde puedo haber perdido algo en los bucles for?

Edit1: Finalmente obtiene la respuesta después de buscar en Google. ¡Este dsp es definitivamente complicado! Añadí al código anterior, se agudizará la imagen. ¿No se supone que

Saludos

+0

Esta sería una buena pregunta para dsp.stackexchange.com – Dima

Respuesta

5

En primer lugar, el resultado de la convolución con un Laplaciano puede tener valores negativos. Considere un píxel con un valor de 1 rodeado de 0. El resultado de la convolución en ese píxel será -8.

En segundo lugar, el rango del resultado será entre [-8 * 255, 8 * 255], que definitivamente no cabe en 8 bits. Esencialmente, cuando haces la verificación de rango, estás perdiendo la mayor parte de la información, y la mayoría de tus píxeles resultantes serán 0 o 255.

Lo que tienes que hacer es almacenar el resultado en una matriz de tipo que está firmado y lo suficientemente amplio como para manejar el rango. Luego, si desea generar una imagen de 8 bits, deberá volver a escalar los valores para que -8 * 255 corresponda a 0, y 8 * 255 corresponda a 255. O puede reescalarlo para que el valor mínimo corresponda a 0 y el mayor valor se asigna a 255.

Editar: en este caso específico, se puede hacer lo siguiente:

rtotal = (rtotal + 8 * 255)/(16 * 255) * 255; 

que simplifica a

rtotal = (rtotal + 8 * 255)/16; 

este mapa sería Rtotal en un rango entre 0 y 255 sin truncamiento. Debe hacer lo mismo para gtotal y btotal.

+0

Gracias por la respuesta. Pero lo que no entiendo es que cuando hago el cálculo vecino, lo almacena en r/g/btotal, que es un valor flotante, debería ser lo suficientemente grande, ¿verdad? Por lo que puedo ver, un valor máximo de vecino puede ser 8 * 255 o -8 * 255 como dijiste anteriormente que es (-) 2040 * 9 (nueve vecinos todos juntos) = (-) 18360. Busco el rango de flotación en C++ y dice que el rango de flotación es de 7 dígitos. Sin embargo, ahora entiendo completamente por qué obtuve un gran blog de píxeles blancos y negros porque perdí otros cálculos. Ver mi edición OP. ¡Gracias! – bili

+0

El hecho de que esté utilizando un flotador para el r/g/btotal está bien. El problema ocurre cuando truncas el valor de r/g/btotal para que esté entre 0 y 255. En lugar de configurar todo por debajo de 0 a 0 y todo por encima de 255 a 255, debes escalar el valor. Está truncando el rango, mientras que debería estar comprimiendo el rango. – Dima

+0

Sí, lo entiendo ahora. Debería escalar el valor en lugar de truncarlo. ¡tyvm! – bili

1

que dividir por el número de píxeles de la máscara después de calcular la suma ponderada, lo que produce un promedio ponderado? Sin esto, la suma de nueve valores de píxeles (incluso cuando se multiplican con valores de máscara no muy brillantes) excederá fácilmente a 255.

+2

La suma de los valores en la matriz de la máscara es cero, por lo que no, no habrá ninguna ganancia general que cause un desbordamiento.Sin embargo, debe tener cuidado de utilizar un tipo más grande en cálculos intermedios, de lo contrario podría desbordar un valor de 8 bits mientras calcula la suma. Para cada píxel, el laplaciano lo reemplaza con la suma de todos sus vecinos menos ocho veces el valor del píxel original, algo así como una operación de diferenciación. Se usa en detección de bordes. –

+0

Gracias. Lo investigaré ahora. – bili

+0

@Jason R: Haz una respuesta, creo que eso es exactamente lo que sucedió aquí. –

2

Creo que su problema es que r, g y b son del tipo unsigned int y eso, dependiendo en qué compilador está utilizando y cómo se está optimizando, está implícitamente transfiriéndolos a flotantes en las líneas rtotal += r* kernel[y+1][x+1]; etc. Pero si el compilador arroja de manera diferente a sus expectativas, calcular el valor medio no funcionará porque unsigned int no puede ser negativo .

Solución: cambie r, gyb para flotar.

No hará ninguna diferencia, pero hay un pequeño error en las líneas r = Image->GetRed(i+y,j+x); porque estoy haciendo un bucle sobre la horizontal y j está girando a la vertical.

+0

Al multiplicar un float por un char sin signo, el compilador siempre promocionará el char sin signo a un float. Pero no encajar en 8 bits al final y los valores negativos definitivamente son el problema. – Dima

+0

la razón r, g, b son char sin signo es porque las funciones GetRed/Verde/Azul devuelven char sin signo. – bili

Cuestiones relacionadas