Compresores Basado en La Transformada Wavelet

16
1 PRÁCTICAS TXÓN. DATOS MULTIMEDIA COMPRESORES BASADOS EN LA TRANSFORMADA WAVELET 1. Introducción En esta práctica estudiaremos tanto la Transformada Discreta Wavelet (DWT) como los principales compresores basados en esta transformada, entre los que se encuentra JPEG 2000, la siguiente versión del famoso estándar para compresión de imágenes de tono continuo. En la primera parte de la práctica presentaremos e implementaremos la transformada Wavelet orientada a imagen (es decir, bi-dimensional). Para este estudio e implementación nuevamente se proporciona un código fuente incompleto escrito en ANSI C++, que se deberá analizar y completar. En la segunda parte de la práctica introduciremos los compresores basados en Wavelet: JPEG 2000 y LTW, y a partir de unos ejecutables que implementan estos algoritmos, realizaremos una comparación de ambos en términos de eficiencia en compresión y en tiempo de ejecución. 2. La Transformada Wavelet La Transformada Wavelet, más conocida por su nombre en inglés, Discrete Wavelet Transform (DWT), es una herramienta matemática de reciente desarrollo que permite descomponer una señal no sólo en componentes frecuenciales sino también espaciales. Si la comparamos con la DCT (que está basada en las conocidas teorías de Fourier), observamos que los coeficientes resultantes de aplicar la DCT a un conjunto de muestras nos indican qué componentes frecuenciales componen esa señal, pero no tienen ningún tipo de información sobre su situación en la señal original, sino que se refiere al global de las muestras. Por el contrario, los coeficientes de la DWT nos sitúan distintos componentes frecuenciales en posiciones espaciales, mediante un análisis por subbandas. En general, los más modernos compresores de imagen han decidido sustituir la DCT por la DWT para la fase de la transformada por diversas ventajas, entre ellas: (1) La DWT es capaz de compactar la energía en menos coeficientes que la DCT. Uno de los objetivos de aplicar una transformada matemática a los píxels antes de su almacenamiento/transmisión es ser capaz de concentrar gran parte de la información sobre la representación de la imagen en unos cuantos componentes, de manera que el resto de componentes sean cero, o prácticamente cero. Después de aplicar la DCT a un bloque de 8x8, la mayor parte de la energía (valores más altos) está en la componente de continua (DC) y los coeficientes que la rodean. En la DWT esta concentración de energía será aun más pronunciada, quedando la mayor parte de la energía en las subbandas de menor frecuencia.

description

wavelet

Transcript of Compresores Basado en La Transformada Wavelet

Page 1: Compresores Basado en La Transformada Wavelet

1

PRÁCTICAS TXÓN. DATOS MULTIMEDIA

COMPRESORES BASADOS EN LA TRANSFORMADA WAVELET

1. Introducción

En esta práctica estudiaremos tanto la Transformada Discreta Wavelet (DWT) como los principales compresores basados en esta transformada, entre los que se encuentra JPEG 2000, la siguiente versión del famoso estándar para compresión de imágenes de tono continuo. En la primera parte de la práctica presentaremos e implementaremos la transformada Wavelet orientada a imagen (es decir, bi-dimensional). Para este estudio e implementación nuevamente se proporciona un código fuente incompleto escrito en ANSI C++, que se deberá analizar y completar. En la segunda parte de la práctica introduciremos los compresores basados en Wavelet: JPEG 2000 y LTW, y a partir de unos ejecutables que implementan estos algoritmos, realizaremos una comparación de ambos en términos de eficiencia en compresión y en tiempo de ejecución. 2. La Transformada Wavelet

La Transformada Wavelet, más conocida por su nombre en inglés, Discrete Wavelet Transform (DWT), es una herramienta matemática de reciente desarrollo que permite descomponer una señal no sólo en componentes frecuenciales sino también espaciales. Si la comparamos con la DCT (que está basada en las conocidas teorías de Fourier), observamos que los coeficientes resultantes de aplicar la DCT a un conjunto de muestras nos indican qué componentes frecuenciales componen esa señal, pero no tienen ningún tipo de información sobre su situación en la señal original, sino que se refiere al global de las muestras. Por el contrario, los coeficientes de la DWT nos sitúan distintos componentes frecuenciales en posiciones espaciales, mediante un análisis por subbandas. En general, los más modernos compresores de imagen han decidido sustituir la DCT por la DWT para la fase de la transformada por diversas ventajas, entre ellas:

(1) La DWT es capaz de compactar la energía en menos coeficientes que la DCT. Uno de los objetivos de aplicar una transformada matemática a los píxels antes de su almacenamiento/transmisión es ser capaz de concentrar gran parte de la información sobre la representación de la imagen en unos cuantos componentes, de manera que el resto de componentes sean cero, o prácticamente cero. Después de aplicar la DCT a un bloque de 8x8, la mayor parte de la energía (valores más altos) está en la componente de continua (DC) y los coeficientes que la rodean. En la DWT esta concentración de energía será aun más pronunciada, quedando la mayor parte de la energía en las subbandas de menor frecuencia.

