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 05-01-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
Ampliar imagen o parte de ella - Interpolacion Lineal

Buenas foristas,

Lo que pretendo es muy simple. Aplicar una función que permita ampliar una zona determinada de la imagen (o incluso, entera). Se que hay dos métodos:

1. Por repetitción: que consiste en repetir cada pixel K veces en k-1 columnas y filas siguientes. Es sencillo, pero para niveles de K grandes, se produce un efecto cuadriculado.
2. Por interpolación lineal. El proceso se detalla para una K = 2. Primeramente se arma la imagen de tamaño (kM x kN). Segundo, cada pixel de la zona se ingresa en la imagen ampliada dejando un pixel en el medio (valor cero). Por ejemplo:

x 0 x 0
0 0 x 0
x 0 x 0

Donde x es el valor del pixel (ojo... a nivel de gris).

Posteriormente se hace un especie de "filtrado" convolucionando la zona a ampliar con una plantilla (o matriz). Para una k = 2 (es decir ampliar en 200%) se tiene la matrix: ((1/4,1/2,1/4),(1/2,1,1/2),(1/4,1/2,1/4). Una vez realizado esto, se repite la ultima fila y columna.

Según la bibliografía que consulto:
Cita:
Para una k genérica hay que amplicar la plantilla k veces
Y valla que se hace un lío. Pues, si K = 3, entonces... la matriz ¿como sería?... Y Si me guío por este comentario, si realizo el procedimiento una vez (como si fuera K=2) y al resultado le vuelvo aplicar el "filtrado" la imagen conseguida no sería de (kM x KN) sino que sería de (K+1M x k+1N)

Mi pregunta por tanto es... ¿Alguien conoce como realizar el algoritmo para una k cualquiera?

Seoane, lo mas seguro es que si te das una vuelta por aqui... te pongas a escribir codigo Y es muy probable de que te sepas esto

Desde ya, muchas gracias a todos por robarles su tiempo para leer este post.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #2  
Antiguo 11-01-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
He logrado avanzar un poco...

Buenas, de lo que pude averiguar buscando en la gran red de redes, he podido encontrar la forma genérica de calcular el valor correspondiente a cada pixel de acuerdo a la dimensión.
Entiendo el algoritmo, y es como detallo a continuación:

1) Armar una imagen temporal de tamaño (kM x kN), siendo k el factor de ampliación.
2) Por cada pixel de la imagen original se debe colocar intercalando (k-1) ceros entre ellos hasta alcanzar el tamaño (kM x kN):

Por ejemplo:
5-11
8-25

se transforma a (con k = 3)
5-0-0-11-0-0
0-0-0- 0-0-0
0-0-0- 0-0-0
8-0-0-25-0-0
0-0-0- 0-0-0
0-0-0- 0-0-0

Hasta allí barbaro, logro hacer dicho procedimiento...
La cosa se complica al calcular los valores intermedios entre ellos, es decir los ceros. Si A y B son dos puntos originales de la imagen, cualquier k-1 puntos entre ellos (no diagonal) se determina:

x = (i*A + j*B)/k ,i = k-1,..,1 j = 1..k-1 ,k >= 3
x = (A + B)/2 ,k >= 2

Mientras i va decrementado, j aumenta lo cual permite asignar valores intermedios entre A y B de modo tal que se produzca una transición suave entre ellos.

Para rellenar estos valores, primero se calculan en las filas:
5-7-9-11-0-0
0-0-0-0-0-0
0-0-0-0-0-0
8-14-19-25-0-0
0-0-0-0-0-0
0-0-0-0-0-0

Luego se aplica sobre las columnas:
5-7-9-11-0-0
6-9-12-16-0-0
7-12-16-20-0-0
8-14-19-25-0-0
0-0-0-0-0-0
0-0-0-0-0-0

Los ceros restantes, toman el valor de la ultima columna, y fila:
5-7-9-11-11-11
6-9-12-16-16-16
7-12-16-20-20-20
8-14-19-25-25-25
8-14-19-25-25-25
8-14-19-25-25-25

Y alli termina el algoritmo.

