30 julio 2009

Codificación RLE para una imagen binaria en MATLAB

La codificacion RLE (Run Length Encoding) se aplica a cadenas de caracteres en las cuales existe una secuencia de datos. En este caso tenemos una imagen binaria, que es resultado de aplicar la extracción de bits a una imagen en escala de grises, como se pretende extraer solo un bit en especifico de la imagen, pues el resultado es una imagen binaria, en la cual se tienen valores de 0 o 1 dependiendo del valor del pixel. La imagen será del mismo tamaño de la imagen original puesto que es una operación de pixel por pixel.

Para visualizar de mejor manera lo que se intenta hacer aquí es menester mostrar un ejemplo. La imagen es una matriz de 2D de MxN, y tendremos para una imagen de 8x8 una matriz como la siguiente:

 
Bit Extraction Example

De lo anterior se desprende:

a) Aquí podemos observar la imagen de 8x8 original, en la cual cada valor de la matriz representa un pixel de 8 bits, o sea valores de 0-255.

b) En esta imagen se representa cada valor en su equivalente binario, con el propósito de visualizar el valor en bits de cada pixel.

c) El ultimo ejemplo de estas tres imágenes muestra el valor extraído de cada pixel para el bit mas significativo (MSB), o sea el bit 8.

La matriz que nos interesa es la matriz contenida en c). Para poder codificarla tenemos que tener una cadena de valores en los cuales existan secuencias de valores repetidos. En este caso son solo 0 y 1, y dado a que es una matriz 2D, tenemos que redimensionarla a 1D, y quedaría como se muestra a continuación:

 

Matiz 1D de bits extraídos

Tenemos una secuencia de valores que se representa en 16 caracteres, y debido a que sabemos que tendremos una secuencia de ceros y unos es importante notar el primer número y después de ahí solo se irán alternando.

Necesitamos establecer una manera de poder decodificar nuestra cadena de caracteres, y reconstruir la imagen original, necesitamos saber un par de datos para regresar a nuestra imagen original. Como se decía en el párrafo anterior es necesario saber con que valor se empieza la secuencia de caracteres, también es necesario saber el tamaño de la imagen original, para que al reconstruir la secuencia unidimensional la podamos regresar a 2D de la misma manera que la original.

Así que el encabezado nos quedará mas o menos de la siguiente manera: Fb M N . . . Secuencia . . .

En donde Fb es el primer caracter, M y N es el tamaño de la imagen original y Secuencia, como su nombre lo indica es la cadena de valores que vamos a almacenar iniciando con Fb y alternando hasta terminar. El ejemplo anterior nos quedaría como a continuación:

1 8 8 1 1 1 4 1 3 1 1 1 1 1

Ahora si, despues de tanto rollo, aqui esta el código en MATLAB para hacer esto.

a = imread('c:\matlab7\work\lena.pgm');
[cols rows] = size(a);
b = BitExtraction(a,8,1,1);
figure(1); imshow(a);
figure(2); imshow(uint8(b));
myEncodedImageB = EncodeRLEimage(b);

Este es el código de la función para extraer bits de la imagen:

function x = BitExtraction(myImagen, B, n ,L)

myImagenNueva = myImagen;
[rows cols] = size(myImagen);

for i = 1 : rows
    for j = 1 : cols
        u = double(myImagen(i,j));
        iEne = floor(u/2^(B-n));
        iEneMenosUno = floor(u/2^(B-(n-1)));
       BitExtraido = iEne - (2*iEneMenosUno);
       if BitExtraido == 1
           BitExtraido = L;
       else
           BitExtraido = 0;
       end
       myImagenNueva(i,j) = BitExtraido;
    end
end
x = myImagenNueva;

Este es la función encargada de codificar la imagen.

function eImg = EncodeRLEimage(myImage)
    encoded = [];
    [cols rows] = size(myImage);
    img1D = double(reshape(myImage,1,[]));
    SizeOf1D = cols*rows;
    counter = 0;
    encoded = [img1D(1)];
    for i =1:SizeOf1D-1
        if img1D(i)==img1D(i+1)
            counter=counter+1;
        else
            encoded = [encoded counter];
            counter = 1;
        end
    end

    if counter ~= 1
    encoded = [encoded counter+1];
    end

    eImg = encoded;

¿Sirve de algo?

28 julio 2009

¿Qué es compresión de Imágenes?

Antes de terminar el compresor (que en estos momentos creo que no va a servir mas que de práctica, je je je, bueno, de todos modos no pensaba desbancar al JPG, todavía), quiero explicar un poco que es la compresión de imágenes. Voy a empezar por poner un par de definiciones:


"La compresión de imágenes aborda el problema de reducir la cantidad de datos para representar una imagen digital. La compresión se logra removiendo una o más de las tres posibles redundancias básicas. (a)Redundancia de código: cuando se usan códigos de palabra menos óptimos (de menor longitud). (b)Redundancia interpixelaria: Que resulta de la correlación entre pixeles de una imagen. (c)Redundancia psicovisual: La cual se da debido a los datos que el sistema de visión humano ignora"1

Según Wikipedia:
"Compresión de imágenes es la aplicación de la compresión de datos en imágenes digitales. En efecto, el objetivo es reducir redundancias en la imagen con el objetivo de transmitirla o almacenarla en una manera eficiente. La compresión puede ser con pérdidas (lossy), o sin pérdidas (lossless). La compresión con pérdidas que produce diferencias imperceptibles se llama también visualmente sin pérdidas (visual lossless)."2

Entonces podemos decir que se trata de reducir el número de bits con necesarios para representar una imagen. Y hay de dos tipos (que pueden ser tres, y no es el chiste del gato). Con pérdidas, sin pérdidas y visualmente sin pérdidas. En el ejemplo de compresor que estoy tratando de hacer, es un compresor con pérdidas, de una imagen en escala de grises de 8 bits.

Pero bueno, ¿cómo le hacemos para saber si el compresor que estamos haciendo vale la pena? Pues fácil, hacemos un montón de pruebas, observamos las imágenes resultantes y la que no se vea tan peor pues decimos que es nuestra imagen codificada usando un compresor con pérdidas. También lo podemos hacer de la manera fancy, usamos PSNR o MSE o cualquier otra medida de error matemática para ver que tanto se distorsiona en referencia con la imagen original.


  1. Digital Image Processing 2nd Edition (DIP/2e)
    by Gonzalez and Woods
    © 2002. Prentice Hall
  2. Image Compression
    From Wikipedia, the free encyclopedia. Extracted July 28th, 2009

27 julio 2009

Update del Compresor que estoy haciendo

  • Ya tengo el algoritmo para hacer la extracción de Bits.
  • Ya tengo el código para codificar la imagen binaria en RLE (gracias JMG, ya lo tenía arrinconado)
  • Ya tengo el código para decodificar la imagen codificada con lo anterior

Ahora solo me falta hacer pruebas suficientes para llegar a una conclusión.

Lo voy a terminar...

... algún día.

16 julio 2009

Idea para un compresor de imágenes con pérdidas usando extracción de bits y codificación RLE a una imagen PGM

Tengo una idea para hacer un compresor de imágenes PGM (por si se preguntan, no, no tengo fijación alguna con este tipo de imágenes solo que es sencillo, ¡gulp!, trabajar con ellas) con pérdidas usando la extracción de bits (medio explicada aquí) y codificación RLE. La idea principal viene de el hecho de que al aplicar un algoritmo extracción de bits a una imagen tenemos un arreglo binario como resultado, tendremos 1 arreglo 2D de ceros y unos por cada bit extraído, es decir que para una imagen de 8-bits, tendremos 8 arreglos de binarios. De esto podemos observar que cada imagen resultante contiene información de la imagen, y se puede observar una degradación empezando del bit más significativo hacia abajo. Se pueden emplear un par de estas imágenes para codificarlas usando un algoritmo de RLE aprovechando que tendremos secuencias de unos y ceros; luego al recuperarlas y aplicarles algún tipo de técnica de Diethering, para mejorar la calidad de la imagen resultante, claro, con pérdida de información con respecto a la original.

A continuación listo los pasos que creo que son necesarios para este algoritmo:

  • Aplicar la extracción de bits a la imagen. Resultado: 8 imágenes (1 por bit en este caso)
  • Seleccionar las imágenes que serán empleadas para la codificación RLE. Resultado: conjunto de imágenes a comprimir.
  • Aplicar RLE a un cada una de las imágenes seleccionadas en el paso anterior. Resultado: n número de conjuntos de datos (1 por imagen). El total de datos obtenidos aquí nos dará como resultado una compresión.
  • Para descomprimir la imagen, aplicamos RLE inversa a los conjuntos de datos. Resultado: n número de imágenes binarias.
  • Se combinan las imágenes obtenidas en el paso anterior (esto es posible asignando cada bit y reconstruyendo la imagen de 8bits). Resultado: Imagen de 8bits con pérdida de información.
  • A la imagen resultante le aplicamos algún tipo de Diethering para mejorar la calidad. Resultado imagen codificada y decodificada con pérdidas.

No se hasta que punto sea posible obtener una buena imagen como resultado, o que tan buena compresión se pueda lograr para mantener un balance entre calidad de imagen y compresión.

Ya pondré los resultados en un post en cuanto tenga algo que valga la pena. :)

This is I

Blog dedicado a escribir sobre Sistemas Embebidos y el Internet de las Cosas o IoT que le llaman.