Page 2: Compresores Basado en La Transformada Wavelet

2

(2) No es necesario dividir en bloques la imagen para aplicar la DWT, se puede usar sobre la imagen completa. Como sabemos, en la DCT, sin embargo, sí es necesario aplicar la DCT en pequeños bloques de 8x8, ya que su aplicación a la imagen completa sería excesivamente costosa. Cuando el índice de compresión aplicado es alto, esta aplicación de la DCT y posterior cuantización de la imagen en bloques puede dar lugar al típico efecto de bloque, en el que los bloques resultan perfectamente visibles (ver figura), degradando mucho la calidad perceptual de la imagen. Como ya hemos comentado, en la DWT este efecto no sucede, porque se aplica a toda la imagen.

(3) Una cualidad interesante de la DWT es que permite un análisis en multiresolución de las imágenes. Esto permitirá incluir fácilmente escalabilidad espacial en un compresor de imagen.

2.1 La transformada Wavelet 1D (1D-DWT) La teoría matemática que subyace a la DWT puede resultar ciertamente compleja, con una base para el espacio Wavelet más compleja que los cosenos a distintas frecuencias que forman la base de la DCT. En concreto, la DWT usa como base funciones de soporte finito, con propiedades oscilantes, que se escalan y se desplazan respecto a una función prototipo. Sin embargo, su implementación es bastante sencilla, basándose en un banco de filtros de análisis paso-bajo { }kh y paso-alto { }kg que descomponen una señal unidimensional en dos bandas, una de baja frecuencia y otra de alta frecuencia. Posteriormente haremos un downsampling de los coeficientes resultantes, de manera que nos quedaremos con la mitad de las muestras obtenidas al aplicar cada filtro. Para obtener las muestras originales aplicando la transformada inversa (IDWT), lo que se conoce como proceso de síntesis, bastará con hacer un upsampling de los coeficientes (poniendo “0’s” en las muestras que se eliminaron en el downsampling) y aplicar los filtros de síntesis paso-bajo { }kh~ y paso-alto { }kg~ . En la siguiente figura se esquematiza este proceso para un primer nivel de descomposición.

Page 3: Compresores Basado en La Transformada Wavelet

3

Un problema a resolver en la transformada es cómo operar con los valores próximos a los bordes, en los que no se dispone de suficientes muestras para aplicar al filtro (por ejemplo, para aplicar un filtro a la primera muestra de la fila no disponemos de valores a la izquierda de las muestras). Para poder aplicar el filtro en estos casos hay distintas alternativas, pero la que se propone es usar extensión simétrica (es decir, si el vector inicial de muestras es “abcde…”, replicamos el borde simétricamente con las muestras del propio vector de la siguiente forma: “edcbabcde…”, esta solución también se puede adoptar en el extremo final del vector). Ejercicio 1 Para entender mejor el proceso de transformada Wavelet aplicada a una señal unidimensional (esto es, un vector), vamos a realizar una implementación de esta transformada. Para la parte de la práctica en al que implementaremos la DWT, se ha definido un Workspace de Visual C++6.0 con tres proyectos distintos: 1DDWT, 2DDWT y 2DDWTn, uno por cada ejercicio. En este primer ejercicio vamos a trabajar con el proyecto 1DDWT, en el que el material necesario es simplemente un par de ficheros: “DWT.cpp” y “1DDWT.cpp” (y el DWT.h asociado). En “DWT.cpp” se tendrán que implementar las distintas versiones de la transformada Wavelet que haremos en esta práctica. Por otro lado, el fichero “1DDWT.cpp” simplemente contiene un sencillo programa que define un vector constante de 32 elementos, en concreto float Muestras[32]= {33,21,22,11,35,34,33,64,66,44,33,64,34,12,55,43, 33,21,22,11,35,34,33,64,66,44,33,64,34,12,55,43}; y llama a las funciones de transformada directa e inversa, mostrando el resultado de cada una de estas operaciones. En particular, con el filtro que usaremos en prácticas, el resultado de la transformada directa una vez implementada correctamente debe ser el siguiente vector: {29.17 17.03 30.02 38.69 63.65 41.97 35.08 42.64 32.41 17.54 30.02 38.69 63.65 41.97 35.67 41.39 -5.74 -18.58 1.42 14.55 -10.72 39.57 -39.38 -0.87 -4.00 -18.58 1.42 14.55 -10.72 39.57 -37.37 -12.27}

2 ↑

Paso-bajo

{ }kh 2 ↓

{ }kg 2 ↓

Paso-alto

S

