Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Gráficos
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 16-02-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Gradiante de Sobel. Detección de contornos

Buenas foristas...
Ando nuevamente a la carga...

Estoy implementando funciones de detección de contornos mediante gradientes. Por ahora estoy aplicando el de Sobel. Tengo entendido que aplica una plantilla:
-1 0 -1
-2 0 2
-1 0 1
Para contornos horizontales. Y:
-1 -2 -1
0 0 0
1 2 1
Para los verticales.

Al funcionamiento lo tengo bien en claro... con dichas plantillas le hago un filtrado espacial y se suman los valores de ambos gradientes. Y si es mayor a un umbral... el valor que corresponde a la imagen es 1, sino 0.

Mi duda pasa por una cuestión un poco más práctica... De otra ayuda que me vino de mano del buen amigo seoane. El filtrado no se aplica en los bordes. Pero claro... cuando se aplica el algoritmo... el borde queda negro. Y esto puede que no sea parte de las formas analizadas en la imagen. ¿Me explico?

La solución sería aplicar una plantilla como la de Roberts que es de 2x2 y esta si podría usarse en los bordes. Pero esta plantilla tiene el defecto de no ser sencible a transiciones suaves.

¿Habría un método... predictivo o matemático que permita determinar si algún valor del borde forma parte del contorno de los objetos o formas que contiene una imagen? Estaba pensando en asignar un valor en blanco en los bordes... Pero a lo mejor no es una buena solución.

Gracias a todos que se hayan tomado las molestias de leer este hilo.
Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #2  
Antiguo 17-02-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Buenas...
Después de buscar alguna info por la red para ver si logro despejar mi duda... no he logrado responderme.
La cuestión sigue en pie.

Agradecería si alguien sabría indicarme como tratar correctamente a este "inconveniente"

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #3  
Antiguo 18-02-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
A ver, si me explico bien... pues... lo más que he logrado encontrar (serio, confiable,académico y por supuesto sencillo) fue en la wikipedia

En el enlace se ve claramente un ejemplo de lo que me refiero: ¿Forma o no el pixel (bajo estudio) correspondiente al borde de la imagen PARTE de algún objeto visualizado en la imagen?

Veran el mecanismo de filtrado que empleo no parte desde el borde, sino desde un pixel más interior. Ya que a lo sumo tiene 5 pixeles vecino con los cuales se estima el valor de filtrado. Si se realizan las operaciones con estos vecinos el valor que se obtiene es cercano al negro y el valor estimado no es correcto.

Como el gradiente de sobel se realiza tanto en dirección horizontal como vertical el valor obtenido de entre ellos (suma) se compara con un valor umbral para determinar si dicho pixel es o no parte del contorno. Con que uno de los valores de los gradientes sea lo suficientemente cercano al negro podría predecirse erroneamente que se trata del contorno de algun objeto.

Al evitarme el análisis desde el borde... queda éste sin filtrar... y por tanto... el efecto que se obtiene es una imagen con los contornos y un "borde" falso. Y existe el peligro de que algun punto del borde corresponda a algun contorno.

Espero haberme explicado bien. La verdad es que esto me está dejando sin cerebro... Por favor si alguien tiene conocimientos de ésto (muy posiblemente todo lo que dije suene chino para varios) y entiende mi dilema le agradecería si me puede dar una pequeña mano.

Gracias
Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #4  
Antiguo 18-02-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Bueno, puedes resolver el problema de los bordes de la misma manera que lo hace Gimp. Si es bueno para ellos, supongo que para nosotros también sera suficiente

Aquí tienes el código en C del plugin de sobel del Gimp:
http://www.koders.com/c/fid044208159...F79285EC1.aspx

Si te fijas en el código, se puede ver que en el caso de los bordes utiliza para reemplazar a la columna o fila que falta, la propia fila o columna que se esta analizando. Es decir, si estamos en la primera fila, utilizamos como fila anterior también la primera fila. Si estamos en la ultima fila, utilizamos como fila siguiente la ultima fila. Y lo mismo con las columnas.
Responder Con Cita
  #5  
