Imagenes BMP. Destripándolas a fondo

Pues hoy, tito amchacon os va a hablar de las imagenes en formato BMP. Como funcionan, como están diseñadas y porque ocupan tanto tamaño.

Los pixeles, unidad mínima del sistema Imageximal (?)

Toda imagen, independientemente del formato que tenga. Está formada con un conjunto de *pixeles, cuantos más tenga más grande será la imagen.

Así pues, una imagen de 500x200 significa que tiene 500 pixeles a lo ancho y 200 pixeles a lo alto. En total unos 500x200 = 100.000 pixeles. Lo que equivale a 0,1 megapixeles (1 megapixel son 1 millón de pixeles).

Cada pixel tiene un color determinado, pintando cada color pixel a pixel se forma la imagen. La forma de expresar el color de cada pixel depende del formato de imagen que cojamos (de hecho en la práctica, es la única diferencia que hay de un formato a otro).

Colores, como se forman

En las imagenes BMP tenemos 4 formatos distintos de colores:

- Monocromático: O dicho de otra forma, en blanco o negro. Pero cuando digo blanco o negro, digo literalmente en blanco y negro. No hay grises ni nada:
Imagen

- Modo 16 colores/4 bits: Se escojen 16 colores fundamentales (negro,azul,rojo amarillo...). Se usa para dibujos sencillos (como los que hacíamos de pequeñitos). Pero carece de la potencia para mostrar fotografías:

Imagen

- Modo 256 colores/8 bits: Se escojen 256 colores fundamentales. Es un punto intermedio entre 24 bits (color real) y 16 colores. Sirve para mostrar dibujos y diseños más complejos, pero sigue sin ser válidos para fotografías:

Imagen

- Modo 24 bits: Color real, equivale al número de colores del mundo en el que vivimos y es el número de colores que tienen las fotografías:

Imagen

Los colores de 24 bits en BMP están formado por las mezclas de 3 colores básicos: Rojo, Verde y Azul (Red, Green, Blue. Sistema RGB). Cada color tiene una intensidad del 0 al 255, jugando con las intensidades podemos formar cualquier color que querramos.

Por ejemplo, si mezclamos 255 de Rojo y 255 de Verde conseguiremos amarillo. Ahora bien, si mezclamos 255 de rojo y 230 de Verde, conseguiremos un amarillo con distinta intensidad, si seguimos disminuyendo el verde obtendremos el naranja. Pero si a su vez le añadimos bastante azul, podríamos conseguir rosa.

El tamaño, nuestro peor enemigo

Los BMP definen los pixeles de uno, mientras que los PNG/GIF los definen como asociaciones (si hay 5 pixeles de rojo seguidos, no define los 5 pixeles uno a uno, sino que define una línea de 5 pixeles). Es por eso por lo que los BMP ocupan tanto.

Las dos cosas que condicionan el tamaño de un BMP es en primer lugar, el número de pixeles que tenga la imagen, y en segundo lugar, el formato de colores elegido:

- Formato Monocromático: Cada byte representa 8 pixeles.
- Formato 16 colores: Cada byte representa 2 pixeles.
- Formato 256 colores/ 8 bits: Cada byte representa un pixel.
- Formato 24 bits: Cada 3 bytes representan un pixel.

Teniendo en cuenta eso, podemos hacer una simple formula que nos calcule el tamaño que tendrá un BMP:

Ancho x Alto x FactorDeColor

Siendo "Factor de Color" 1/8 si la imagen es monocromática, 1/2 si la imagen es de 16 colores, 1 si la imagen es de 256 colores, y 3 si la imagen es de 24 bits.

Cojamos una imagen de 600x400 y veamos su tamaño en cada formato de color:

- Modo monocromático: 600x400x1/8 = 30.000 Bytes = 30 kb.
- Modo 16 colores: 600x400x1/2 = 120.000 Bytes = 120 kb.
- Modo 256 colores: 600x400x1 = 240.000 Bytes = 240 kb.
- Modo 24 bits: 600x400x3 = 720.000 Bytes = 720 kb.