{ }kh~

{ }kg~

S

2 ↑

Análisis Síntesis

Figura: Un nivel de descomposición wavelet de una señal, y su reconstrucción obteniendo la señal original.

Page 4: Compresores Basado en La Transformada Wavelet

4

mientras que el de la transformada inversa, lógicamente debe ser el vector original. Observa que las primeras 16 muestras de este vector corresponden a la banda de baja frecuencia (banda L, es el resultado de aplicar el filtro paso bajo), mientras que las 16 últimas muestras forman la banda de alta frecuencia (banda H, el resultado del paso alto), también denominados coeficientes wavelet. En principio podemos destacar los siguientes elementos del fichero DWT.cpp: • Para la transformada directa (DWT), vamos a usar los filtros que corresponden a la

transformada Wavelet bi-ortogonal 9/7 (B9/7), de manera que otros filtros definirían otras DWT. En concreto, los filtros de B9/7 de análisis y síntesis son los siguientes.

k Análisis paso bajo, { }kh k Análisis paso alto, { }kg

0 + 0.602949018236360 0 + 1.115087052457000 ± 1 + 0.266864118442875 ± 1 − 0.591271763114250 ± 2 − 0.078223266528990 ± 2 − 0.057543526228500 ± 3 − 0.016864118442875 ± 3 + 0.091271763114250 ± 4 + 0.026748757410810

k Síntesis paso bajo, { kh~ } k Síntesis paso alto, { }kg~ 0 + 1.115087052457000 0 + 0.602949018236360 ± 1 + 0.591271763114250 ± 1 − 0.266864118442875 ± 2 − 0.057543526228500 ± 2 − 0.078223266528990 ± 3 − 0.091271763114250 ± 3 + 0.016864118442875 ± 4 + 0.026748757410810

En el módulo DWT.cpp, los filtros de análisis se encuentran definidos en los vectores B97_AnalisisPasoBajo[] y B97_AnalisisPasoAlto[], y los de síntesis en B97_SintesisPasoBajo[] y B97_SintesisPasoAlto[]. Observa que estamos usando filtros simétricos, con lo que la posición 1 se corresponde también con la -1, la 2 con la -2, etc. (por eso en los vectores tan sólo definimos cinco elementos para los filtros de longitud nueve, y cuatro para los de longitud siete).

• La aplicación de un filtro digital sobre un vector consiste en, por cada componente

de este vector, multiplicar los taps (coeficientes del filtro) por los distintos componentes del vector y sumar el resultado. Por ejemplo, el filtro { }kg aplicado sobre una posición x de un vector { }iv , daría como resultado:

{ }3322110112233 gvgvgvgvgvgvgv xxxxxxx +++−−−−−− ++++++ Esta operación está ya implementada por la función

float PasoDeFiltrado7(float *coef,int pos, float *tap)

Page 5: Compresores Basado en La Transformada Wavelet

5

que recibe como parámetros el vector con el que operar (“coef”), la posición que filtrar, y el filtro (de longitud siete) a usar (existe una función equivalente para los filtros de longitud nueve). Para aplicar el filtrado, simplemente tendremos que utilizar esta función sobre cada una de las posiciones que compongan el vector a filtrar.

• Como ya hemos visto anteriormente, para poder operar alrededor de las posiciones del vector próximas a los extremos, es necesario aplicar una extensión simétrica de la señal. Esta operación se encuentra ya implementada en la función void ExtensionSimetrica(float *ini,float *fin). Otras funciones auxiliares interesantes son CopiaVector(…) y PonVectorACero(…), que lógicamente sirven para copiar un vector sobre otro, y poner un vector a cero, respectivamente.

Además, en esta misma unidad nos encontramos con las funciones para el cálculo de la DWT 1D directo e inverso, que se encuentran parcialmente implementadas, y hay que completarlas. En concreto, la función void Calcula1D_DWT(float *Vector, int tam)

(1) Reserva la memoria necesaria para los distintos vectores auxiliares. (2) Como el resultado de la transformada se debe dejar sobre el propio vector de

entrada, una de las primeras cosas a hacer es copiarlo sobre un vector distinto (para no perder los datos de entrada a medida que se van calculando los nuevos datos). El vector que contiene la copia es “VectorAux”, y otra de las tareas a realizar es extender los extremos simétricamente (para ello hemos usado un pequeño truco, y es que hemos definido este vector sobre otro más grande, llamado “VectorAux_Extendido”). Esta parte se ofrece ya implementada.

(3) A continuación hay que aplicar los filtros de síntesis paso alto y paso bajo a “VectorAux”, dejando el resultado en los vectores “ResultadoPasoBajo[]” y “ResultadoPasoAlto[]”. Esta parte hay que implementarla.