Antiguo 18-02-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Bueno, puedes resolver el problema de los bordes de la misma manera que lo hace Gimp. Si es bueno para ellos, supongo que para nosotros también sera suficiente

Aquí tienes el código en c del plugin de sobel del Gimp:
http://www.koders.com/c/fid044208159...F79285EC1.aspx

Si te fijas en el código, se puede ver que en el caso de los bordes utiliza para reemplazar a la columna o fila que falta, la propia fila o columna que se esta analizando. Es decir, si estamos en la primera fila, utilizamos como fila anterior también la primera fila. Si estamos en la ultima fila, utilizamos como fila siguiente la ultima fila. Y lo mismo con las columnas.

PD: Delphius, creo que esta misma solución también se podría aplicar para el caso del suavizado.
Responder Con Cita
  #6  
Antiguo 18-02-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Gracias seoane. Le heché un buen ojo al código... pues mucho de C no entiendo (es más... creo que esta es la 3ra o 4ta vez que veo codigo C )

Cita:
Empezado por seoane
Si te fijas en el código, se puede ver que en el caso de los bordes utiliza para reemplazar a la columna o fila que falta, la propia fila o columna que se esta analizando. Es decir, si estamos en la primera fila, utilizamos como fila anterior también la primera fila. Si estamos en la ultima fila, utilizamos como fila siguiente la ultima fila. Y lo mismo con las columnas.
Algo asi estaba intentando pensar... buscarle la "vuelta" al tema de los bordes. Yo inicialmente estaba pensando en tomar los dos vecinos disponibles y no uno, pero a lo mejor sería complicarlo demasiado y tal vez el suavisado sea un valor más bajo del real.

Y de acuerdo a lo que dices tu y el código parece que el ponderar el análisis de la fila/columna borde dos veces... ofrece un valor mejor. Al menos en la teoria suena tentadora... voya ver que dice la práctica

Gracias!
Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #7  
Antiguo 18-02-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Bueno, como ayer ya me metí en el tema, ahora no me queda mas remedio que acabarlo. Si no lo termino no me quedo contento

El código seria el siguiente:
Código Delphi [-]
type
  TRGB = array[1..3] of Byte;
  PRGB = ^TRGB;
  TFila = array[1..3] of TRGB;
  PFila = ^TFila;

function Calcular(F1, F2, F3: PFila; i,j, Umbral: integer): TRGB;
var
  k: integer;
begin
  for k:= 1 to 3 do
  begin
    Result[k]:=
      Trunc(
        sqrt(
          // Horizontal
          sqr((F1[1][k]*(-1)) + (F1[i][k]*(-2)) + (F1[j][k]*(-1)) +
              (F3[1][k]*1) + (F3[i][k]*2) +(F3[j][k]*1)) +
          // Vertical
          sqr((F1[1][k]*(-1)) + (F1[j][k]*1) +
              (F2[1][k]*(-2)) + (F2[j][k]*2) +
              (F3[1][k]*(-1)) + (F3[j][k]*1) )
        )  / 5.66
      );
    // Umbralizar ¿se dice asi?, si el Umbral es cero no lo usamos
    if Umbral > 0 then
      if Result[k] > Umbral then
        Result[k]:= 255
      else
        Result[k]:= 0;
  end;
end;

procedure Sobel(Img: TPicture; Umbral: Integer);
var
  Bitmap: TBitmap;
  P1,P2,P3,P4: PByte;
  i,j: Integer;