Los tamaños no son exactos, puesto que habría que sumar 50 Bytes aproxidamante del encabezado de la imagen (el encabezado básicamente, dice que tamaño tiene la imagen, en que formato de color está, la firma del programa con el que se hizo...). Además para pasar de Bytes a Kb hay que dividir entre 1024 y no 1000... Pero bueno, todo sea para simplificar cálculos xD).

¿Por que debo creerte?

No debes creerme, por eso voy a demostrarte todo lo que he dicho. Paso a paso y fácilmente recreable.

Formato hexadecimal, un invento extravagante.

Para ello os voy a hablar del formato hexadecimal, como mucho sabrán. Todo en el ordenador funciona con una base binaria (unos y ceros). Cada "bit" de datos puede ser un 1 o un 0.

Ahora bien, las unidades de información no usan bits sino Bytes que son asociaciones de 8 bits. Cada bit tiene 2 posibles valores, luego cada Byte tiene 16 valores distintos.

Para representar cada unos de los valores que puede tener un Byte se usa la base Hexadecimal, que se diferencia de la nuestra es que los números llegan hasta el 16, en vez de hasta el 10.

La base normal que usamos siempre:
0 1 2 3 4 5 6 7 8 9

La base hexadecimal:

0 1 2 3 4 5 6 7 8 9 A B C D E F

A partir de la F, haríamos igual que siempre. Añadiríamos un numero más y seguiríamos:

10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F

Y así hacia el final de los tiempos.

Imagenes al desnudo

Vamos a abrir una imagen BMP con un editor hexadecimal, un editor hexadecimal muestra el código hexadecimal de un archivo. Por lo que podremos ver el contenido de los Bytes, incluso el de los Bits.

Por su facilidad, potencia, estabilidad (y porque es gratis y en Español). Usaremos este editor hexadecimal en la demostración:
http://hxd.softonic.com/

Creamos una imagen en 256 colores BMP de las sencillitas:

Imagen

(sencilla de cojones)

Para guardarla en 256 colores, lo podemos hacer con el paint mismo:

Imagen

Ahora abriremos nuestro Editor Hexadecimal, seleccionamos Archivo -> Abrir y cogeremos nuestra imagen:

Imagen

Os explicare brevemente como funciona el editor, la primera columna indica que parte del archivo estamos (en el Byte 0, en el Byte 10, en el Byte 20...).

La segunda, son los valores hexadecimal de cada Byte.

La tercera columna, es una interpetración de esos valores en texto. Los editores hexadecimales suelen usarse muchas veces, para traducir o capturar textos de archivos. De ahí que tengamos esa columna... Nosotros ni caso.

Lo que vemos en primer plano, es el encabezado de la BMP. Se está indicando, en que formato está la imagen, que tamaño tiene... Si seguimos bajando, encontraremos donde empieza la imagen, dado que es toda del mismo color, creo que nos daremos cuenta rápido:

Imagen

That´s Suspicious...

Aquí se ve, como cada Byte representa un pixel de la pantalla (en 256 colores)... Para confirmarlo, vamos a cambiar unos de estos valores:

Imagen

A continuación, le damos a guardar y vemos la imagen:

Imagen

Oh vaya, que decepción. Parece que no ha pasado nada... ¡Un momento! ¿Que es eso de ahí?

Imagen

Ampliando al 800% y forzando la vista, podemos ver que un pixel ha cambiado de color.

Repitamos la jugarreta con varios pixeles:

Imagen

Hemos cambiado unos 100 pixeles de unos (400x200 = 80.000 pixeles) que tiene la imagen. Y lo podemos comprobar:

Imagen

Sigue siendo menos de una milésima parte de la imagen, pero se notan las manchas verdes de abajo, no?

Creo que ha quedado claro, que cada vez que modificamos uno de los bytes de la imagen. Se modifica un pixel de esta, por lo cual queda demostrado que en 256 colores, cada Byte equivale a un pixel.

Hagamos la prueba ahora con 24 bits, cogemos la misma imagen y la guardamos en 24 bits:

Imagen

Al echarle una radiografía interior:

Imagen

Despertad del "shock" que acabais de sufrir al ver esto y pensad con claridad.

Tenemos unas FF y dos espacios de 00... Si recordais las imagenes de 24 bits tienen 3 bits: Uno que indica la cantidad de rojo, otro que indica la cantidad de verde y otro que indica la cantidad de azul...

