Esta función realiza el desenfoque de una imagen. Lo que hace es sumar todos los colores que hay alrededor de cada pixel y hacer la media, dandole más importancia al color central (8 veces más importancia), según el siguiente esquema:
pixel1 pixel2 pixel3 1 1 1
pixel4 pixel5 pixel6 * 1 8 1
pixel7 pixel8 pixel9 1 1 1
pixel5 = (pixel1*1 + pixel2*1 + pixel3*1 + pixel4*1 + pixel5*8 + pixel6*1 + pixel7*1 + pixel8*1 + pixel9*1) / 16
La función necesita de 5 variables para su funcionamiento (yo las tengo como variables miembro de la superficie). Las variables son:
m_lpBuffer = Es el puntero al inicio de la superficie. En el caso de una superficie DX se puede conseguir con la función Lock
m_lPitch = Es el número de bytes de cada línea de la superficie. En el caso de una superficie DX se puede conseguir con la función Lock
m_bpp = Son los bits bor pixel de la superficie
m_bypp = Son los bytes por pixel de la superficie. Aunque este valor tambien se puede deducir de la variable anterior
m_Rect = Está almacenado el rectángulo de la superficie (tamaño)
Mediante la configuración de estas variables se controla el tamaño y el formato de la imagen, por lo que se puede aplicar la función a una superficie de render, una textura, etc
Cuantas más veces seguidas se llama a la función, más efecto de desenfoque se produce
Hay que tener en cuenta que aunque está hecha con funciones MMX, no deja de ser muy lenta, así que solo se puede usar para cosas muy puntuales o simplemente como curiosidad
void Superficie::Desenfoque()
{
int maxlinea,pixelsx,pixelsy,bypp,bpp,incxlinea,maxlinea2,contpixel;
unsigned char *dirw;
dirw=m_lpBuffer;
maxlinea=m_lPitch;
bypp=m_bypp;
bpp=m_bpp;
pixelsx=m_Rect.Width()-2;
pixelsy=m_Rect.Height()-2;
_asm{
mov eax,maxlinea
mov esi,eax
shl eax,1
mov maxlinea2,eax
mov eax,pixelsx
imul bypp
mov edx,esi
sub edx,eax
mov incxlinea,edx
sub esi,bypp
mov edi,dirw
add edi,maxlinea
add edi,bypp
psrld mm7,32
linea:
mov eax,pixelsx
mov contpixel,eax
cmp bpp,32
jz linea32
cmp bpp,24
jz linea24
cmp bpp,16
jz linea16
linea15:
sub esi,maxlinea2
mov ax,word ptr [edi+esi]
mov bx,word ptr [edi+esi+2]
shrd edx,eax,5
shrd ecx,ebx,5
shr eax,5
shr ebx,5
shr edx,3
shr ecx,3
shrd edx,eax,5
shrd ecx,ebx,5
shr eax,5
shr ebx,5
shr edx,3
shr ecx,3
shrd edx,eax,13
shrd ecx,ebx,13
movd mm0,edx
punpcklbw mm0,mm7
movd mm1,ecx
punpcklbw mm1,mm7
paddw mm0,mm1
mov ax,word ptr [edi+esi+4]
add esi,maxlinea
mov bx,word ptr [edi+esi]
shrd edx,eax,5
shrd ecx,ebx,5
shr eax,5
shr ebx,5
shr edx,3
shr ecx,3
shrd edx,eax,5
shrd ecx,ebx,5
shr eax,5
shr ebx,5
shr edx,3
shr ecx,3
shrd edx,eax,13
shrd ecx,ebx,13
movd mm1,edx
punpcklbw mm1,mm7
paddw mm0,mm1
movd mm1,ecx
punpcklbw mm1,mm7
paddw mm0,mm1
mov ax,word ptr [edi+esi+2]
mov bx,word ptr [edi+esi+4]
shrd edx,eax,5
shrd ecx,ebx,5
shr eax,5
shr ebx,5
shr edx,3
shr ecx,3
shrd edx,eax,5
shrd ecx,ebx,5
shr eax,5
shr ebx,5
shr edx,3
shr ecx,3
shrd edx,eax,13
shrd ecx,ebx,13
movd mm1,edx
punpcklbw mm1,mm7
psllw mm1,3
paddw mm0,mm1
movd mm1,ecx
punpcklbw mm1,mm7
paddw mm0,mm1
add esi,maxlinea
mov ax,word ptr [edi+esi]
mov bx,word ptr [edi+esi+2]
shrd edx,eax,5
shrd ecx,ebx,5
shr eax,5
shr ebx,5
shr edx,3
shr ecx,3
shrd edx,eax,5
shrd ecx,ebx,5
shr eax,5
shr ebx,5
shr edx,3
shr ecx,3
shrd edx,eax,13
shrd ecx,ebx,13
movd mm1,edx
punpcklbw mm1,mm7
paddw mm0,mm1
movd mm1,ecx
punpcklbw mm1,mm7
paddw mm0,mm1
mov ax,word ptr [edi+esi+4]
shrd edx,eax,5
shr eax,5
shr edx,3
shrd edx,eax,5
shr eax,5
shr edx,3
shrd edx,eax,13
movd mm1,edx
punpcklbw mm1,mm7
paddw mm0,mm1
psrlw mm0,4
packuswb mm0,mm0
movd eax,mm0
shr eax,3
shrd edx,eax,5
shr eax,8
shrd edx,eax,5
shr eax,8
shrd edx,eax,22
mov word ptr [edi],dx
add edi,2
dec contpixel
jnz linea15
mov eax,pixelsx
mov contpixel,eax
add edi,incxlinea
dec pixelsy
jnz linea15
jmp final
linea16:
sub esi,maxlinea2
mov ax,word ptr [edi+esi]
mov bx,word ptr [edi+esi+2]
shrd edx,eax,5
shrd ecx,ebx,5
shr eax,5
shr ebx,5
shr edx,2
shr ecx,2
shrd edx,eax,6
shrd ecx,ebx,6
shr eax,6
shr ebx,6
shr edx,3
shr ecx,3
shrd edx,eax,13
shrd ecx,ebx,13
movd mm0,edx
punpcklbw mm0,mm7
movd mm1,ecx
punpcklbw mm1,mm7
paddw mm0,mm1
mov ax,word ptr [edi+esi+4]
add esi,maxlinea
mov bx,word ptr [edi+esi]
shrd edx,eax,5
shrd ecx,ebx,5
shr eax,5
shr ebx,5
shr edx,2
shr ecx,2
shrd edx,eax,6
shrd ecx,ebx,6
shr eax,6
shr ebx,6
shr edx,3
shr ecx,3
shrd edx,eax,13
shrd ecx,ebx,13
movd mm1,edx
punpcklbw mm1,mm7
paddw mm0,mm1
movd mm1,ecx
punpcklbw mm1,mm7
paddw mm0,mm1
mov ax,word ptr [edi+esi+2]
mov bx,word ptr [edi+esi+4]
shrd edx,eax,5
shrd ecx,ebx,5
shr eax,5
shr ebx,5
shr edx,2
shr ecx,2
shrd edx,eax,6
shrd ecx,ebx,6
shr eax,6
shr ebx,6
shr edx,3
shr ecx,3
shrd edx,eax,13
shrd ecx,ebx,13
movd mm1,edx
punpcklbw mm1,mm7
psllw mm1,3
paddw mm0,mm1
movd mm1,ecx
punpcklbw mm1,mm7
paddw mm0,mm1
add esi,maxlinea
mov ax,word ptr [edi+esi]
mov bx,word ptr [edi+esi+2]
shrd edx,eax,5
shrd ecx,ebx,5
shr eax,5
shr ebx,5
shr edx,2
shr ecx,2
shrd edx,eax,6
shrd ecx,ebx,6
shr eax,6
shr ebx,6
shr edx,3
shr ecx,3
shrd edx,eax,13
shrd ecx,ebx,13
movd mm1,edx
punpcklbw mm1,mm7
paddw mm0,mm1
movd mm1,ecx
punpcklbw mm1,mm7
paddw mm0,mm1
mov ax,word ptr [edi+esi+4]
shrd edx,eax,5
shr eax,5
shr edx,2
shrd edx,eax,6
shr eax,6
shr edx,3
shrd edx,eax,13
movd mm1,edx
punpcklbw mm1,mm7
paddw mm0,mm1
psrlw mm0,4
packuswb mm0,mm0
movd eax,mm0
shr eax,3
shrd edx,eax,5
shr eax,7
shrd edx,eax,6
shr eax,9
shrd edx,eax,21
mov word ptr [edi],dx
add edi,2
dec contpixel
jnz linea16
mov eax,pixelsx
mov contpixel,eax
add edi,incxlinea
dec pixelsy
jnz linea16
jmp final
linea24:
sub esi,maxlinea2
movd mm0,dword ptr [edi+esi]
punpcklbw mm0,mm7
movd mm1,dword ptr [edi+esi+3]
punpcklbw mm1,mm7
paddw mm0,mm1
movd mm1,dword ptr [edi+esi+6]
punpcklbw mm1,mm7
paddw mm0,mm1
add esi,maxlinea
movd mm1,dword ptr [edi+esi]
punpcklbw mm1,mm7
paddw mm0,mm1
movd mm1,dword ptr [edi+esi+3]
punpcklbw mm1,mm7
psllw mm1,3
paddw mm0,mm1
movd mm1,dword ptr [edi+esi+6]
punpcklbw mm1,mm7
paddw mm0,mm1
add esi,maxlinea
movd mm1,dword ptr [edi+esi]
punpcklbw mm1,mm7
paddw mm0,mm1
movd mm1,dword ptr [edi+esi+3]
punpcklbw mm1,mm7
paddw mm0,mm1
movd mm1,dword ptr [edi+esi+6]
punpcklbw mm1,mm7
paddw mm0,mm1
psrlw mm0,4
packuswb mm0,mm0
movd eax,mm0
mov word ptr [edi],ax
shr eax,16
mov byte ptr [edi+2],al
add edi,3
dec contpixel
jnz linea24
mov eax,pixelsx
mov contpixel,eax
add edi,incxlinea
dec pixelsy
jnz linea24
jmp final
linea32:
sub esi,maxlinea2
movd mm0,dword ptr [edi+esi]
punpcklbw mm0,mm7
movd mm1,dword ptr [edi+esi+4]
punpcklbw mm1,mm7
paddw mm0,mm1
movd mm1,dword ptr [edi+esi+8]
punpcklbw mm1,mm7
paddw mm0,mm1
add esi,maxlinea
movd mm1,dword ptr [edi+esi]
punpcklbw mm1,mm7
paddw mm0,mm1
movd mm1,dword ptr [edi+esi+4]
punpcklbw mm1,mm7
psllw mm1,3
paddw mm0,mm1
movd mm1,dword ptr [edi+esi+8]
punpcklbw mm1,mm7
paddw mm0,mm1
add esi,maxlinea
movd mm1,dword ptr [edi+esi]
punpcklbw mm1,mm7
paddw mm0,mm1
movd mm1,dword ptr [edi+esi+4]
punpcklbw mm1,mm7
paddw mm0,mm1
movd mm1,dword ptr [edi+esi+8]
punpcklbw mm1,mm7
paddw mm0,mm1
psrlw mm0,4
packuswb mm0,mm0
movd dword ptr [edi],mm0
add edi,4
dec contpixel
jnz linea32
mov eax,pixelsx
mov contpixel,eax
add edi,incxlinea
dec pixelsy
jnz linea32
final:
emms
}
}
Éste código fue enviado por fiero el 3 de noviembre del 2002 fierodeval@hotmail.com
Si quieres enviar tu propio código hazlo a eth_cotd@lycos.es
Ola! Como nadie pone nada, lo pongo yo :D
Notad que el filtrado es anisotrópico (para los no iniciados, quiere decir que no filtra igual en todas las direcciones ;))
Sync
vaya churro!
He de decir que aunque parezca un lio de instrucciones es bastante facil, solo fijaros en la parte de 32 o 24 bits. Lo que lía la cosa son los bucles de 16 y 15 bits, ya que hay que pasar los colores a 32 bits para descomponer los valores RGB he ir sumandolos en los registros mmx.
No me habia parado a pensar en eso de "anisotropias" :ojo: , de todas formas hacerlo de derecha a izquierda o de abajo a arriba no seria muy perceptible a nuestros cansados ojos no sync?
un saludo
bueno, no puedo editar, así que escribo otro....
[synchrnzr]
Se me ocurre que para que fuese un filtro perfecto habria que usar diferentes imagenes de entrada y salida no? para no ir machacando los colores...
No he mirado demasiado el codigo (mode flame ON) el codigo ensamblador me produce nauseas. Creo q en c /c++ hubiera estado mejor por 2 cosas. Mas claridad, mas rapidez (estaria por jugarme el cuello) . De q sirve tener un codgo muy bueno si despues nadie lo puede entender o es dificil su lectura?.
Por otro lado es el tipico caso de filtro. Supongo q habras usado una convolucion para obtener el resultado. Se puede demostrar q es mucho mas eficiente cara al numero de operaciones q es mucho mejor hacerlo con FFT's. Moraleja: trata de optimizar los algoritmos y no tu codigo.
(mode flame OFF)
saludos. si tengo algun tiempo tratare de descifrarlo :))
Este filtrado convolutivo no filtra igual las direcciones horizontales o verticales que las diagonales, aunque es lo más utilizado en la demoscene para efectos de soften y desenfoque ;)
Pos no sé qué formas hay de hacer un filtrado isotrópico, yo sólo sé hacer filtrados isotrópicos a partir de la transformada de Fourier de la imagen que es lo que me enseñaron en la asignatura de proceso de imágenes:
[abstenerse no iniciados :I]
La idea es hacer una convolución con una imagen cuyo espectro sea una función gaussiana del mismo tamaño que la imagen. La FFT se aplica en este proceso porque acelera mucho los cálculos (una convolución en el domino espacial es una simple multiplicación en el domino frecuencial) aunque para aplicar la FFT necesitamos que la imagen tenga unas dimensiones concretas (imagen cuadrada, potencia de 2...)
La metodología sería:
a) Tenemos una imagen nxm
B) La convertimos en una imagen qxq (q es un número potencia de 2) y la pasamos a una imagen de complejos para poder aplicar la FFT
c) Hacemos la FFT de la imagen
d) Generamos el espectro de una gaussiana (es más fácil y rápido generar el espectro directamente)
e) Multiplicamos ambos espectros
f) Antitransformamos la imagen resultante
g) Devolvemos a la imagen resultante la profundidad de bits que corresponde (después de la convolución, los valores de cada pixel habran aumentado una burrada)
Cuando hablo de espectro me refiero al módulo de la imagen compleja, supongo que se da por supuesto ;)
Sync
PD: Por cierto, aunque parezca muy complicado y rebuscado, se puede hacer a tiempo real con un coste parecido al del otro método gracias a la FFT
PPD: Más info sobre el tema en www.cvc.uab.es :X9:
¿Tiempo real? Mola. ¿Puedes postear un código que use ese método? Quizás para la semana que viene, :D
[ethernet]
La verdad es que tengo la manía de hacer los bucles muy repetitivos en ensamblador, aunque sé que en muchos casos no merece la pena...
Sin embargo en este caso hacerlo en C sería improductivo. No se me ocurre ninguna forma más rápida de sumar dos colores RGB que esta:
movd mm0,dword ptr [edi+esi] //Primer color en mm0=00000RGB
punpcklbw mm0,mm7 //Desempaquetado de los componentes (de bytes a words) mm0=000R0G0B
movd mm1,dword ptr [edi+esi+4] //Segundo color en mm1=00000RGB
punpcklbw mm1,mm7 //Desempaquetado de los componentes (de bytes a words) mm1=000R0G0B
paddw mm0,mm1 //Suma de los componentes en words
//Después de la suma:
psrlw mm0,1 //Se dividen el resultado entre 2
packuswb mm0,mm0 //Se empaquetan los componentes (de words a bytes) mm0= 0RGB0RGB
movd dword ptr [edi],mm0 //Se almacena el color de 32 bits
Si se haria el código en C no se sumarian las 3 componentes a la vez en una misma instrucción, ya que los compiladores no suelen meter mmx (de esto no estoy muy seguro)
[synchrnzr]
En cuanto a lo de usar FFT, no tengo ni idea de hacer filtros así :oops: , aunque bueno es saberlo... :ojo:
saludos
Loover: lo único que tengo es en ViLi, una especie de versión visual del Lisp desarrollado en el propio CVC. Además no es muy didáctico porque lo que es hacer la FFT ya está implementado en el propio lenguaje. En C supongo que sabría hacerlo, pero la verdad es que no me he puesto nunca porque me dedico más a cosillas de sonido :loco:
En cualquier caso no creo que sea el código de la semana que viene pero a lo mejor algun dia de estos me animo y envio algo sobre sonido, si tengo tiempo :)
Sync
Quizas eso q comentas de sumar dos colores sea lo mas rapido. Yo no digo q no se use asm, por ejemplo para ese caso es util, pero el resto del codigo en c estoy casi seguro q el compilador lo haria mas optimo. Para muestra, un boton :) ->
http://www.codepixel.com/modules.php?op=mo...ewthread&tid=53saludos
Examinando ese código de codepixel me parecía muy raro que ganara C. Estos con los resultados que he obtenido yo con ese mismo código:
time_c++: 1.121921
time_asm: 0.106562
(compilado con VC6)
Por cierto, he leido algo sobre el memcpy() en ese mismo hilo. Esa función de microsoft está integramente realizada en asm, hay un fichero por el visual studio llamado memcpy.c en el que está tol cotarro...
Lo que me resulta extraño son tus tiempos ethernet :-?
un saludo
PD: ethernet, una vez dijiste que con el compilador de intel te salia un botoncito en la barra del VC, ¿como se hace para que salga?
Juro por dios q me daba esos tiempos, ademas lo probe un monton de veces cambiando la memoria el tamaño y demas. Por cierto, con intel me daba mas lento q con vc++.
fiero: no es un boton. En project->settings->c/c++-> preprocesor definitions pones: USE_INTEL_COMPILER (creo q es eso, en la ayuda delcompilador te pone lo q debes poner)
Hola!
He probado el codigo de codepixel y en Debug me va mas lento el codigo en C ( casi que es normal :b )
En release obtengo estos resultados:
time_c++: 0.062924
time_asm: 0.099366
Parece mentira!!
Un saludo!
ups, error mio, lo estaba probando en modo debug. En modo release:
time_c++: 0.073878
time_asm: 0.158920
:o realmente increible!!!
voy a destriparlo a ver lo que hace el compilador con ese bucle for.....
un saludo
poned el codigo en C pa q los q no controlamos asm le echemos un vistazo :)
Citar
es que... si se pone en C, ya no se usa mmx :)
¬_¬;
mejor, no? es mas rapido y no es necesario MMX :P
Dos cosas, como yo vengo diciendo de hace mucho tiempo, hay qe ser un pro para poder codificar en asm mejor qe un compilador actual.
Y lo otro, cuando tais en esas opciones tan horrorosas del vc podreis ver cosas como generar codigo optimizado para X para Y etc.. al activar eso el compilador utilizara instrucciones mmx sse o lo qe sea.
Si ta claro, C se hizo para no codificar en ASM, xqe volver a pegarse con lo mismo?
Fiero -> compilar en debug no tiene perdon xDDD
En c SI se puede usar mmx en las partes q se necesiten.
el vc++7.0 optimiza para mmx y otro tipo de tecnologias similares ?
Hola,
he estado leyendo las "discusiones" acerca de qué es mejor si C/C++ o ensamblador embebido. Personalmente, dudo mucho que se pueda mejorar la eficiencia de un código compilado con un ensamblador decente (en modo de máxima optimización, claro, -o3 en la mayoría de compiladores). Además, la ganancia en claridad y portabilidad del código es muy grande. Yo ni he intentado leer el código en ensamblador puro que habías puesto arriba, demasiado complejo para mí (paso de mirarme las instrucciones MMX y SSE2 que creo que utilizas) :) .
Así que me sumo a los de la opinión que el código en C compilado es más rápido que en ensamblador. Además, por otro lado, es lógico. Los compiladores se hacen específicamente por gente bastante inteligente y documentada. Planean desenrollados y desordenados de código mirando dependencias, etc. Eso, además de ser muy costoso hacerlo a mano (a mí me lo van a decir que me lo piden para el jodido examen de febrero) es muy fácil que, debido a los bloques de paso de parámetros, etc. no podamos optimizarlo tanto como el compilador. Así que nada, me sumo al grupo de los que se ponen en modo Flame OFF. Saludos,
Barkley