begin
  Bitmap:= TBitmap.Create;
  try
    Bitmap.Width:= Img.Width;
    Bitmap.Height:= Img.Height;
    Bitmap.Canvas.Draw(0,0,Img.Graphic);
    if not (Img.Graphic is TBitmap) then
      Img.Assign(Bitmap);
    Img.Bitmap.PixelFormat:= pf24bit;
    Bitmap.PixelFormat:= pf24bit;
    for j:= -1 to Bitmap.Height - 2 do
    begin
      // Ajustamos el borde superior
      if j < 0 then
        P1:= Bitmap.ScanLine[0]
      else
        P1:= Bitmap.ScanLine[j];
      P2:= Bitmap.ScanLine[j+1];
      // Ajustamos el borde inferior
      if j > Bitmap.Height - 3 then
        P3:= Bitmap.ScanLine[Bitmap.Height - 1]
      else
        P3:= Bitmap.ScanLine[j+2];
      P4:= Img.Bitmap.ScanLine[j+1];
      // Primera columna
      PFila(P4)[1]:=
        Calcular(PFila(P1),PFila(P2),PFila(P3),1,2,Umbral);
      for i:= 0 to Bitmap.Width - 3 do
      begin
        PFila(P4)[2]:=
          Calcular(PFila(P1),PFila(P2),PFila(P3),2,3,Umbral);
        inc(P1,Sizeof(TRGB));
        inc(P2,Sizeof(TRGB));
        inc(P3,Sizeof(TRGB));
        inc(P4,Sizeof(TRGB));
      end;
      // Ultima columna
      PFila(P4)[2]:=
        Calcular(PFila(P1),PFila(P2),PFila(P3),2,2,Umbral);
    end;
  finally
    Bitmap.Free;
  end;
end;
Como veras aparecen los tipos ya conocidos TRGB y TFila, y sus correspondientes PRGB y PFila. El calculo de la matriz pasa a estar dentro de una función, para mayor comodidad, y se han eliminado algunos cálculos innecesarios (hay filas y columnas nulas en el filtro Sobel). El resto es muy similar a los códigos anteriores de filtros, solo que se hacen las correcciones de fila y columna que te comentaba antes.

En cuanto al Umbral, en algunos texto recomiendan pasar la imagen por un umbral después de aplicar el filtro, si no lo quieres usar (Gimp tampoco lo usa) simplemente usa el valor 0.

Bueno, pruebalo y me cuentas que tal te funciona. Ya sabes, la forma de usarlo como siempre:
Código Delphi [-]
  Sobel(Image1.Picture,0);
  Image1.Refresh;

Última edición por seoane fecha: 18-02-2007 a las 21:34:22.
Responder Con Cita
  #8  
Antiguo 19-02-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Gracias maestro!

Pues gracias seoane, por ofrecer tu honorable y bien oportuna, sin olvidar tu profresional ayuda.

Cita:
Empezado por seoane
Bueno, como ayer ya me metí en el tema, ahora no me queda mas remedio que acabarlo. Si no lo termino no me quedo contento
¿No te queda remedio? ¿O es que no quieres admitir que te gusta poner código y seguir ayudando en lo que puedas... sin olvidar que se trata de un área que dominas?

Como ya dije... ¡muchas gracias!
Yo todavía no había escrito nada de código (al menos dijitalmente). Seguía con mis pruebas a mano, papel y lapiz.

El código como es de esperar sigue siendo similar a los otros. Y te agradezco de que me hayas hecho ver un cálculo tonto:

Cita:
Empezado por seoane
(hay filas y columnas nulas en el filtro Sobel)
Se me había olvidado que Algo por cero es cero

Pero algo del código me llama la atención:
Código Delphi [-]
Trunc(
        sqrt(
          // Horizontal
          sqr((F1[1][k]*(-1)) + (F1[i][k]*(-2)) + (F1[j][k]*(-1)) +
              (F3[1][k]*1) + (F3[i][k]*2) +(F3[j][k]*1)) +
          // Vertical
          sqr((F1[1][k]*(-1)) + (F1[j][k]*1) +
              (F2[1][k]*(-2)) + (F2[j][k]*2) +
              (F3[1][k]*(-1)) + (F3[j][k]*1) )
        )  / 5.66
      );
