PDA

Ver la Versión Completa : Algoritmo de recorrido de imagenes.


bustio
08-01-2005, 19:20:47
Hola Comunidad:

Resulta que tengo que hacer un trabajo para la empresa donde estoy practicando(pues estudio informatica en la Universidad) y tengo que entregar el histograma de una imagen de acuerdo a los valores que esta presente en la escala RGB.
El detalle esta en que ya hice el histograma(implementado en C#) y funciona a las mil maravillas... pero solo para imagenes de poco tamanno, es decir, para imagenes en el orden de los Kb y algunas en Mb. Todo esta muy bien, solo que este histograma debe ser capaz de trabajar para imagenes grandes, digase en el orden de los 50 Mb pues para estas imagenes es que se quiere implementar este histogarama.
Este histograma lo que hace es recorrer la imagen pixel por pixel, y tomando de cada uno de ellos el valor que tiene en la escala de los rojos, verdes y azules, que sera un valor entre 0 y 255. Luego estos valores se iran contando dentro de un array que corresponde con los colores de las escalas... es decir, que tendre un array para almacenar los valores en la escala de Azules, otro para la escala de Rojos y otro para la escala de Verdes. Si el primer pixel tiene un valor de 25 para el azul, lo que se hace es ir a la pos 25 de array de azules e incrementar el valor que ahi estara en 1(si no hay valores para esta pos. el nodo del array contendra el valor cero.)
El fin es contar la frecuencia en que aparece una tonalidad para las distintas escalas y luego graficar esto.

Como se puede ver, el algoritmo es bien simple.. pero solo para imagenes de hasta 1024 x 768 pixeles. Para imagenes mas grandes comienza a demorarse demasiado y se necesita ante todo velocidad y poca congestion del procesador.. cosas que de la manera en que lo implemente no se logran, pues el tiempo en que se recorreo cada uno de los pixeles de la imagen el micro esta trabajando al 100%. Necesito algun otro algoritmo que optimice esto y la verdad es que no tengo idea de como lograrlo.
Entonces, publico mi interrogante en este foro a ver si alguien me pudiera sugeriri alguna idea.

Gracias.. y Saludos...

Lazaro Bustio Martinez.

Mick
09-01-2005, 00:01:58
Supongo que el calculo que usas consiste en recorrer solamente una vez los pixeles de la imagen, es un algoritmo simple de modo que no hay forma de conseguir otro algoritmo que vaya mas rapido, ya que es imposible calcular el histograma sin acceder como minimo una vez a todos y cada uno de los pixeles.
Tampoco indicas cuanto tarda en ejecutarse para poder saber si realmente es demasiado tiempo, como referencia te puedo decir que el calculo que haces programado en Delphi para una imagen de 10 megabytes tarda menos de 2 decimas de segundo en un PIV a 2.4 Ghz (sin contar el tiempo de carga de la imagen en memoria desde el disco duro).
Si solo recorres una vez cada pixel, la lentitud podria venir o de que no hay suficiente memoria libre para cargar la imagen completa en memoria, o que utilices una forma muy lenta de acceder a los pixeles de la imagen, o que quizas el codigo hecho en C# no lo hayas compilado a codigo nativo.
Si no muestras ningun codigo fuente dificilmente se podra descubrir el problema.

En cuanto a la congestion del procesador , en general el procesador mientras esta ejecutando algo sea lo que sea siempre esta al 100%, si solo usase la mitad de ciclos libres (al 50% por ejemplo) el calculo tardaria el doble de tiempo, no teniendo otros threads que ejecutar, seria bastante tonto que el procesador desperdiciase su poder de calculo haciendo los calculos a mitad de su velocidad.

Saludos

bustio
09-01-2005, 00:17:52
Hola:
Ante todo, debo agradecerte el tomarte el trabajo de responder a mi pregunta. Te dire que estoy trabajando en un Celeron P4 a 1.7GHz de velocidad, con 248 Mb de RAM y para una imagen de 28 Mb, con 4000 y tantos por 7000 y tantos pixeles se demora bastante... por encima de los 10 minutos, cosa que es indeseable. Estoy comparando mi histograma con el que trae implementado el Paint Shop Pro 9 y para la misma imagen solo se demora unos pocos segundos. Evidentemente, ellos hacen algun tipo de analiisis no solo mas rapido qeu el que yo hago, sino muchisimo mas eficiente. En pocas palabras, lo que hago es algo como esto:

creo una variable tipo Bitmap y luego le asigno la imagen leida desde el fichero que deseo analizar.
Luego, cuento los pixeles por filas y columnas y luego con un ciclo voy visitando pixel a pixel, y en ese momento y para el pixel(x,y) obtengo sus respectivos valores en la escala RGB y los almaceno en los arrays de los que ya te hable en mi pregunta. Pienso que la demora esta en el recorrido de la imagen, por que lo que resta es leer estos arrays y con LineTo... graficar los valores.
No se de que otra manera pudiera optimizar esto. En realidad, no me interesa tanto que el procesador este al 100% como que el calculo del histograma sea rapido. Pienso que se puede sacrificar un poco la congestion del micro con el fin de que este analisis sea rapido.

De cualquier manera, si crees ser capaz de ayudarme con el codigo, pues perfectamente te lo puedo enviar(si es que esto no viola las reglas del foro)para ver de qye manera se puede llegar a la solucion mas optima.
Te agradezco otra vez por tomarte el trabajo de responderme..

GRACIAS!!!

<Sergio>
09-01-2005, 15:48:13
creo una variable tipo Bitmap y luego le asigno la imagen leida desde el fichero que deseo analizar.
Luego, cuento los pixeles por filas y columnas y luego con un ciclo voy visitando pixel a pixel, y en ese momento y para el pixel(x,y) obtengo sus respectivos valores en la escala RGB
¿No estarás accediendo a la imagen con el pixels[], verdad?:rolleyes:

P.D.

Si lo estás haciendo es mejor que utilices el scanline (muchísimo más rápido por varios motivos...), te devuelve una referencia a memoria al inicio de la linea "y".

Define un tipo de dato de acuerdo al tipo de formato de pixel, ej: arreglo de bytes para 24 bits: en bytes: 3*ancho de la imagen.

TLinea=array[0..64535] of byte;//el 64535 solo para el control de rangos del compilador, puede ser 0..0 si no controla rangos.
PLinea=^Tlinea;

Defines una variable del tipo PLinea y le asignas el valor que devuelve
bitmap.scanline(y) suponiendo que tienes un objeto bitmap:Tbitmap

Mucho cuidado de pasarse del ancho total en bytes de cada linea de tu imagen.

Otra forma es usar directamente la referencia a memoria, guardarla en un entero de 4 bytes mientero=integer(bitmap.scanline(y)), hacer un ciclo while e incrementar la posición de memoria a revisar y cuando sea necesario aclararle al compilador que quieres usar tu entero como referencia a memoria: mivalor:=byte(pointer(mientero)^), esto genera código más eficiente.

El pixels[x,y] está pensado para acceder a cualquier pixel de la imagen al azar: realiza control de rangos, llama al scanline por cada pixel y además que realiza conversión de color al formato utilizado por Tcolor. Llamar al scanline para cada pixel es bastante pesado comparado a llamarlo sólo para cada línea.

bustio
10-01-2005, 00:52:08
Pues si Sergio, muchisimas gracias por responder a mi pregunta. En realidad si estoy usando Pixel[]..... fijate bien en mi pregunta original, que dije que estaba programando en C#. Puse esta pregunta en este foro de Delphi por que tambien programo bastante en Delphi y creo que este es uno de los mejores foros que existen,.... ademas, lo que andaba buscando es un algoritmo para optimizar mi tratamiento a las imagenes.
Aunque no he probado todavia, supongo que en C# tambien exista un ScanLines... y siendo asi pondre a prueba tu sugerencia, todo esta en que exista esa funcion o propiedad.
De todas maneras te agradezco mucho haberte tomado el trabajo de leerte mi pregunta y responder.

Saludos..

Lazaro Bustio Martinez.

bustio
13-08-2005, 19:30:26
Hola comunidad:
Hace ya mucho tiempo le encontre la solucion a mi problema, y no la habia compartido. Espero que sepan disculparme.

Lo que se debe hacer para acelerar la velocidad con que se recorre un gra bitmap es muy sencillo. Solo basta con pensar que es una imagen BMP??? pues como todo, es un fichero, que tiene un encabezado que lo caracteriza y un area de datos. Es mucho mas comodo, sencillo y rapido tener una "copia" de este fichero en la memoria de la PC y tratarlo segun sus datos del encabezado que leer o utilizar una instruccion que lo haga, tal vez por un metodo que realiza cientos de operaciones que en mi caso no me interesaban.
Lo que hice fue leer el encabezado del fichero BMP en cuestion, analizar que es lo que describia en el area de datos y luego, basandome en esta informacion, pues interpretar los numeros, que seria un array de integers en la RAM. Estos arrays, por muy largos que sean son muy rapidos accesados de esta manera.
y vean como es asi, que en mi pc, un Celeron con 256 Mb de Ram y 1.7Ghz de velocidad, una imagen de de 57 Mb se recorrio y se analizo en tan solo 13 segundos como promedio. El resultado creo que es satidfactorio.
Espero qeu le sirva a alguien lo que he tratado de explicar. De tan sencilla la solucion jamas se me ocurrio tomarla en serio.
Ya ven como son las cosas en el mundo de la programacion.
Muchas gracias!

Casimiro Notevi
13-08-2005, 20:21:16
Nos alegramos que el desenlace haya sido feliz :)

Muy interesante, todos los días se aprende algo.

lpmlpm
29-08-2005, 22:20:50
Yo he trabajado tambien con imágenes muy grandes, teniendo como en tu caso que hacer un recorrido de pixeles, pero en mi caso no solo eran bmp's, sino diferentes formatos de imagenes las que se debian analizar... la solución fue muy simple para mi, usar la libreria Graphics32 www.g32.org que hace un tratamiento de imágenes y canvas en general de manera fenomenal... en un suspiro recorre pixel a pixel una imagen grande

saludos y espero a alguien le sirva