(4) A continuación debes implementar la aplicación del downsampling de las muestras, dejando el resultado en “ResultadoPasoBajoDownsampled[]” y “ResultadoPasoAltoDownsampled[]”. Observa que para los coeficientes de baja frecuencia debemos eliminar las muestras de las posiciones pares (0, 2, 4, etc.), mientras que para los de alta frecuencia hay que eliminar las muestras impares (posiciones 1, 3, 5, etc.).

(5) Por último se debe dejar el resultado sobre el vector de entrada, dejando los coeficientes de baja frecuencia en la parte baja del vector de entrada, y los de alta frecuencia en la parte alta del vector de entrada. Esta parte también está implementada.

En cuanto a la función void Calcula1D_IWT(float *Vector, int tam)

(1) Reserva la memoria necesaria para los distintos vectores auxiliares. (2) Separamos el vector de entrada en dos vectores, que contendrán los

coeficientes de baja frecuencia (vector “CoeficientesPasoBajoDownsampled[]”) y los coeficientes de alta frecuencia (vector “CoeficientesPasoAltoDownsampled[]”) que se calcularon en la transformada directa. Esta parte está implementada.

Page 6: Compresores Basado en La Transformada Wavelet

6

(3) A continuación tenemos que hacer un upsampling de ambos vectores, retornándolos a sus dimensiones originales, y dejando el resultado de este upsampling en los vectores “CoeficientesPasoBajo[]” y “CoeficientesPasoAlto[]”. Para hacer esta operación, en primer lugar deberemos poner estos vectores a cero (para que las posiciones no completadas sean “0’s”), y luego tendremos que realizar la asignación inversa a la que hicimos en el punto (4) de la DWT. Esta parte hay que implementarla.

(4) A continuación se realiza una extensión simétrica de los bordes de los vectores que se acaban de crear (esta parte se da hecha).

(5) En último lugar hay que aplicar los filtros de síntesis a los vectores que acabamos de construir, y sumar el resultado de la aplicación de ambos filtros, dejando el resultado de la suma en el propio vector de entrada. Para hacer esto de manera sencilla, sin necesidad de más vectores auxiliares, puedes asignar a “Vector” el resultado de aplicar un filtro, e ir sumando posteriormente el resultado de aplicar el otro filtro.

2.2 La transformada Wavelet 2D (2D-DWT) No debemos olvidar que nuestro objetivo final es usar esta nueva transformada para compresión de imagen, y por tanto que su uso final será la aplicación sobre señales bidimensionales. Partiendo de la transformada wavelet 1D, su aplicación sobre imágenes es sumamente sencilla. Simplemente se debe aplicar la transformada 1D, primero a cada una de las filas que forman la imagen, y después a cada una de las columnas (el orden también podría ser el contrario, al ser una transformada separable). La aplicación de esta 2D-DWT a una imagen dará lugar a cuatro bandas de frecuencias denominadas LL, HL, LH y HH. En la banda HL se encuentra el resultado de aplicar el filtro paso alto a las filas, y paso bajo a las columnas, mientras que en la LH tenemos el caso contrario. La banda HH es la resultante de aplicar el filtro paso alto por filas y columnas, mientras que por último, la banda LL se obtiene a partir del filtro paso bajo tanto por filas como por columnas. En la siguiente figura se observa un ejemplo de la imagen estándar “Lena”, tras aplicar esta transformada:

Page 7: Compresores Basado en La Transformada Wavelet

7