¿Sencillo no? Pues, en palabras... pues me he quedado encerrado tratando de ver como lo puedo llevar a cabo. Mi algoritmo solo me ha llegado hasta intercalar los ceros. Lo siguiente no tengo idea de como hacerlo. Adjunto lo que logrado hacer.
Si alguien puede darme un consejo de como proseguir se lo agradecería.

Yo hasta el momento estaba empleando scanline(), para moverme entre los pixeles. Es rápido... pero estaba pensando que con pixels[] sería más sencillo... pero muy lento. No se.. escucho alternativas.

saludos,
Archivos Adjuntos
Tipo de Archivo: zip uzoom.zip (1,3 KB, 72 visitas)
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #3  
Antiguo 11-01-2007
Avatar de Ñuño Martínez
Ñuño Martínez Ñuño Martínez is offline
Moderador
 
Registrado: jul 2006
Ubicación: Ciudad Catedral, Españistán
Posts: 6.000
Poder: 25
Ñuño Martínez Tiene un aura espectacularÑuño Martínez Tiene un aura espectacular
Una forma podría ser utilizar matrices. De hecho, es lo que usan los programas como potochop, The Gimp y similares. Intentaré explicarlo, a ver qué tal me sale.

Primero amplias la imagen por el método uno.
Cita:
Empezado por Delphius
1. Por repetitción: que consiste en repetir cada pixel K veces en k-1 columnas y filas siguientes. Es sencillo, pero para niveles de K grandes, se produce un efecto cuadriculado.
Después creas la matriz de pesos. Esta matriz tendrá un tamaño doble al índice de ampliación más uno ((k * 2) + 1) Por ejemplo, si amplías por 3 y quieres todos los puntos pesen igual, deberás crear una matriz de 7x7 con todos los elementos iguales a 1:

Código Delphi [-]
VAR
  MatrizPesos: ARRAY [1..(k*2)+1, 1..(k*2)+1] OF INTEGER;
  x, y: INTEGER;

...

  FOR y := 1 TO ImagenAmpliada.alto DO
    FOR x := 1 TO ImagenAmpliada.ancho DO
      MatrizPesos[mx, my] := 1;
Después recorres la imagen ampliada (cuyo tamaño es, por ejemplo <w, h>) y, sumas los pesos de los puntos que rodean el pixel según indica la matriz. El pixel resultante es dicha suma dividido por el total de los pesos:
Código Delphi [-]
VAR
  x, y: INTEGER;
  mx, my: INTEGER;
  PesoTotal: INTEGER;
  ValorPixel: INTEGER;

