Mostrando entradas con la etiqueta Tratamiento Imagenes. Mostrar todas las entradas
Mostrando entradas con la etiqueta Tratamiento Imagenes. Mostrar todas las entradas

sábado, 16 de febrero de 2008

Esteganografia en Imagenes (LSB)

Este es un un trabajo que presente en la universidad el 2004 para el curso de Algebra Universal, y quiero postearlo por aqui para que no se pierda en el olvido.

Es una aplicacion de esteganografia que permite ocultar un texto ascii o inclusive un archivo binario cualquiera dentro de una imagen BMP de 24 bits.

Esteganos: Oculto, Grafia: Escrito
La esteganografía tiene como objeto de estudio las técnicas que permitan ocultar información detrás de otros datos; de tal forma que al ser "mezclados" sean visibles solo los datos de soporte y nuestra información confidencial pase desapercibida ante los ojos de cualquier observador.

Ej.
Otro ejemplo.

La iglesia mas antigua, puso el rumor ultimo.

...si extraemos la primera letra de cada palabra obtenermos:
La iglesia mas antiguaa, puso el rumor ultimo. = Lima peru.

Este es un ejemplo muy sencillo en texto, ya se les podra ocurrir miles de ideas distintas para ocultar sobre texto, pero... como ocultar sobre una imagen?

La primera alternativa para ocultar un mensaje (bits) sobre un BMP de 24 bits es aprovechar su estructura simar al siguiente grafico. solo debemos ocultar nuestros datos justo despues de los metadatos (primeros 54 bytes) y modificar el campo offset (campo que guarda la distancia entre los metadatos y los pixeles) de tal manera que podamos hacer espacio para todo lo que queremos esconder.
Esta alternativa si bien es cierto es muy sencilla de implementar tiene el defecto de que la imagen obtenida sera considerablemente grande, seria extranho tener una imagen de un icono (10x10) que nos ocupe 10 Mb no?

Otra alternativa -desde mi parecer mucho mejor- es esconder lo que queremos esconder en los LSB de cada componente de un pixel.

En espanhol:

Cada pixel, en un archivo BMP (de 24 bits), esta representado por 3 bytes conteniendo la intensidad de color para ROJO, VERDE y AZUL (RGB: red, green, blue). Entonces combinando valores en esas posiciones podemos obtener los = (16777216) colores que puede mostrar un pixel, habitualmente se dice 16 millones de colores, pero son un poquito mas.

Bueno entonces... cada byte contiene un valor entre 0 y 255 (en binario 00000000 y 11111111), estos bytes igual que en el sistema decimal conforme sus cifras esten mas a la izquierda tendran mas valor (peso) por citar un ejemplo:

5768, si cambiamos la primera cifra (la mas significativa) a 3 nos queda 3768, la diferencia es notable. Pero si cambiamos la ultima cifra (la menos significativa) por ejemplo a un 2 nos queda 5762, la diferencia es relativamente minima.

Con esto quiero decir que podemos modificar los LSB (less significant bits, o cifras menos significativas) sin producir mayor alteracion.

Un caso:

Si observamos estos dos pixels, tan solo se le ha cambiado una unidad a cada componente R, G, B, y la variacion de color ha sido minima. Al ojo humano son practicamente el mismo color.


Con esto hemos logrado sembrar 3 bits que originalmente eran 101 ahora hemos sembrado 010, eso significa que por cada pixel podemos almacenar 3 bit sin producir un cambio aparente en el pixel.

Si repetimos este paso, recorriendo los pixels de la imagen, podemos ir sembrando (ocultando) los bits que querramos dentro de nuetra imagen. En cada pixel podremos poner 3 bits es decir necesitaremos masomenos 8 pixels para poner 3 bytes (un byte tiene 8 bits :P).



Como se puede ver no es muy dificil


Esta es una imagen que contiene un mensaje, si logran recuperarlo lo comentan :P



La imagen de bart con el mensaje la pueden descargar aqui.
La aplicacion ejecutable la pueden descargar aqui.
El codigo fuente para vb 6, lo pueden descargar aqui.
Un instalador de la aplicacion lo pueden descargar de aqui.


y si no tienen el winrar lo pueden descargar de aqui


Saludos.


jueves, 14 de febrero de 2008

Mujer afgana identificada por su iris