Ese famoso sqrt()/5.66 ¿que es? ¿Es el "umbral previo" del que
comentas en?:

Cita:
Empezado por seoane
En cuanto al Umbral, en algunos texto recomiendan pasar
la imagen por un umbral después de aplicar el filtro
Yo simplemente le metería:

Código Delphi [-]
result[k] := trunc(Modulo_Gradiente);
Siendo Modulo_Gradiente la raiz cuadrada de la suma de los cuadrados de los
resultados de las plantillas. Tal como operas.
No termina de cuadrarme la idea del 5.66

Muchas gracias seoane....
Saludos,

EDITO Y AGREGO:
he visto en el e-mail (una vez que he terminado de responder este mensaje) de tu respuesta... y me di con que inicialmente tu mensaje fue:

Cita:
Empezado por seoane
En cuanto a los parámetros Umbral y divisor, tienen el siguiente significado. El
divisor es el numero por el que se divide después de multiplicar la matriz, a mi
entender este debería ser 120 (10x12), pero en el filtro de Gimp utilizan un
valor de 56 (56.6 para ser exactos), sus razones tendrán que a mi se me escapan,
pero el efecto es que la imagen resultante es mas luminosa.
Pues... eso ya me ha confundido más... ahora veo porque editaste el mensaje.

Voy a probar el código... dejo mi lapiz y papel. Tengo que hacerles varias pruebas. Y ver de donde sale ese numero mágico...
Pero claro, que tonto soy . En cualquier filtrado hay que dividir el resultado con la "suma" de los elementos de la matriz (si los elementos están expresados en forma entera) (se evitaría la división si fueran reales: Num/divisor). Pero a mi la "suma" me da cero . Tu dices que es 120.
Esto me marea... pero de algún modo voy a sacar esto...

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]

Última edición por Delphius fecha: 19-02-2007 a las 07:59:40.
Responder Con Cita
  #9  
Antiguo 19-02-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Antes de nada Delphius no hagas caso a lo que te llego por email, debí modificar como 20 veces el código. Cada vez que lo editaba, volvía a encontrar otro detalle para corregir . La versión que puedes ver ahora es la definitiva, y arroja un resultado similar al filtro Sobel de Gimp (con un Umbral=0).

Cita:
Empezado por Delphius
Ese famoso sqrt()/5.66 ¿que es? ¿Es el "umbral previo" del que comentas en?:
Jeje, el famoso 5.66. Pues si te digo la verdad no estoy muy seguro de donde sale, aunque tengo mi teoría, pero la verdad es que copie ese valor del código de Gimp

Mi teoría es la siguiente, en el peor de los casos al aplicar el filtro podemos llegar a obtener un valor de 4 * 255, este valor es demasiado alto para guardarlo en un byte. Así que dividimos todos los valores por cuatro, de hecho este el valor que debemos de usar si solo aplicamos unos de los filtros (horizontal o vertical)

Ahora bien si aplicamos ambos filtros a la vez debemos combinar ambos valores de la siguiente manera sqrt(sqr(a)+sqr(b)), siendo a y b los valores resultantes de aplicar cada filtro. En el peor de los casos tendríamos a = 4*255 y b=4*255, como ya explique en el párrafo anterior, así que si aplicamos la formula anterior la suma de los dos peores casos es sqrt(32*sqr(255)), y sorpresa la raiz cuadrada de 32 es 5,656 . Por lo que según entiendo esta división se realiza para asegurarse de que ningún valor sobrepase el limite de 255.

En cuento al Umbral, simplemente se aplica cuando se quiere tener un borde muy definido. Me explico, si solo se aplica el filtro, los bordes pueden tener mas o menos luminosidad. Si lo que nos interesa es que todos los bordes tengan la máxima luminosidad es cuando aplicamos el umbral.

Esto de los filtros es un mundo, y yo ya tengo bastante olvidadas las clases de matemáticas, así que espero no estar diciendo ninguna burrada