Fíjate como la subbanda LL es la que concentra más energía, y muestra una versión reescalada de la imagen. Para obtener la imagen original, a partir de estas cuatro subbandas, simplemente bastaría con aplicar la transformada wavelet inversa unidimensional (1D-IWT), por filas y por columnas. Ejercicio 2 En este segundo ejercicio vamos a implementar la 2D-DWT a partir de la transformada 1D desarrollada durante el primer ejercicio. En este caso usaremos el proyecto 2DDWT de nuestro Workspace y la imagen de prueba “lena512.raw”. Esta imagen está almacenada en formato crudo, y puede ser vista con algún visor de imágenes como IrfanView (http://www.irfanview.com/), indicando al abrirla que las dimensiones de la imagen son de 512x512, y que está codificada con 8 BPP (escala de grises). En el nuevo proyecto se ha incorporado el módulo “ImagenES.cpp” para realizar la carga y escritura de imágenes desde disco, y el fichero “2DDWT.cpp”, que contiene el programa principal, que realiza en primer lugar una carga de la imagen de Lena, llama a la función para el cálculo de la 2D-DWT sobre esta imagen, seguidamente guarda el resultado de esta transformada en el fichero “lenaDWT.raw”, para a continuación calcular la 2D-IWT, finalmente guardando el resultado de esta transformada inversa en el fichero “lenaRec.raw”. En este ejercicio simplemente debemos implementar las funciones para el cálculo de la 2D-DWT directa e inversa, que se encuentran en el fichero DWT.cpp. • La función void Calcula2D_DWT(float **Imagen, int ancho, int alto)

debe implementar la transformada directa. En la primera variable se recibe la imagen a transformar, cuyas dimensiones vienen dadas en las dos siguientes variables. El resultado de la transformada se debe dejar en esta misma imagen. Observa que a la fila “i” de la imagen de entrada se puede acceder como el vector

LH HH

HL LL

Page 8: Compresores Basado en La Transformada Wavelet

8

“Imagen[i]”, mientras que un píxel (x,y) de la imagen es accesible como “Imagen[y][x]”. En esta función, en primer lugar calcularemos la 1D DWT de todas las filas, y posteriormente de las columnas. Debido a la organización por filas de las imágenes en memoria, el cálculo de la 1D-DWT sobre filas se puede hacer directo, pero para el cálculo de las columnas es necesario antes realizar una copia de cada columna sobre un vector auxiliar (“Vector”, ya creado en la propia función), y realizar la copia inversa, del vector a las columnas, después del cálculo. Para hacer estas copias se proporcionan las rutinas auxiliares “void PasaColumnaAVector(…)” y “void PasaVectorAColumna(…)”, en las que se indican por parámetro cuál es la imagen, qué columna se quiere copia (NCol) y sobre qué vector se quiere copiar (además hay que pasar el alto de la imagen). El resultado de la imagen en “lenaDWT.raw” después de implementar correctamente esta transformada debe ser similar a la siguiente figura:

• En void Calcula2D_IWT(float **Imagen, int ancho, int alto) implementaremos la transformada inversa. Los parámetros son exactamente los mismos que en la función directa, y su implementación es exactamente igual, cambiando la llamada a las funciones unidimensionales DWT por las equivalentes IWT.

Una vez se implementen correctamente estas dos funciones, el fichero “lenaRec.raw” deberá tener una versión de “Lena” visualmente idéntica a la original.

2.3 La transformada Wavelet 2D multinivel (2D-DWTn) Podemos observar en el punto anterior que después de calcular la 2D-DWT sobre una imagen la mayor parte de la energía se encuentra centrada en una única subbanda, la de baja frecuencia (LL). Esto se debe a que las imágenes naturales se encuentran formadas sobre todo por información de baja frecuencia.

Page 9: Compresores Basado en La Transformada Wavelet

9

Para concentrar aun más la energía, podemos repetir exactamente el mismo proceso de transformada 2D, centrándonos ahora exclusivamente en esta subbanda LL. De manera que un segundo nivel de transformada daría el siguiente resultado:

En este caso, hemos aplicado la 2D-DWT con dos niveles de transformada, dando lugar a coeficientes wavelet de dos niveles distintos (HL1 y HL2, LH1 y LH2, HH1 y HH2), y un único nivel de subbanda de baja frecuencia (LL2). Decimos que la DWT facilita la multiresolución de manera natural porque vamos teniendo distintas versiones de la imagen original, a distintos tamaños, a medida que vamos calculando más niveles de transformada. Podemos ver como en la banda de baja frecuencia de la figura tenemos nuevamente una versión reducida de la imagen original. Además, esta banda contiene la mayor parte de la energía, con lo que podríamos repetir el proceso de transformada 2D centrándonos en las distintas subbandas de baja frecuencia hasta que consideremos que hemos concentrado suficientemente la energía en una única banda de dimensiones reducidas, facilitando esto el posterior proceso de compresión. Ejercicio 3 En este ejercicio vamos a implementar la 2D-DWT multinivel a partir de la transformada 2D desarrollada en el anterior ejercicio. Ahora usaremos el proyecto 2DDWTn de nuestro Workspace, en el que hemos añadido “2DDWTn.cpp”, que contiene un programa principal similar al del ejercicio 2, pero que en este caso llama a las funciones de transformada multinivel del módulo “DWT.cpp” (usando un nivel de descomposición por defecto de 3). Nuevamente implementaremos las funciones directa e inversa sobre DWT.cpp: • En void Calcula2D_DWT_Multinivel(float **Imagen, int ancho, int alto, int

nivel) vamos a implementar la transformada directa. A los parámetros de la 2D-DWT anterior le hemos añadido un último parámetro indicando el nivel de descomposición deseado (esto es, el número de veces que vamos a aplicar la 2D-DWT).

LH1 HH1

HL1 LH2 HH2

HL2 LL2

Page 10: Compresores Basado en La Transformada Wavelet

10

La implementación de esta función a partir de la del ejercicio 2 es muy sencilla, y simplemente debemos calcular la transformada bidimensional un número de veces igual a nivel, reduciendo las dimensiones de la imagen (variables “ancho” y “alto”) a la mitad en cada uno de los niveles. El resultado de la imagen después de tres niveles de descomposición (el valor usado por defecto) deberá ser similar a la siguiente figura:

• La transformada inversa multinivel se debe implementar en void

Calcula2D_IWT_Multinivel(float **Imagen, int ancho, int alto, int nivel). En este caso hay que seguir el mismo recorrido que en la función directa, pero en camino inverso. Es decir, se parte de la imagen transformada, y a partir de unas dimensiones de (ancho/2nivel−1) y (alto/2nivel−1), debemos ir calculando la transformada 2D inversa y duplicando el ancho y el alto, tantas veces como nivel de transformada se aplicó en la directa. Nuevamente podremos comprobar la corrección de los procesos directos e inversos observando la calidad de la imagen resultante “lenaRec.raw”.

3. Compresores de imagen basados en la transformada Wavelet

3.1 JPEG 2000 Una de las razones por la que la transformada Wavelet cobra tanto interés en compresión de imagen es que el nuevo estándar que sustituye a JPEG, llamado JPEG 2000, utiliza la DWT en vez de la DCT. La estructura básica del nuevo estándar es similar a la de JPEG y el resto de codificadores basados en transformada. Esta estructura es la siguiente:

(1) Si la imagen a comprimir es en color, en primer lugar se hace una conversión del espacio de colores de la imagen sin comprimir (normalmente RGB) a un espacio YCbCr 4:2:0, en el que la luminancia se codifica completa, y para las crominancias (diferencias de colores respecto a la luminancia) se realiza un downsampling a la mitad.

Page 11: Compresores Basado en La Transformada Wavelet

11

(2) Posteriormente se aplica la transformada matemática, en este caso la DWT, en su versión bi-ortogonal 9/7 (la implementada en el ejercicio 1). Ya no se realiza una división por bloques de cada uno de los planos a comprimir, sino que la transformada se aplica a la imagen entera (o, en el caso de imágenes a color, a cada uno de los planos de luminancia y crominancia que la componen)

(3) Se hace una cuantización del resultado de calcular la DWT, por la que se pasa de coeficientes flotantes a coeficientes enteros.

(4) Se divide la imagen en bloques de un tamaño considerable, normalmente 64x64, y cada uno de estos bloques se codifica separadamente usando el algoritmo EBCOT. Este codificador realiza una compresión del bloque por planos de bit, es decir, empieza comprimiendo el bit más significativo de todos los coeficientes, luego continúa por el siguiente bit, etc., hasta llegar al plano de bits menos significativo. Cada plano de bits lo codifica en tres pasadas, de manera que intenta identificar de forma eficiente cuando un coeficiente tiene el primer bit significativo distinto de cero. Fíjate que aunque en esta fase volvemos a realizar una compresión por bloques, el efecto de bloque típico de JPEG no aparecerá, ya que la transformada y la cuantización se han aplicado a toda la imagen, sin divisiones previas.

(5) La última etapa de JPEG 2000 es una reorganización de los distintos bitstream obtenidos de codificar cada uno de los bloques con EBCOT. Esta ultima etapa es importante porque nos permite obtener el tipo de escalabilidad deseado, de forma que si queremos escalabilidad espacial, simplemente tendremos que codificar en primer lugar la subbanda LL (que es una versión reducida de la imagen), y luego el resto de subbandas wavelet, de mayor a menor nivel. Por otro lado, si se quiere una escalabilidad en calidad (o SNR), tendremos que almacenar la imagen por planos de bit, del plano más significativo al menos significativo. En esta fase se construye el bitstream final según el tamaño que se desea que tenga el fichero comprimido. De hecho, JPEG 2000 realiza un rate control tan preciso que se le puede indicar un tamaño de fichero y es capaz de comprimir la imagen en ese mismo tamaño. Esto lo realiza con un algoritmo de optimización basado en los multiplicadores de Lagrange. Esta característica no la tenía JPEG, en el que tan sólo se le podía indicar un nivel de compresión, sin conocer “a priori” cual sería el tamaño final al que el compresor comprimiría la imagen.

Para más información sobre JPEG 2000 y el codificador EBCOT se puede consultar el artículo “High performance scalable image compression with EBCOT” de la revista IEEE Transactions on Image Processing, Volumen 9, número 7, julio de 2000.

3.2 Lower Tree Wavelet (LTW) encoder. JPEG 2000 es un compresor muy versátil, ya que permite indicar el tipo de escalabilidad deseada y el tamaño exacto del fichero final. Sin embargo estas características adicionales lo convierten en un compresor bastante costoso computacionalmente. El LTW es un compresor basado en la transformada Wavelet que intenta mantener la eficiencia en compresión de JPEG 2000, con un coste computacional sensiblemente menor. Para esto, en primer lugar elimina la codificación por planos de bit que se realiza en JPEG 2000, evitando así las múltiples iteraciones necesarias para codificar cada

Page 12: Compresores Basado en La Transformada Wavelet

12

coeficiente Wavelet. Además no usa ningún tipo de algoritmo de optimización de Lagrange, con lo que se pierde la posibilidad de indicar un tamaño exacto de fichero. El nivel de compresión se varía por medio de un parámetro de cuantización. El compresor LTW, como otros compresores basados en Wavelets (por ejemplo, EZW y SPIHT), ordena los coeficientes en árboles. Por ejemplo, es fácil observar que un coeficiente en una subbanda de un tercer nivel, se corresponde espacialmente con 4 coeficientes del segundo nivel, y 16 coeficientes del primer nivel, tal y como se muestra en la siguiente figura, parte izquierda:

De esta forma, podemos definir la estructura de árboles que se muestra en la parte derecha de la figura. Aprovechando esta estructura de árboles, el codificador LTW comprime los coeficientes wavelet, de la siguiente forma:

(1) Se recorren las subbandas desde las de mayor nivel hasta las de primer nivel (2) Por cada coeficiente que sea cero (después de cuantización) y todos sus

descendientes en el árbol también sean cero, codificamos un símbolo “L” (con un codificador aritmético). Este símbolo ya representa todo el árbol, con lo que sus descendientes de las siguientes subbandas ya no se codificarán.

(3) Si el coeficiente es cero, pero tiene algún descendiente distinto de cero, se codifica como cero aislado, usando el símbolo “I”

(4) Si por el contrario el coeficiente no es cero, codificamos el valor del coeficiente (para ello se codifica el número de bits que tiene dicho coeficiente, y sus bits por debajo del más significativo distinto de cero).

Es importante destacar que este compresor es eficiente por el hecho de que si un coeficiente es distinto de cero en un determinado nivel, es bastante probable que sus descendientes también lo sean. Además, este compresor es escalable en resolución (se codifican antes los coeficientes de las subbandas de menor nivel), pero no lo es en calidad. Para más información sobre este codificador, se propone la lectura del artículo “Low-complexity multiresolution image compression using wavelet lower trees” de la revista

LH1 HH1

HL1 LH2 HH2

HL2 HL3

HL2

HL1

Page 13: Compresores Basado en La Transformada Wavelet

13

IEEE Transactions on Circuits and Systems for Video Technology, Volumen 16, número 11, noviembre de 2006. Ejercicio 4 En este último ejercicio vamos a comparar dos implementaciones de JPEG 2000 y LTW, en términos de índice de compresión (curva “tasa de bits/distorsión”) y en coste computacional (curva “tasa de bits/tiempo de ejecución”). En concreto vamos a emplear la implementación estándar de JPEG 2000 denominada JASPER (software de referencia incluido en la parte 5 del estándar) y el LTW implementado por los autores de la propuesta. Para comparar el nivel de compresión de ambos codificadores vamos a dibujar la gráfica “tasa de bits/distorsión” usando la imagen estándar “Lena”. En concreto, como índice de distorsión usaremos el PSNR (que realmente indica calidad, así que cuanto mayor es el índice, mejor calidad presenta la imagen). Respecto al nivel de compresión, usaremos los “bits por píxel” del fichero resultante. Como la imagen es de dimensiones 512x512, esta relación se puede calcular fácilmente como el resultado de dividir el número de bits del fichero comprimido entre el número de pixels de la imagen, esto es: “Bits por píxel =(Tamaño del fichero*8)/(512*512)” Para realizar la compresión con JPEG 2000 basta con teclear jasper --input lena512.pgm --output lena.jp2 -O mode=real -O rate=0.25 Con esta orden podrás comprimir la imagen Lena sobre el fichero “lena.jp2”, y obtendrás directamente el número de millones de ciclos de CPU que se han empleado para la codificación. A partir de este valor y el tamaño del fichero resultante puedes obtener un punto de la gráfica que relaciona tiempo de ejecución y bits por píxel. A su vez, para obtener un punto de la gráfica que relaciona PSNR y bits por píxel, necesitamos comparar la imagen comprimida con la original. Esto se puede hacer simplemente tecleando imgcmp -f lena.jp2 -F lena512.pgm -m psnr siendo el PSNR el último de los números que aparece como resultado de esta ejecución. Para obtener el resto de puntos que nos sirva para completar ambas gráficas tendremos que modificar el parámetro “rate” en la compresión. Utiliza el siguiente conjunto de parámetros y construye ambas gráficas para JPEG 2000: rate={0.125, 0.0625, 0.03125, 0.015625}

Page 14: Compresores Basado en La Transformada Wavelet

14

0.25 0.5 0.75 1 1.25 1.5 1.75 2 Bits por pixel

30

35

40

45

PSNR (dB)

0.25 0.5 0.75 1 1.25 1.5 1.75 2 Bits por pixel

0

50

100

150

Millones de ciclo de CPU

200

250

Page 15: Compresores Basado en La Transformada Wavelet

15

A continuación vamos a rellenar las mismas gráficas para el compresor LTW. Para ello es conveniente que uses un bolígrafo de otro color para realizar los trazos que formen las nuevas gráficas. Para llevar a cabo la compresión teclearemos LTWcod –i lena512.pgm –o lena.ltw –q 0.45 –t y anotaremos el tiempo de ejecución del codificador y los bits por píxel resultantes. El PSNR lo podremos calcular usando el descompresor, y comparando con el origina, de la siguiente forma: LTWdecod –i lena.ltw –o lenaRec.pgm –c lena512.pgm Utiliza el siguiente conjunto de parámetros de cuantización para construir la gráfica: –q={0.9, 1.8, 3.6, 7.2} También puedes observar las distintas versiones de la imagen que se van obteniendo (fichero lenaRec.pgm, editable con IrfanView), y su correspondencia con el índice PSNR. Una vez construida la gráfica, ya podrás comparar ambos compresores en eficiencia de compresión y coste computacional. ¿Qué compresor consideras mejor según estos parámetros? Independientemente de los resultados obtenidos, ten en cuenta que JPEG 2000 permite la creación de un bitstream más flexible, con distintas escalabilidades, y que además es un compresor estándar.

4. Posibles extensiones de la práctica

Como extensiones de la práctica, se propone

1) Realizar una implementación de la transformada wavelet 3D. Esta implementación estaría orientada a una secuencia de vídeo, en la que la tercera dimensión sería el tiempo. Para realizar esta ampliación, simplemente deberás llevar a cabo las mismas modificaciones que hiciste cuando pasaste de una transformada 1D DWT a 2D DWT. Así, deberás cargar un grupo de imágenes en memoria (que formen el vídeo), y aplicar la transformada en el tiempo. No te olvides de implementar la transformada inversa