Sharbat Gula, fotografiada en 1984 a los 12 años en un refugio en Pakistán por el fotógrafo de la National Geographic Steve McCurry, y localizada 18 años después en una remota parte de Afganistán donde fue nuevamente fotografiada por McCurry, es mencionada por la National Geographic en su revista y en su website.

John Daugman todo un ícono en el procesamiento y reconocimiento del iris humano, calculó el IrisCode de ambos ojos en la fotografía de 1984. Un sección procesada de la fotografía de 1984 se muestra aquí. La circunferencia muestra la automática localización del iris y sus bordes, el descarte de ciertas reflexiones especulares del ojo y la representación del IrisCode. Luego calculó el IrisCods de ambos ojos fotografiados en 2002. La imágenes procesadas pueden ser vistas aquí, para el ojo izquierdo y derecho.

Aún lo más interesante surge a continuación. Cuando se obtuvo la distancia de Hamming de los ojos izquierdo y derecho(los cuales en todo humano son completamente diferentes), se obtuvo medidas muy similares, que como el mismo Daugman manifiesta es estadísticamente casi imposible para diferentes iris se muestren medidas tan poco distintas. La estadística matemática de que tal evento pase es de seis millones a uno para el ojo derecho y 10 elevado a 15 para el ojo izquierdo. NatGeo aceptó nuevamente publicar esta conclusión.

Como se ve el IrisCode tuvo todo un reto, y salió con algunas heridas pero victorioso al fin.

Fuente: http://www.seccperu.org/?q=node/608

miércoles, 6 de febrero de 2008

Destripando un BMP (24 bits)

Existe una gran variedad de formatos de imágenes tal como BMP, TIFF, GIF, PNG, JPEG, etc. El más sencillo de todos es el formato BMP de 24 bits.

Características:
No es comprimido (Una desventaja con respecto a espacio pero ventaja por su simplicidad)
Por no ser comprimido es de alta calidad
Se puede ver en cualquier visor de imágenes por ser el mas básico.

Veamos que hay dentro...



Los Primeros 54 Bytes contienen los metadatos de nuestra imagen y su estructura es la siguiente:

2 bytes - contienen siempre 'BM', para poder identificar que es un bmp
4 bytes - tamaño del archivo (en bytes)
4 bytes - Reservados, contienen ceros (reservados para usos futuros)
4 bytes - offset, distancia entre cabecera y píxels (no lo usaremos)
4 bytes - Tamaño de Metadatos (tamaño de esta estructura = 40)
4 bytes - Ancho (numero de píxeles horizontales)
4 bytes - Alto (numero de pixeles verticales)
2 bytes - Numero de planos de color (No lo usaremos, valdrá 1)
2 bytes - Profundidad de color (debe ser 24 para nuestro caso)
4 bytes - Tipo de compresión (valdrá 0, ya que es descomprimido)
4 bytes - Tamaño de la estructura Imagen
4 bytes - Píxeles por metro horizontal (No lo usaremos)
4 bytes - Píxeles por metro vertical (No lo usaremos)
4 bytes - Cantidad de colores usados (No lo usaremos)
4 bytes - Cantidad de colores importantes (Tampoco usaremos)


Suman 54 bytes, y son los primeros 54 bytes que debemos leer de nuestro archivo.
Podemos leerlo uno a uno pero lo mejor es crear una estructura y leerlos todo de un solo paso.

Ejemplo de Estuctura para Visual Basic:


Public Type tipoMetadatosBMP
       B As Byte
       M As Byte
       tamaño As Long
       reservado As Long
       offset As Long
       tamañoMetadatosB
       ancho As Long
       alto As Long
       planos As Integer
       profundidadColor As Integer
       tipoCompresion As Long
       tamañoEstructuraImagen As Long
       pixelsPorMetroH As Long
       pixelsPorMetroV As Long
       cantidadColoresUsados As Long
       cantidadColoresImportantes As Long
End Type


Ejemplo de estructura para C++:

struct tipoMetadatosBMP
{     char bm[2];
      int tamano;
      int reservado;
      int offset;
      int tamanoMetadatos;
      int alto;
      int ancho;
      short numeroPlanos;
      short profundidadColor;
      int tipoCompresion;
      int tamanoEstructura;
      int pxmh;
      int pxmv;
      int coloresUsados;
      int coloresImportantes;

} ;