...

  FOR y := 1 TO ImagenAmpliada.alto DO
    FOR x := 1 TO ImagenAmpliada.ancho DO
    BEGIN
      PesoTotal := 0; { <-- Antes olvidé poner esto }
      ValorPixel := 0;
      FOR my := 1 TO (k*2)+1 DO 
        FOR mx := 1 TO (k*2)+1 DO
        BEGIN
        { Sólo procesar si el pixel está dentro de la imagen }
          IF (0 < x + (mx - k) AND (x + (mx - k) < ImagenAmpliada.ancho) AND
             (0 < x + (my - k)) AND (x + (my - k) < ImagenAmpliada.alto) THEN
          BEGIN
            PesoTotal := PesoTotal + MatrizPesos[mx, my]
            ValorPixel := ValorPixel + 
                          (ImagenAmpliada.GetPixel (x + (mx - k), y + (my - k)) *
                           MatrizPesos[mx, my]);
          END;
        END;
        ImagenFinal.PutPixel (x, y, ValorPixel DIV PesoTotal);
    END;

No he comprobado el código y lo he hecho de memoria, así que revísalo, en especial la parte de cálculo de coordenadas. De todas formas creo que se entiende lo que quiero hacer, ¿no? En resumidas cuentas se busca la media ponderada del color de los píxeles que rodean a uno dado.

En cuanto a la velocidad, eso se lo dejo a otro, que mi neurona no da ya para más.
__________________
Proyectos actuales --> Allegro 5 Pascal ¡y Delphi!|MinGRo Game Engine

Última edición por Ñuño Martínez fecha: 11-01-2007 a las 13:05:43. Razón: El editor me jugó una mala pasada.
Responder Con Cita
  #4  
Antiguo 11-01-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
Hola Ñuño, estoy leyendo tu método, y si no leí mal se trata de agrandar y luego suavizar la imagen. Este método de aplicar una matriz para suavizar la imagen ya lo discutimos aquí, usando Scanline y todo .Pero me queda la duda si quedara bien, si primero añades un montón de ceros y luego aplicas la matriz, lo unico que conseguirás es oscurecer la imagen
Responder Con Cita
  #5  
Antiguo 11-01-2007
Avatar de Ñuño Martínez
Ñuño Martínez Ñuño Martínez is offline
Moderador
 
Registrado: jul 2006
Ubicación: Ciudad Catedral, Españistán
Posts: 6.000
Poder: 25
Ñuño Martínez Tiene un aura espectacularÑuño Martínez Tiene un aura espectacular
Cita:
Empezado por seoane
Hola Ñuño, estoy leyendo tu método, y si no leí mal se trata de agrandar y luego suavizar la imagen. Este método de aplicar una matriz para suavizar la imagen ya lo discutimos aquí, usando Scanline y todo .Pero me queda la duda si quedara bien, si primero añades un montón de ceros y luego aplicas la matriz, lo unico que conseguirás es oscurecer la imagen
Ya, por eso primero hay que ampliarla sin filtro. Después de la ampliación se aplica el filtro de suavizado. Creo que ya lo dije, ¿no?
Cita:
Empezado por Ñuño Martínez
Primero amplias la imagen por el método uno.
Cita:
Empezado por Delphius
1. Por repetitción: que consiste en repetir cada pixel K veces en k-1 columnas y filas siguientes. Es sencillo, pero para niveles de K grandes, se produce un efecto cuadriculado.
Por ejemplo:
5-11
8-25

se transforma a (con k = 3)
5-5-5-11-11-11
5-5-5-11-11-11
5-5-5-11-11-11
8-8-8-25-25-25
8-8-8-25-25-25
8-8-8-25-25-25


Por otro lado, obtengo el valor del pixel de ImagenAmpliada pero el resultado lo guardo en ImagenFinal. Esto es importante para evitar pisar los datos.

De todas formas, si llego a a saber que ya se habló de aplicar filtros a una imagen mediante matrices, me ahorro todo ese código y la mayor parte de las explicaciones .

[edit] error en el código que puse: Olvidé poner un "PesoTotal := 0" antes del bucle interno. Ahora ya está bien.
__________________
Proyectos actuales --> Allegro 5 Pascal ¡y Delphi!|MinGRo Game Engine

Última edición por Ñuño Martínez fecha: 11-01-2007 a las 12:58:28.
Responder Con Cita
  #6  
Antiguo 11-01-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 Yo mismo
y si no leí mal ...
Pues parece que si lo hice, yo entendía que agrandabas añadiendo ceros y luego suavizabas, cuando claramente (ahora que releo tu mensaje) veo que agrandas la imagen repitiendo los pixeles y luego suavizando. Este método ya me parece mucho mejor

Una opción seria agrandar la imagen como siempre, usando la API de windows, que su métodos tendrá, y luego aplicar el suavizado. Aunque no se si el objetivo de Delphius es puramente teórico, es decir, quiere saber como agrandar, o practico, es decir, necesita agrandar una imagen dentro de su programa. Si es el primer caso no le quedara mas remedio que romperse la cabeza hasta encontrar el super algoritmo , si es lo segundo usar la API puede servir, o GDI+, o cualquier otra librería gráfica.

Cita:
Empezado por Delphius
Seoane, lo mas seguro es que si te das una vuelta por aqui... te pongas a escribir codigo
Ahora mismo no tengo mucho tiempo, si no ya me hubiera puesto a teclear. Ya sabes que es un tema que me gusta.
Responder Con Cita
  #7  
Antiguo 11-01-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 por ayudar

Cita:
Empezado por seoane
Una opción seria agrandar la imagen como siempre, usando la API de windows, que su métodos tendrá, y luego aplicar el suavizado. Aunque no se si el objetivo de Delphius es puramente teórico, es decir, quiere saber como agrandar, o practico, es decir, necesita agrandar una imagen dentro de su programa. Si es el primer caso no le quedara mas remedio que romperse la cabeza hasta encontrar el super algoritmo , si es lo segundo usar la API puede servir, o GDI+, o cualquier otra librería gráfica.
Mi objetivo es tanto teorico como práctico. Y en teoría entiendo... cuando la quise llevar a la práctica... ¡hay mama!... se me complicó la cosa.
Lamentablemente si necesito agrandar una imagen y tiene que ser código mio. Podría usar la API, la verdad es que no me fijé si había alguna... yo me estoy basando en un libro y de alli estoy sacando los elementos que voy necesitando, pues ya he presentado mis fuentes bibliográficas ante mis tutores (no puedo cambiarlas ahora). Por lo que no puedo hacer uso de librerias gráficas, el objetivo es que yo las implemente. Asi lo impuse yo para mi trabajo.

Ahora me doy cuenta de que esto no era la papa (fàcil)...

Y si... como dices: me tendré que romper el coco tratando de sacarle el algoritmo.

Nuño: gracias por tu aporte. Ese algoritmo es relativamente sencillo. Es repetir... a ese lo tengo. Es por el otro método (interpolación lineal) el que me estoy dando golpes en la cabeza con el martillo que tengo al lado Como habrás notado el método por repetición es casi elemental pero sufre de una gran problema, cuanto más elevado sea el factor k, la imagen queda totalmente dibujada en bloques. El segundo método trata de evitar este efecto, pero claro... a niveles altos también falla: la imagen queda borrosa.

Cita:
Empezado por seaone
Ahora mismo no tengo mucho tiempo, si no ya me hubiera puesto a teclear. Ya sabes que es un tema que me gusta.
A mi también me gusta. Y a pesar de que me cueste, de una u otra forma lo voy a sacar. Tuve que buscar en internet un largo rato para lograr darme cuenta de la dichosa fórmula. Si bien no la encontré explícitamente (pues yo la encontré a mano y papel)* en ningún sitio... en todos me fueron dejando "pistas". Lástima, ninguno me advirtió de lo que seguía.

Gracias seoane, no es mi intención de que me hagas la tarea... en otro hilo tu ayuda vino bárbara. Yo prefiero una directrices, tips... Pero debo admitir de que si tu no hubieras puesto ese código, tal vez yo no hubiera avanzado mucho.

* como dicen en Argentina: ¡me volví mono!

Seguiré dandome golpes... a ver si no quedo loco antes.
Gracias a ambos
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #8  
Antiguo 26-01-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
No puedo, no me sale... no se como...

Buenas de nuevo. Disculpen por abrir de nuevo este hilo, pero la verdad es que este algoritmo me ha dejado sin cerebro... por más que lo piense... y lo piense... no logro encontrarle manera de codificarlo. Lo entiendo al algoritmo, pero en la práctica mi cerebro queda frito.

Lo he pensado incluso en papel para guiarme, en forma manual lo saco... Pero al momento de "traducirlo" empleando tanto Pixels[] como Scanline() no puedo, sinceramente, se me borra todo de mi mente...

Este algoritmo me ha dejado mal parado... he podido continuar con otras partes de mi proyecto, pero lamentablemente he llegado a un punto en donde no puedo avanzar si no logro implementar al (disculpen mis palabras) maldito algoritmo de zoom por interpolación lineal.

Si alguno puede darme alguna orientación le estaría muy agradecido.

Muchas gracias,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #9  
Antiguo 26-01-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, una primera aproximacion seria la siguiente:

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

procedure Ampliar(Imagen: TPicture; Z: Integer);
var
  Bitmap: TBitmap;
  P1, P2, P3, P4: ^TRGB;
  i, j, k: Integer;
  x: Integer;
begin
  if Z < 1 then
    Exit;
  Bitmap:= TBitmap.Create;
  try
    Bitmap.Width:= Imagen.Width;
    Bitmap.Height:= Imagen.Height;
    Bitmap.Canvas.Draw(0,0,Imagen.Graphic);
    Bitmap.PixelFormat:= pf24bit;
    Imagen.Assign(Bitmap);
    Imagen.Bitmap.Width:= Bitmap.Width * Z;
    Imagen.Bitmap.Height:= Bitmap.Height * Z;
    for j:= 0 to Imagen.Bitmap.Height - 1 do
    begin
      // Actuales
      P1:= Bitmap.ScanLine[j div Z];
      P2:= Imagen.Bitmap.ScanLine[j];
      // Anteriores
      if j >= Z then
        P3:= Bitmap.ScanLine[(j div Z)-1]
      else
        P3:= P1;
      P4:= P1;
      for i:= 0 to Bitmap.Width - 1 do
      begin
        for x:= 1 to Z  do
        begin
          for k:= 1 to 3 do
          begin
            P2^[k]:= P4^[k] + (((P1^[k] - P4^[k]) * x) div Z);
            P2^[k]:= P2^[k] + (((P3^[k] - P2^[k]) * (z-(j mod Z))) div Z);
          end;
          inc(P2);
        end;
        P4:= P1;
        inc(P1);
        inc(P3);
      end;
    end;
  finally
    Bitmap.Free;
  end;
end;

// Por ejemplo, Zoom x3 
  Ampliar(Image1.Picture,3);
  Image1.Refresh;

Puede que tenga fallos, es solo una primera aproximación, además tiene que haber una solución mejor donde el Zoon no tenga que ser un numero entero. Todo se andará ...

Última edición por seoane fecha: 26-01-2007 a las 17:54:22.
Responder Con Cita
  #10  
Antiguo 26-01-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
Muchísimas gracias por tu infinita ayuda

seoane, muchísimas gracias por brindar nuevamente tus conocimientos en la materia. A simple vista no lo entiendo mucho... pero como tu dices:

Cita:
Empezado por seoane
(...)una primera aproximacion(...)
Voy a analizar y estudiar con lujo, detalles, y objetivamente tu algoritmo.
Primeramente deberé refrescar mi cerebro. Nunca me ha pasado algo así: generalmente logro "sacar" algoritmos en cuestión de no más de 3 días... pero quedarme en blanco... es de no creer! Se nota que lo he forzado mucho.

Bueno, unas horas de siesta y retorno el trabajo.
Nuevamente muchas gracias, como he dicho antes: hay lugar en mi lista de agradecimientos y cumplidos para todos aquellos que han aportado altruistamente sus conocimientos y ayuda.

¡Muchas gracias!
Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #11  
Antiguo 27-01-2007
Avatar de Zeta
Zeta Zeta is offline
Miembro
 
Registrado: feb 2005
Posts: 215
Poder: 20
Zeta Va por buen camino
¿QUerés hacer algo como esto? O quizás te orienta ya que tiene el source
http://img255.imageshack.us/img255/5277/dibujowf4.jpg

Hay un componente que te lo permite:

TMagnify 2.0 ( FULL SOURCE free )

Saludos
__________________
And I'd like an hour on the holodeck with Seven of Nine.
Responder Con Cita
  #12  
Antiguo 27-01-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
Zeta, de lo que se trata es de implementar un algoritmo de interpolación. El componente que tu indicas se limita a usar las funciones de dibujo de la API para agrandar el dibujo, y te puedo asegurar que la api, en este caso, no utiliza ningún tipo de interpolación . Además como ya explico Delphius necesita implementar su propio algoritmo, no le sirve con utilizar funciones de la API o librerías de terceros.
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
¿Crear email con imagen como parte del contenido del texto? burasu Varios 6 07-04-2006 19:11:30
Crear directorio con lista lineal davitcito Varios 4 07-05-2005 07:20:01
Programa que agrande una parte de la imagen maravert Gráficos 0 05-08-2004 01:12:50
Ampliar un campo en un dbgrid hogol Varios 1 21-11-2003 16:02:40


La franja horaria es GMT +2. Ahora son las 14:52:01.


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