¡Cojonudo! Gracias por compartir esto :)

P.D: Es probable que el email no llegase al responder por superar los 100Kb,
tamaño maximo de mensaje permitido en la lista. Lo he subido a 300...

Un saludo,

Joseba 

> -----Mensaje original-----
> De: [EMAIL PROTECTED] 
> [mailto:[EMAIL PROTECTED] En nombre de Miguel Angel Sánchez
> Enviado el: miércoles, 05 de julio de 2006 14:31
> Para: Lista dedicada a Actionscript
> Asunto: [ASNativos] Detectar imágenes con colores similares
> 
> Finalmente pude sacar algo de tiempo libre para hacer la 
> clase que obtiene el color promedio de una imagen a través de 
> su histograma de color.
> 
> Os explico como va el tema:
> - Es un sistema de votación, tenemos una matriz 
> tridimensional histograma[r][g][b] inicializada a ceros.
> - Recorremos cada pixel de la imagen y obtenemos su 
> componente r, g y b.
> - Con esas 3 componentes incrementaremos el valor de la casilla
> correspondiente: histograma[r][g][b]++
> - Finalmente, la casilla que mayor valor tenga será la del 
> color dominante
> 
> Puntualizaciones:
> - Para sacar el color con error cero, habría que crear una 
> matriz histograma[256][256][256], que consumiría demasiada 
> memoria y tiempo para rellenarla.
> - Lo que se hace para reducir tiempo y memoria es discretizar 
> el histograma a, por ejemplo, [64][64][64], de forma que el 
> pixel con valores de rgb 32,64,128 en lugar de votar por la 
> casilla [32][64][128], votaría por la casilla [8][16][32], ya 
> que hemos dividido el espacio de colores entre 4. Esto 
> significa que el color 33,65,129 votaría por la misma casilla 
> que el color anterior, pero este error es admisible ya que a 
> simple vista no podremos diferenciar un color de otro.
> - Varios ejemplos de color promedio dependiendo del número de 
> niveles en el que hayamos dividido el histograma:
>   - [20][20][20] -> rgb = 26 64 13
>   - [40][40][40] -> rgb = 45 51 32
>   - [50][50][50] -> rgb = 46 51 36
>   - [80][80][80] -> rgb = 48 51 35
>   - [150][150][150] -> rgb = 49 53 38
>   - [180][180][180] -> rgb = 50 53 38
> - Como se puede observar, a mayor número de niveles más 
> preciso es el algoritmo, pero mucho más tiempo y memoria 
> consume. Con 50 niveles ya obtenemos un color aceptable que 
> no dista mucho del promedio real, y a simple vista es inapreciable.
> 
> A continuación os pongo la clase sin optimizaciones para que sea más
> legible:
> <code>
> public static function getColorPromedioSinOptimizar(bitmap:BitmapData,
> niveles:Number):Number {
>     var histograma:Array = [];
>     for (var i:Number=0; i<niveles; i++) {
>         histograma[i] = [];
>         for (var j:Number=0; j<niveles; j++) {
>             histograma[i][j] = [];
>             for (var k:Number=0; k<niveles; k++) {
>                 histograma[i][j][k] = 0;
>             }
>         }
>     }
>    
>     var rango:Number = 256 / niveles;
>     var colorPromedio:Number = 0;
>     var mayor:Number = 0;
>    
>     var w:Number = bitmap.width;
>     var h:Number = bitmap.height;
>     var totalPixeles:Number = w*h;
>     var valorVotacion:Number = 1 / totalPixeles;
>     for (var i:Number=0; i<w; i++) {
>         for (var j:Number=0; j<h; j++) {
>             var color:Number = bitmap.getPixel(i, j);
>             var r:Number = (color >> 16) & 0xFF;
>             var g:Number = (color >> 8) & 0xFF;
>             var b:Number = color & 0xFF;
>             r = Math.floor(r / rango);
>             g = Math.floor(g / rango);
>             b = Math.floor(b / rango);
>             histograma[r][g][b] += valorVotacion;
>             if (histograma[r][g][b] > mayor) {
>                 mayor = histograma[r][g][b];
>                 colorPromedio = color;
>             }
>         }
>     }
>     return colorPromedio;
> }
> </code>
> 
> Y a continuación la clase optimizada, que es menos legible 
> pero funciona casi el doble de rápido:
> <code>
> public static function getColorPromedio(bitmap:BitmapData,
> niveles:Number):Number {
>     var histo:Array = [];
>     for (var i:Number=niveles-1; i>=0; i--) {
>         histo[i] = [];
>         var histo1:Array = histo[i];
>         for (var j:Number=niveles-1; j>=0; j--) {
>             histo1[j] = [];
>             var histo2:Array = histo1[j];
>             for (var k:Number=niveles-1; k>=0; k--) {
>                 histo2[k] = 0;
>             }
>         }
>     }
>    
>     var rango:Number = 256 / niveles;
>     var rangos:Array = [];
>     var f:Function = Math.floor;
>     for (var i:Number=0; i<256; i++) {
>         rangos[i] = f(i / rango);
>     }
>    
>     var w:Number = bitmap.width;
>     var h:Number = bitmap.height;
>     var valorVotacion:Number = 1 / (w*h);
>    
>     var colorPromedio:Number = 0;
>     var mayor:Number = 0;
>    
>     for (var i:Number=0; i<w; i++) {
>         for (var j:Number=0; j<h; j++) {
>             var color:Number = bitmap.getPixel(i, j);
>             var r:Number = rangos[(color >> 16) & 0xFF];
>             var g:Number = rangos[(color >> 8) & 0xFF];
>             var b:Number = rangos[(color & 0xFF)];
>             histo[r][g][b] += valorVotacion;
>             if (histo[r][g][b] > mayor) {
>                 mayor = histo[r][g][b];
>                 colorPromedio = color;
>             }
>         }
>     }
>     return colorPromedio;
> }
> </code>
> 
> Es un método estático que podéis incluir en vuestras clases 
> ColorUtils o similares. El primer parámetro es un objeto 
> BitmapData con la imagen y el segundo es el número de niveles 
> en el que vamos a dividir el histograma.
> 
> Un ejemplo de uso podría ser este:
> <code>
> //imagen es un MovieClip con una imagen dentro en su 
> coordenada (0,0) var bmp:BitmapData = new 
> BitmapData(imagen._width, imagen._height); bmp.draw(imagen);
> 
> var colorPromedio:Number = ColorUtil.getColorPromedio(bmp, 50);
> 
> //resultado es un MovieClip con un cuadrado negro //lo 
> coloreo para ver el color promedio de la imagen var c:Color = 
> new Color(timeline.resultado); c.setRGB(colorPromedio); </code>
> 
> Y para terminar este pedazo de tocho, un poco de benchmarks en un AMD
> 2500XP:
> - Imagen 330x374 con 80 niveles (versión sin optimizar): 5.5 
> - 5.7 segundos
> - Imagen 330x374 con 80 niveles (versión optimizada): 3.2 - 
> 3.4 segundos
> 
> Para imágenes más pequeñas o menos niveles, evidentemente 
> menos tiempo.
> 
> Saludos
> 
> [Perdonad que no siga el hilo anterior pero le doy a 
> responder y no aparecen los mensajes en la lista :-/ ]
> 
> -----------------------------------------------------
> ASNativos
> www.5dms.com
> subscripciones/desubscripciones
> http://asnativos.5dms.com
> -----------------------------------------------------
> 
> 


-----------------------------------------------------
ASNativos
www.5dms.com
subscripciones/desubscripciones
http://asnativos.5dms.com
-----------------------------------------------------

Responder a