Última edición por seoane fecha: 19-02-2007 a las 17:54:46.
Responder Con Cita
  #10  
Antiguo 19-02-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Y ya que estamos podemos obtener bonitos resultados con este metodo. Podemos realzar los bordes de una imagen, como si estuviera perfilada con un rotulador negro, como en un comic.

Código Delphi [-]
type
  TRGB = array[1..3] of Byte;
  PRGB = ^TRGB;
  TFila = array[1..3] of TRGB;
  PFila = ^TFila;

function Calcular(F1, F2, F3: PFila; i,j, Umbral: integer): TRGB;
var
  k: integer;
begin
  for k:= 1 to 3 do
  begin
    Result[k]:=
      Trunc(
        sqrt(
          // Horizontal
          sqr((F1[1][k]*(-1)) + (F1[i][k]*(-2)) + (F1[j][k]*(-1)) +
              (F3[1][k]*1) + (F3[i][k]*2) +(F3[j][k]*1)) +
          // Vertical
          sqr((F1[1][k]*(-1)) + (F1[j][k]*1) +
              (F2[1][k]*(-2)) + (F2[j][k]*2) +
              (F3[1][k]*(-1)) + (F3[j][k]*1) )
        ) / 5.66
      );
    //  --- Esta es la parte importante --- 
    // Pintamos los bordes de negro y dejamos sin tocar el resto de la imagen
    if Umbral > 0 then
      if Result[k] > Umbral then
      begin
        FillChar(Result,Sizeof(Result),0);
        break;
      end else
        Result[k]:= F2[i][k];
  end;
end;

procedure Comic(Img: TPicture; Umbral: Integer);
var
  Bitmap: TBitmap;
  P1,P2,P3,P4: PByte;
  i,j: Integer;
begin
  Bitmap:= TBitmap.Create;
  try
    Bitmap.Width:= Img.Width;
    Bitmap.Height:= Img.Height;
    Bitmap.Canvas.Draw(0,0,Img.Graphic);
    if not (Img.Graphic is TBitmap) then
      Img.Assign(Bitmap);
    Img.Bitmap.PixelFormat:= pf24bit;
    Bitmap.PixelFormat:= pf24bit;
    for j:= -1 to Bitmap.Height - 2 do
    begin
      // Ajustamos el borde superior
      if j < 0 then
        P1:= Bitmap.ScanLine[0]
      else
        P1:= Bitmap.ScanLine[j];
      P2:= Bitmap.ScanLine[j+1];
      // Ajustamos el borde inferior
      if j > Bitmap.Height - 3 then
        P3:= Bitmap.ScanLine[Bitmap.Height - 1]
      else
        P3:= Bitmap.ScanLine[j+2];
      P4:= Img.Bitmap.ScanLine[j+1];
      // Primera columna
      PFila(P4)[1]:=
        Calcular(PFila(P1),PFila(P2),PFila(P3),1,2,Umbral);
      for i:= 0 to Bitmap.Width - 3 do
      begin
        PFila(P4)[2]:=
          Calcular(PFila(P1),PFila(P2),PFila(P3),2,3,Umbral);
        inc(P1,Sizeof(TRGB));
        inc(P2,Sizeof(TRGB));
        inc(P3,Sizeof(TRGB));
        inc(P4,Sizeof(TRGB));
      end;
      // Ultima columna
      PFila(P4)[2]:=
        Calcular(PFila(P1),PFila(P2),PFila(P3),2,2,Umbral);
    end;
  finally
    Bitmap.Free;
  end;
end;

// Por ejemplo
  Comic(Image1.Picture,16);
  Image1.Refresh;
Dependiendo de la imagen original y el valor de umbral que escojamos, podemos conseguir un efecto bastante bueno.

PD: Delphius este ultimo mensaje, es solo lúdico. Espero que no te importe
Responder Con Cita
  #11  