2) Implementar una transformada wavelet 1D siguiendo el esquema lifting.

El esquema lifting es una forma de calcular la transformada Wavelet totalmente distinta a la aplicación de filtros. En este esquema, en primer lugar las muestras se dividen entre muestras pares e impares, y se suceden pasos de predicción y actualización. En la predicción, el conjunto de muestras pares se intenta predecir a partir de las impares, mientras que en la actualización se realiza un ajuste de las impares a partir de las pares. Finalmente se aplica una etapa de

Page 16: Compresores Basado en La Transformada Wavelet

16

normalización. En esta extensión tendréis que implementar la transformada 1D según este esquema, obteniendo los mismos resultados que al usar los filtros. Para implementar este esquema, podéis usar las siguientes referencias:

[RAB02] M. Rabbani, R. Joshi, An overview of the JPEG2000 still image compression standard, Signal Processing: Image Communication, vol. 17, 2002.

[SWE96] W. Sweldens, The lifting scheme: a custom-design construction of biorthogonal wavelets, Journal of Applied Computational and Harmonic Analysis, vol. 3, pp. 186-200, 1996.

3) Implementar un compresor basado en la transformada Wavelet Aparte del LTW y EBCOT, varios codificadores basados en la transformada Wavelet han sido publicados en distintas revistas. Ejemplos de estos compresores son el SFQ, PROGRES, SPIHT, SPECK y SBPH. Una vez implementada la transformada Wavelet en esta práctica, el siguiente paso sería usar esta transformada para realizar la implementación de uno de estos compresores. Puedes usar las siguientes referencias para obtener más información:

[CHO05] Yushin Cho, W. A. Pearlman, A. Said, Low complexity resolution progressive image coding algorithm: PROGRES (Progressive Resolution Decompression), IEEE International Conference on Image Processing, September 2005.

[PEA04] W. A. Pearlman, A. Islam, N. Nagaraj, A. Said, Efficient, low-complexity image coding with a set-partitioning embedded block coder, IEEE Transactions on Circuits and Systems for Video technology, vol. 14, pp. 1219-1235, November 2004.

[CHY00] C. Chrysafis, A. Said, A. Drukarev, A. Islam, W. A. Pearlman, SBHP- A low complexity wavelet coder, IEEE International Conference on Acoustics, Speech, and Signal Processing, pp. 2035-2038, 2000.

[XIO97] Z. Xiong, K. Ramchandran, M. Orchard, Space-frequency quantization for wavelet image coding, IEEE Transactions on Image Processing, vol. 46, pp. 677-693, May 1997.

[SAI96] A. Said, A. Pearlman, A new, fast, and efficient image codec based on set partitioning in hierarchical trees, IEEE Transactions on circuits and systems for video technology, Vol. 6, no3, June 1996.

[RAB02] M. Rabbani, R. Joshi, An overview of the JPEG2000 still image compression standard, Signal Processing: Image Communication, vol. 17, 2002.