Ahora bien, en formato hexadecimal, FF quiere decir 255!. Tenemos pixeles de 255 de rojo y 0,0 de verde y azul.

Si abrimos una imagen con amarillo:

Imagen

Imagen

FF FF y 00... Es decir, 255 de rojo, 255 de verde y 0 de azul. La composición del amarillo!

Ha quedado claro que los pixeles de las imagenes de 24 bits, se componen de 3 bytes por pixel: Uno por cada color.

Para rematar la faena, abriremos una imagen de 16 colores, pero esta vez cogeremos una más pequeña para ver mejor sus efectos:

Imagen

Imagen

Se huele el humo de vuestra cabeza chamuscada desde aquí...

Comenzemos a jugar, cambiamos un valor:

Imagen

Imagen

Vale, está claro. Al modificar un Byte hemos cambiado un pixel de color.

Sin embargo, solo hemos modificado la primera cifra del Byte. Vamos a probar a modificar la segunda cifra del Byte aver que pasa:

Imagen

Imagen

Lo que pasa, es que un segundo pixel ha cambiado de color.

Es decir, la primera cifra de los Bytes indica el color del primer pixel y la segunda cifra del pixel siguiente... Luego con cada Byte se representa 2 pixeles.

Dado que estamos en formato hexadecimal, podemos representar 16 valores distintos con cada cifra (0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F). De modo que podremos representar los 16 colores sin problema.

Y ahora demos el salto a la fama, pasemos al modo Monocromático:

Imagen

120 Bytes de tamaño O_O

Imagen

No queda nada claro no? Modificamos un Byte:

Imagen

Imagen

Hemos cambiado un pixel, nada que no supieramos.

Pero ahora pongamos un FF en el Byte en vez de un 1:

Imagen

Imagen

¡1,2,3,4,5,6,7... 8! ¡8 prostitutas!

Quiero decir, 8 pixeles!. Con un byte hemos modificado 8 pixeles diferentes, queda claro que cada byte de una imagen monocromática, representa 8 pixeles distintos.

Conclusión

Las imagenes BMP son imagenes sencillísimas, básicamente representan la imagen pixel a pixel. Esto lo hace muy fácil de interpetrar y abrir, pero tienen un gran problema con el tamaño.

El formato BMP es invención de windows. Y se nota.
Muy interesante :O

Ya casi no se usan bmp's, aun recuerdo los tiempos de windows 95/98 y las imagenes de varios megas a bajas resoluciones.
Claro que en aquella epoca no existian camaras como las de ahora.
ZeLu escribió:Claro que en aquella epoca no existian camaras como las de ahora.

¿Cuanto ocuparía una imagen de 10 megapixeles en BMP?. Teniendo en cuenta que 10 megapixeles = 10 millones de pixeles y que las fotos estarían en 24 bits de color: Son 3 bytes por pixel que serían unos 30 millones de bytes, que son 30.000 kb que son 30 MB por foto... Totalmente inviable [carcajad]

Pero es un formato sencillo y fácil de interpetrar, por eso siempre tendrá soporte.
Buena explicación, aunque te podrías plantear haberlo puesto en la Wiki. Yo usé hace años en mi PFC estas imágenes para ocultar mensajes (esteganografía) y elegí este formato por su sencillez, incluso hice una pequeña librería para leer y manipular imágenes.

También están los BMP de 256 colores en escala de grises, aunque creo que era una variante de los que tú has puesto: En las imágenes de 16 y 256 colores, antes de los valores de cada pixel hay una paleta con 16 o 256 entradas, en la que cada entrada corresponde a un valor de color de 24 bits. Por ejemplo, si queremos poner que la entrada 1 de la paleta sea el color rojo, la paleta quedaría como:

1 -> 0 0 255

Un detalle curioso es que los colores se establecen con el formato BGR, no RGB así que el rojo es el último valor a modificar.

Si ahora queremos utilizar el rojo en la paleta, podríamos a 1 el píxel correspondiente. Como sólo hay 16 o 256 entradas en la paleta, nos bastan 4 u 8 bits por pixel.