Antiguo 19-02-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Seoane... tu teoria suena mejor que la mia.
Medité que el filtro espacial tiene todos los elementos distintos de cero... hay nueve casillas... y en la forma que estaba expresado el filtro tanto la suma como el conteo me daban igual... pero al estar expresados en forma real se ve que el denominador corresponde a la cantidad de casillas distintas de cero y/o que corresponde a los vecinos a filtrar (1). Como la plantilla de sobel tiene 6 elementos... y considerando el factor de error que se tiene al operar con sqrt()... me dije: ¡por eso el 5.66!

Si no se me entendió... disculpen... uno alucina a las 4 AM (a esa hora se me ocurrió la teoria) ... sobre todo si tiene el estómago vacio y el no haber dormido.

(1) Esto lo comprobé (o será una simple coincidencia) mediante la observación y comparación con otras plantillas de filtros.

Cita:
Empezado por seoane
En cuento al Umbral, simplemente se aplica cuando se quiere tener un borde muy definido. Me explico, si solo se aplica el filtro, los bordes pueden tener mas o menos luminosidad. Si lo que nos interesa es que todos los bordes tengan la máxima luminosidad es cuando aplicamos el umbral.
Si he visto ese efecto. Además, el umbral se emplea (en estos propósitos) para determinar (a prueba de ensayo y error) cuales de los pixeles serán considerados para el análisis y declarados contornos.

Ahorita que me acuerdo, tengo que seguir con estos tipos de análisis: de puntos, detección de tranciones de claro-oscuro en 8 direcciones... Cada vez me está gustando más esto.

Y lástima... que haya dejado de lado (tal vez algun momento intente de nuevo) a la amplicación mediante interpolación lineal.

Cita:
Empezado por seoane
Y ya que estamos podemos obtener bonitos resultados con este metodo. Podemos realzar los bordes de una imagen, como si estuviera perfilada con un rotulador negro, como en un comic.
Lo tomo como un elemento más de aprendizaje, y aplicaciones.

Cita:
Empezado por seoane
PD: Delphius este ultimo mensaje, es solo lúdico. Espero que no te importe
No hay problema... y ¡gracias! Tal vez sea algo de juego... pero para mi sigue siendo otra manera de aprender y entender las aplicaciones y usos de estos métodos de tratamiento de imagen. Cuando termine mi tesis (si es que la termino) me voy a hacer mi propio PhotoShop.

Y esto de los tratamiento de imagen.. recien comienza para mi. Ya me ando acercando al análisis y posicionamiento de formas (mediante plantillas), por esto me resulta de importancia implementar sobel. De los contornos que detecte dependerán los resultados de mi sistema.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #12  
Antiguo 20-02-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
La verdad es que perdi la cuenta de las veces que te he agradecido seoane... pero alli va... gracias!

Probé el código que me enviaste y ahora lo voy a adaptar a mi caso.
Solamente debo decir que a mi parecer, el efecto debe ser inverso. Tu código implementa el umbral de la siguiente manera:

Código Delphi [-]
if Result[k] > Umbral then
        Result[k]:= 255
      else
        Result[k]:= 0;
Yo, en cambio lo prefiero asi:

Código Delphi [-]
if Result[k] > Umbral then
        Result[k]:= 0
      else
        Result[k]:= 255;
Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #13  
Antiguo 20-02-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Cita:
Empezado por Delphius
Solamente debo decir que a mi parecer, el efecto debe ser inverso. Tu código implementa el umbral de la siguiente manera
Eso ya es mas una cuestión estética, con el umbral tal como lo implemento, el fondo es negro y los bordes son colores claros. Supongo que lo contrario, bordes oscuros sobre fondo blanco puede resultar mas atractivo. De hecho, en el código para simular el cómic, si coloreo los bordes de negro.
Responder Con Cita
  #14  
Antiguo 02-03-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Algo no anda bien....?

Buenas, despues de una semana ya tengo implementado el algoritmo de sobel y otros más...