No debe variar mucho de lenguaje en lenguaje.
Inmediatamente después de Nuestra cabecera (metadatos), vienen los píxeles (si, esos cuadraditos de colores que conforman nuestra imagen)

Cada Píxel se almacena en 24 bits (3 bytes)
De los 24 bits = 3 bytes, se utilizan 1 byte por cada color básico es decir...
Un byte parta R, Un byte para G, Un byte para B

NO, no son los colores rastas :P, son los colores básicos para el BMP, cada color puede ser obtenido mediante una combinacion de R (red), G (green) y B (blue).

Considerando que un byte puede almacenar 256 valores diferentes, tenemos:
256 (R) x 256 (G) x 256 colores (B) = 16777216 Colores RGB

Por alguna razón que desconozco al momento de diseñar el formato los ordenaron BGR y no RGB es decir primero el byte para azul, luego el byte para verde y luego el byte para verde.

Importante!!! :
Además despues de cada fila de pixels (barrido horizontal), si el ancho de
la imagen no es multiplo de 4, se rellena la linea con [ancho mod 4] bytes que
contienen 0.
Por ejemplo si la imagen tuviera 42 pixeles de ancho, se
rellenaria 2 bytes (el resto de 42/4) al final de cada fila de
pixeles.
Ahora ya que al leer los metadatos obtuvimos la resolución (Sí, la RESOLUCIÓN, o sea los píxeles horizontales x verticales)

Recuerdas?
...
ancho As Long
alto As Long
...

ahora podemos leer cada uno de los píxeles de la siguiente manera:

Codigo de ejemplo para leer una imagen en Visual Basic.


Dim meta As tipoMetadatosBMP
Dim i As Long, j As Long, k as Integer, resto as Integer
Dim pixelAux As tipoPixel
Dim relleno as Byte

Open nombreBMP For Binary As #1
Get #1, , meta ' Leemos los metadatos
resto = meta.ancho mod 4 'calculamos el resto

For i = 1 To meta.alto 'Recorremos las filas
    For j = 1 To meta.ancho 'Recorremos las columnas
        Get #1, , pixelAux 'leemos el pixel ...
    Next
    For k = 1 To resto 'leemos los pixels de relleno
        Get #1, , relleno
    Next
Next

Close #1

Asumimos que tenemos declarado el tipo:


Public Type tipoPixel
    b As Byte ' Azul
    g As Byte ' verde
    r As Byte ' rojo
End Type

Codigo de ejemplo para leer una imagen en C++

archivo.Open("imagen.bmp",CFile::modeCreateCFile::modeNoTruncateCFile::modeRead);

//cargamos los metadatos -----------------------------------

archivo.Read(&bm,2);
archivo.Read(&tamano,sizeof(tamano));
archivo.Read(&reservado,sizeof(reservado));
archivo.Read(&offset,sizeof(offset));
archivo.Read(&tamanoMetadatos,sizeof(tamanoMetadatos));
archivo.Read(&ancho,sizeof(ancho));
archivo.Read(&alto,sizeof(alto));
archivo.Read(&numeroPlanos,sizeof(numeroPlanos));
archivo.Read(&profundidadColor,sizeof(profundidadColor));
archivo.Read(&tipoCompresion,sizeof(tipoCompresion));
archivo.Read(&tamanoEstructura,sizeof(tamanoEstructura));
archivo.Read(&pxmh,sizeof(pxmh));
archivo.Read(&pxmv,sizeof(pxmv));
archivo.Read(&coloresUsados,sizeof(coloresUsados));
archivo.Read(&coloresImportantes,sizeof(coloresImportantes));
//----------------------------------------------------------


//Luego leemos los pixeles ---------------------------------

int resto = metadata.ancho % 4;
for (i=1;i<=metadata.alto;i++)

{    for (j=1;j<=metadata.ancho;j++)
     {    archivo.Read(&varB,1); //leemos el byte azul en la variable varB
          archivo.Read(&varG,1); //leemos el byte azul en la variable varB
          archivo.Read(&varR,1); //leemos el byte azul en la variable varB
     }
     for (k=1;k<=resto;k++)
          archivo.Read(&var,1); //leemos los pixels de relleno
}
archivo.Close(); //----------------------------------------------------------

El código es muy similar para cualquier otro lenguaje.
Espero les haya servido.
Comentarios y sugerencias a: carlosagreda-at-gmail.com