La cosa es que para las imágenes en escala de grises de 8 bits, basta con establecer una paleta en la que cada entrada sea un tono de gris diferente.
Ottia, muy interesante el artículo, si señor. [plas]
Sólo una cosa. ¿El encabezamiento qué es? Supongo que lo que indica que el archivo es un BMP, pero ¿Qué datos tiene que llevar?
Pues el encabezado como tal es simplemente 0x42 0x4D, es decir BM en código ASCII.

En la Wikipedia hay más info de todo lo que lleva el archivo:
http://en.wikipedia.org/wiki/BMP_file_format

En realidad existe un formato incluso más sencillo, aunque no recuerdo su nombre, en el que simplemente ponías un encabezado, las filas, las columnas y empezabas a rellenar cada píxel con los colores. (Lo encontré http://es.wikipedia.org/wiki/Formatos_Netpbm son los archivos pgm).
JuananBow escribió:Ottia, muy interesante el artículo, si señor. [plas]
Sólo una cosa. ¿El encabezamiento qué es? Supongo que lo que indica que el archivo es un BMP, pero ¿Qué datos tiene que llevar?

El encabezado indica en primer lugar, la firma de BMP (para demostrar que es un fichero BMP) luego lleva datos del tamaño del archivo, del tamaño de la imagen... Aún estoy intentando descifrar en que orden van y como están guardados.

Pero los que he podido observar, es que si los guardas en 256/16 colores, hay un espacio reservado donde se definen en RGB los 256/16 colores que se van a usar... Luego prácticamente casi todo el encabezado se lo pasa definiendo los colores.

Si lo guardas en monocromático o 24 bits, el encabezado no dura más de 36 bytes (porque no hay paleta de colores que definir).

Korso10 escribió:Buena explicación, aunque te podrías plantear haberlo puesto en la Wiki. Yo usé hace años en mi PFC estas imágenes para ocultar mensajes (esteganografía) y elegí este formato por su sencillez, incluso hice una pequeña librería para leer y manipular imágenes.

También están los BMP de 256 colores en escala de grises, aunque creo que era una variante de los que tú has puesto: En las imágenes de 16 y 256 colores, antes de los valores de cada pixel hay una paleta con 16 o 256 entradas, en la que cada entrada corresponde a un valor de color de 24 bits. Por ejemplo, si queremos poner que la entrada 1 de la paleta sea el color rojo, la paleta quedaría como:

1 -> 0 0 255

Un detalle curioso es que los colores se establecen con el formato BGR, no RGB así que el rojo es el último valor a modificar.

Si ahora queremos utilizar el rojo en la paleta, podríamos a 1 el píxel correspondiente. Como sólo hay 16 o 256 entradas en la paleta, nos bastan 4 u 8 bits por pixel.

La cosa es que para las imágenes en escala de grises de 8 bits, basta con establecer una paleta en la que cada entrada sea un tono de gris diferente.

Vaya, precisamente había descubierto algo parecido esta mañana xD... Los colores de la paleta se definen previamente en el encabezado... Lo que no sabía es que se usara BGR (tenía toda la pinta de usar el RGB de toda la vida).

Estoy mirando como añadirlo a la wiki, pero no me coje las negritas ni nada >.<
No te coge negritas y demás porque usa otro formato, creo que había por ahí una guía de estilo.

Otra cosa, si lo que quieres es saber la estructura completa del bmp con detalles y demás te recomiendo http://www.wotsit.org/ que es una página que se dedica justamente a recopilar esto. Yo saqué la información de ahí en su día. Lo de que use BGR creo que era así, pero no estoy seguro. También es curioso que los píxels se leen de abajo a arriba, es decir, que la fila 0 es la inferior.

Y por ultimo, por si te sirve, te adjunto una clase que hice en su día para leer y manipular bmp (sólo 8 y 24 bits, B&N y color) por si te sirve de ayuda para la estructura (mira el método LoadFromFile).

Saludos.
Curradisimo hilo amchacon !
Genial, desconocía esto. Sólo un apunte:
Ahora bien, las unidades de información no usan bits sino Bytes que son asociaciones de 8 bits. Cada bit tiene 2 posibles valores, luego cada Byte tiene 16 valores distintos.

1 byte = 8 bits, 8 bits = 2^8 valores = 256 valores.
Hoy he aprendido algo nuevo, gracias.
9 respuestas