NOTA: el código lo he conseguido basandome en lo que amablemente seoane expuso. De hecho a pesar de contener unas variaciones en forma simple no deja de ser el mismo ¡No hay código más simple y sencillo! Le he buscado la vuelta... y la verdad es que el código de seoane es lo más directo y compacto.

NOTA2: mis variaciones están basadas en el hecho de que yo implemento el algoritmo para que funcione bajo tres condiciones:
* Obtener el gradiente horizontal,
* Obtener el gradiente vertical,
* U obtener el gradiente de ambos.

[off-topic]
seoane... encontré otro error, no es grave: en tus comentarios asociaste el del vertical al gradiente horizontal y viceversa. Me dí cuenta cuando estaba haciendo cuentas con papel y lapiz.
[/off-topic]

Y las pruebas que he realizado no me dejan muy contento. No si se deba a que la implentación del cálculo del valor a comparar con el umbral es incorrecta o es el valor del umbral el que no permite mostrar buenos resultados.

El algoritmo funciona... se vé que lo hace. Pero a mi modo de ver... por más que las imagenes tengan una buena distribución de frecuencia (desde el 0 al 255) en general al pasar un valor ya cercano al 40 o 50 como umbral el resultado ya deja ser algo entendible: alguna que otras lineas y/o puntos aislados.

Según mis cálculos la función módulo: sqrt(a^2 + b^2)/5,656 como máximo da un valor de: 1442,497/5,656 = 255 ¡Todo bien! y como mínimo: 0. Perfecto.... el rango es permitido. Lo que llama la atención es que con valores bajos da resultados.... pero al poner números elevados esto se estropea. Por ejemplo: si deseo que detecte contornos en el rango [0,210] debería poner como umbral 210 si se sigue la lógica de que:

if result[k] >= umbral
then result[k] := 0
else result[k] := 255;

He creado imagenes que contiene contorno en varios rangos... pero el algoritmo sólo funciona para números bajos. ¡No entiendo! según mis apuntes y fuentes debería poder funcionar con números elevados, de hecho el libro que tengo pone un ejemplo con un valor de umbral = 80.

Se que hay técnicas para el cálculo de un umbral óptimo. Pero sólo he conseguido bibliografía sobre el calculos en imágenes binarias.

Según mi bibliografía debería escoger un umbral de forma que del 5% al 10% de los pixeles que presentan un gradiente mayor sean declarados contornos.
Ahora ando pensando en técnicas basadas en histogramas... se que con estas podría hallar un valor... pero igualmente esto debería estar funcionando.

O yo estoy mal... o el código que armé está mal.

Si alguien tiene una idea, gracias.
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #15  
Antiguo 02-03-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
buscando... encontré: filtro paso-alto

Bueno... buscando mejor sobre Sobel, he encontrado un sitio en el que se menciona que para obtener buenos resultados previamente hay que pasar un flitrado de paso-alto para que se resalten mejor los bordes...

Voy a ver que sale de esto. Si no logro hacer que marche mejor... veré que hago.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #16  
Antiguo 04-03-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Buenas, sigo con esto del algoritmo de Sobel.. estoy empezando a calibrar ideas...

Y como dije antes... no estoy muy seguro de los resultados.
Verán, este es mi algoritmo. Bueno en realidad se muestra una parte, yo diría la más importante porque el resto puede seguirse de lo que seoane había comentado.

Código Delphi [-]
const
HORIZONTAL_GRADIENT_SOBEL: TTemplate = ((-1,0,1),(-2,0,2),(-1,0,1));
VERTICAL_GRADIENT_SOBEL: TTemplate = ((-1,-2,-1),(0,0,0),(1,2,1));

GRADIENT_DIVIDING_ONLY = 4;

type
TGradientOption = (goHorizontal,goVertical,goBoth);

