Programación Específica > Programación de Videojuegos
Re: Erosion Binaria De Un Mapa De Bits
(1/1)
patitofeo:
:hola:
Estoy trabajando en un proyecto en el que debo hacer una localización desde una imagen de video.
Debo encontrar una pelotita naranja.
La imagen queda guardado en un array que toma la forma:
camframe imagen[n_filas][n_columnas][bytes_RGB];
se ve claro ¿no?
camframe es un typedef de unsigned char.
esta imagen la binarizo de forma que se coloreen los pixels naranjas.
El resultado queda en un array
camframe_bin imagen[n_filas][n_columnas].
camframe_bin vuelve a ser unsigned char.
Despues implemente la siguiente función para erosionar la imagen y eliminar ruido.
--- Código: Text --- int erode(camframe_bin *img){ int x,y; for(y=1;y<61;y++) { for(x=1;x<81;x++) { if((*img)[y][x]) { if(!((*img)[y+1][x]&&(*img)[y-1][x]&&(*img)[y][x+1]&&(*img)[y][x-1])) (*img)[y][x]=MARK;; } } }for(y=0;y<62;y++) { (*img)[y][0]=NO_ASERT; (*img)[y][81]=NO_ASERT; } for(x=0;x<82;x++) { (*img)[0][x]=NO_ASERT; (*img)[61][x]=NO_ASERT; } for(y=0;y<62;y++) { for(x=0;x<82;x++) { if((*img)[y][x]==MARK) (*img)[y][x]=NO_ASERT; } }return(0);}
pero me parece muy tosca y lenta. ¿verdad?
La pregunta es si podrian aconsejarme algun algoritmo mas eficiente o si conocen algun sitio donde encontrarlo ("yo busque y busque y nada encontre").
muchas gracias.
Por si quieren hecharle un ojo mejor, les escribi un pequeño codigo donde se recoge una imagen de un .bmp y se introduce en un "camframe". despues se binariza, se erosiona y se pasa de nuevo a un .bmp. así podran verlo.
Gracias a cualquiera que tenga un ratito y le heche un ojo.
:gracias:
patitofeo:
Se me olvido decirles, que el tamaño de la imagen debe ser fija de 62x82 pixels (chiquitilla) y 24 bpp.
Si desean darle una ojeada al codigo, primero se les pide que introduzcan el path de la imagen origen.
Se binariza y se les pide un nombre para guardar el resultado.
Despues se erosiona y se vuelve a pedir un path para almacenar el resultado.
Les he hecho una pequeña imagen un poco artesanal para probar. Se la incluyo.
Gracias a todos de antemano.
:hola:
PD: les envio la imagen comprimida porque no me deja de otro modo
Ruben3d:
Hola.
Hace unos días también implementé una función que manipulaba una imagen (realiza un blur). Inicialmente la realicé refiriendome a cada pixel con un método getPixel y otro putPixel que básicamente hacían lo que tú: multiplicaciones de enteros para situarse en los diferentes píxeles de la imagen (con los índices entre corchetes []). De este manera me funcionaba a 35-37 fps a 240x320.
A continuación lo que hice fue mantener mis dos bucles anidados para moverme por la imagen pero, en vez de usar los contadores, iba sumando +1 a un puntero que inicialmente inicialicé con la dirección del primer píxel. De esta manera puedo recorrer la pantalla sin multiplicar en ningún punto. Para saber el valor del píxel de arriba o de abajo calculé cuánto debía sumar o restar al puntero para subir o bajar un píxel. De esta forma subí a 160-170 fps con una imagen del mismo tamaño. Para que lo veas más claro (porque no sé si me he explicado claro, que estoy espeso) te pongo el código del que hablo:
Antes de optimizar
--- Código: Text --- int _x; int x_; int _y; int y_; int r; int g; int b; for (int y=1; y<io3dCore.getDisplay().getHeight()-2; y++) { int x; // caso de x=0 _x = g2d.getPixel(0, y); x_ = g2d.getPixel(0+1, y); _y = g2d.getPixel(0, y-1); y_ = g2d.getPixel(0, y+1); r = (CR5(_x)+CR5(x_)+CR5(_y)+CR5(y_))>>2; g = (CG6(_x)+CG6(x_)+CG6(_y)+CG6(y_))>>2; b = (CB5(_x)+CB5(x_)+CB5(_y)+CB5(y_))>>2; g2d.putPixel(0,y, C565(r,g&0xFFFE,b)); for (x=1; x<io3dCore.getDisplay().getWidth()-2; x++) { _x = g2d.getPixel(x-1, y); x_ = g2d.getPixel(x+1, y); _y = g2d.getPixel(x, y-1); y_ = g2d.getPixel(x, y+1); r = (CR5(_x)+CR5(x_)+CR5(_y)+CR5(y_))>>2; g = (CG6(_x)+CG6(x_)+CG6(_y)+CG6(y_))>>2; b = (CB5(_x)+CB5(x_)+CB5(_y)+CB5(y_))>>2; g2d.putPixel(x,y, C565(r,g&0xFFFE,b)); } // caso de x=width-1 x = io3dCore.getDisplay().getWidth()-2; _x = g2d.getPixel(x-1, y); x_ = g2d.getPixel(x, y); _y = g2d.getPixel(x, y-1); y_ = g2d.getPixel(x, y+1); r = (CR5(_x)+CR5(x_)+CR5(_y)+CR5(y_))>>2; g = (CG6(_x)+CG6(x_)+CG6(_y)+CG6(y_))>>2; b = (CB5(_x)+CB5(x_)+CB5(_y)+CB5(y_))>>2; g2d.putPixel(x,y, C565(r,g&0xFFFE,b)); }
Tiene algunas diferencias (y algún bug) con respecto a la optimizada, ya que la generalicé para rectángulos de tamaño arbitrario. haz caso al bucle central, ya que trato por separado los casos de los extremos.
Ahora la versión optimizada. Es un poco más larga, pero si te fijas en todo el código sólo hay una multiplicación (y no está en ningún bucle). Es tan larga porque trato las esquinas y los bordes por separado, pero fijate en el bucle más central (el que tiene el comentario '//centro').
Versión optimizada
--- Código: Text ---void io3d::CGraphics2D::blurArea(int x1, int y1, int x2, int y2){ if (x1>x2) { switchElems<int>(x1,x2); switchElems<int>(y1,y2); } if (y1>y2) { switchElems<int>(y1,y2); } int _x; // Píxel de la izquierda int x_; // Píxel de la derecha int _y; // Píxel de arriba int y_; // Píxel de abajo int r; int g; int b; int next_line = -(x2-x1+1)+m_nNormYPitch; int x; WORD *pPixel = &m_pBackBuffer[x1+y1*m_nNormYPitch]; // Esquina superior izq. _x = *pPixel; x_ = *(pPixel+1); _y = *(pPixel+1+m_nNormYPitch); // En diagonal abajo-dcha. y_ = *(pPixel+m_nNormYPitch); r = (CR5(_x)+CR5(x_)+CR5(_y)+CR5(y_))>>2; g = (CG6(_x)+CG6(x_)+CG6(_y)+CG6(y_))>>2; b = (CB5(_x)+CB5(x_)+CB5(_y)+CB5(y_))>>2; *(pPixel++) = C565(r,g&0xFFFE,b); // Centro primera fila for (x=x1+1; x<x2; x++) { _x = *(pPixel-1); x_ = *(pPixel+1); _y = *pPixel; y_ = *(pPixel+m_nNormYPitch); r = (CR5(_x)+CR5(x_)+CR5(_y)+CR5(y_))>>2; g = (CG6(_x)+CG6(x_)+CG6(_y)+CG6(y_))>>2; b = (CB5(_x)+CB5(x_)+CB5(_y)+CB5(y_))>>2; *(pPixel++) = C565(r,g&0xFFFE,b); } // Esquina superior dcha. _x = *(pPixel-1); x_ = *pPixel; _y = *(pPixel-m_nNormYPitch); y_ = *(pPixel-1+m_nNormYPitch); // En diagonal abajo-izq. r = (CR5(_x)+CR5(x_)+CR5(_y)+CR5(y_))>>2; g = (CG6(_x)+CG6(x_)+CG6(_y)+CG6(y_))>>2; b = (CB5(_x)+CB5(x_)+CB5(_y)+CB5(y_))>>2; *(pPixel++) = C565(r,g&0xFFFE,b); // Parte central for (int y=y1+1; y<y2; y++) { // Reajuste para la siguiente línea pPixel += next_line; // caso de x=x1 _x = *pPixel; x_ = *(pPixel+1); _y = *(pPixel-m_nNormYPitch); y_ = *(pPixel+m_nNormYPitch); r = (CR5(_x)+CR5(x_)+CR5(_y)+CR5(y_))>>2; g = (CG6(_x)+CG6(x_)+CG6(_y)+CG6(y_))>>2; b = (CB5(_x)+CB5(x_)+CB5(_y)+CB5(y_))>>2; (*pPixel++) = C565(r,g&0xFFFE,b); // Centro for (int x=x1+1; x<x2; x++) { _x = *(pPixel-1); x_ = *(pPixel+1); _y = *(pPixel-m_nNormYPitch); y_ = *(pPixel+m_nNormYPitch); r = (CR5(_x)+CR5(x_)+CR5(_y)+CR5(y_))>>2; g = (CG6(_x)+CG6(x_)+CG6(_y)+CG6(y_))>>2; b = (CB5(_x)+CB5(x_)+CB5(_y)+CB5(y_))>>2; *(pPixel++) = C565(r,g&0xFFFE,b); // Optimizará cambiar 0xFFFE por 0xFE ? } // caso de x=x2 _x = *(pPixel-1); x_ = *pPixel; _y = *(pPixel-m_nNormYPitch); y_ = *(pPixel+m_nNormYPitch); r = (CR5(_x)+CR5(x_)+CR5(_y)+CR5(y_))>>2; g = (CG6(_x)+CG6(x_)+CG6(_y)+CG6(y_))>>2; b = (CB5(_x)+CB5(x_)+CB5(_y)+CB5(y_))>>2; *(pPixel++) = C565(r,g&0xFFFE,b); } // Reajuste para la siguiente línea pPixel += next_line; // Esquina inferior izq. _x = *pPixel; x_ = *(pPixel+1); _y = *(pPixel-m_nNormYPitch); y_ = *(pPixel+1-m_nNormYPitch); // En diagonal arriba-dcha r = (CR5(_x)+CR5(x_)+CR5(_y)+CR5(y_))>>2; g = (CG6(_x)+CG6(x_)+CG6(_y)+CG6(y_))>>2; b = (CB5(_x)+CB5(x_)+CB5(_y)+CB5(y_))>>2; *(pPixel++) = C565(r,g&0xFFFE,b); // Centro última fila for (x=x1+1; x<x2; x++) { _x = *(pPixel-1); x_ = *(pPixel+1); _y = *(pPixel-m_nNormYPitch); y_ = *pPixel; r = (CR5(_x)+CR5(x_)+CR5(_y)+CR5(y_))>>2; g = (CG6(_x)+CG6(x_)+CG6(_y)+CG6(y_))>>2; b = (CB5(_x)+CB5(x_)+CB5(_y)+CB5(y_))>>2; *(pPixel++) = C565(r,g&0xFFFE,b); } // Esquina inferior dcha. _x = *(pPixel-1); x_ = *pPixel; _y = *(pPixel-m_nNormYPitch); y_ = *(pPixel-1-m_nNormYPitch); // En diagonal arriba-izq. r = (CR5(_x)+CR5(x_)+CR5(_y)+CR5(y_))>>2; g = (CG6(_x)+CG6(x_)+CG6(_y)+CG6(y_))>>2; b = (CB5(_x)+CB5(x_)+CB5(_y)+CB5(y_))>>2; *(pPixel++) = C565(r,g&0xFFFE,b);}
Espero que con todo esto veas lo que te estoy tratando de decir. Si tienes alguna duda pregunta por aqui.
Un saludo.
Ruben3d
patitofeo:
:hola:
Muchas gracias, he cambiado la division por un desplazamiento y ahora consigo mucha mas velocidad.
Me ha venido genial tu código. De todas formas seguiré trabajando en ello, seguro que aun se le puede sacar un poquitin más de partido. Ya os contaré. De todos modos cualquier sugerencia sigue siendo bien recibida.
Muchas gracias ruben3d
Navegación
Ir a la versión completa