function GetGradient(F1, F2, F3: PTFila; Gradient: TGradientOption; PosX, PosY,
         Threshold: integer): TRGBCanal;
{******************************************************************************
 Descripción:
 Devuelve el valor de gradiente de sobel asociado a una posición determinada de
 la imagen dependiendo si debe evaluar uno o ambos gradientes.

 Parámetros:
 - F1, F2, F3: Filas correspondientes al filtrado.
 - Gradient: Gradiente a evaluar.
   * Horizontal
   * Vertical
   * Ambos
 - PosX, PosY: Posición actual de los pixel vecinos x e y al evaluado.
 - Threshold: Umbral de decisión.
 ******************************************************************************}
var k: integer;
    GHor, GVer: byte;
begin
  // Para cada canal:
  for k := RED downto BLUE do
    begin
      // Calculamos:
      // ...El Gradiente Horizontal
      GHor := round(
                    (F1[1][k] * HORIZONTAL_GRADIENT_SOBEL[1,1] +
                     F1[PosY][k] * HORIZONTAL_GRADIENT_SOBEL[1,3] +
                     F2[1][k] * HORIZONTAL_GRADIENT_SOBEL[2,1] +
                     F2[PosY][k] * HORIZONTAL_GRADIENT_SOBEL[2,3] +
                     F3[1][k] * HORIZONTAL_GRADIENT_SOBEL[3,1] +
                     F3[PosY][k] * HORIZONTAL_GRADIENT_SOBEL[3,3])
                     /GRADIENT_DIVIDING_ONLY);
      // ...El Gradiante Vertical
      GVer := round(
                    (F1[1][k] * VERTICAL_GRADIENT_SOBEL[1,1] +
                     F1[PosX][k] * VERTICAL_GRADIENT_SOBEL[1,2] +
                     F1[PosY][k] * VERTICAL_GRADIENT_SOBEL[1,3] +
                     F3[1][k] * VERTICAL_GRADIENT_SOBEL[3,1] +
                     F3[PosX][k] * VERTICAL_GRADIENT_SOBEL[3,2] +
                     F3[PosY][k] * VERTICAL_GRADIENT_SOBEL[3,3])
                     /GRADIENT_DIVIDING_ONLY);
      // Determinamos que gradiante usamos
      case Gradient of
        goHorizontal: result[k] := GHor;
        goVertical: result[k] := GVer;
        goBoth: result[k] := GHor + GVer;
      end; // Fin case

      if Threshold > 0
         then begin
                if result[k] >= Threshold
                   then result[k] := 0
                   else result[k] := MAX_RGB;
              end;
    end;
end; {* Fin F. GetGradient *}

Hay una pequeña diferencia con lo descripto en las referencias que tengo. Mis fuentes indican que para obtener la imagen real debe obtenerse el módulo de entre ambos gradientes. Es decir la raiz cuadrada de la suma de los cuadrados de los gradientes.
De lo que pude averiguar en internet, se recomienda implementar la suma directa, tal como pueden observar, ya que simplica las operaciones y se obtiene una buena aproximación.
No me convence todavía algunos resultados... consigo unos bordes gruesos no se si realmente estoy codificando algo mal.
Le agradecería si alguien puede ver este código y/o conoce del tema y me de unas pautas para corregir mi inconveniente.

Como prueba... vean esto:




Este resultado se obtiene siguiendo dos pasos:
1. Se convierte a nivel de gris
2. Se le aplica un suavizado
3. Se calcula el contorno mediante Sobel con un valor de 80.

¿Se entiende lo que trato de explicar? Eso espero.
Gracias, pero mucha gracias a toda persona que se haya tomado el tiempo y las molestias.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Deteccion de Dispositivos USB marceloalegre Varios 9 22-09-2016 13:12:55
Detección de una unidad removible Pascalizado API de Windows 13 22-05-2011 18:54:51
Detección de navegador WEB aerosB4 Internet 5 08-03-2004 17:27:10
Detección de Carga de un programa craven Varios 3 24-11-2003 16:10:46


La franja horaria es GMT +2. Ahora son las 08:54:31.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi