Compresión de Imágenes Digitales Aplicación de Algoritmos

Anuncio
Compresión de Imágenes Digitales
Aplicación de Algoritmos Genéticos en VQ
Trabajo de la Asignatura
Procesamiento de Imágenes Digitales
Departamento de Matemática Aplicada I
Universidad de Sevilla. Curso 2002/2003
Manuel Blanco Guisado, David Martínez González, Raúl Palomino Sánchez
Índice
1. Introducción...............................................................................................................2
2. Objetivos....................................................................................................................3
3. Cuantización Vectorial ..............................................................................................4
3.1. Fundamentos de la Cuantización Vectorial.........................................................4
3.1.1. Cuantización Vectorial con tamaño de bloque variable ...............................5
3.1.2. Cuantización Vectorial con tamaño de bloque fijo ......................................6
3.2. Proceso de codificación VQ................................................................................7
3.3. Generación de codebooks ...................................................................................7
3.3.1. Tamaño del codebook ..................................................................................8
3.3.2. Dimensión del codebook..............................................................................8
3.3.3. Número de codebooks..................................................................................8
3.3.4. Algoritmo de generación del codebook .......................................................9
3.4. Evaluación del resultado ...................................................................................10
4. Algoritmos Genéticos ..............................................................................................12
4.1 Introducción.......................................................................................................12
4.2 Algoritmo empleado ..........................................................................................13
4.2.1 Representación............................................................................................13
4.2.2 Fitness .........................................................................................................13
4.2.3 Cruce...........................................................................................................14
4.2.4 Mutación .....................................................................................................14
4.2.5 Selección.....................................................................................................14
5. Implementación .......................................................................................................16
5.1. Descripción de las clases implementadas .........................................................16
5.2. Ejemplos de uso ................................................................................................19
5.3. Propuestas de ampliación..................................................................................20
6. Resultados................................................................................................................27
7. Componentes ...........................................................................................................30
8. Referencias ..............................................................................................................31
Anexos .........................................................................................................................32
Anexo I. Algoritmos de codificación VQ ................................................................32
Anexo II. Algoritmos de generación de codebooks .................................................33
Anexo III. Código fuente de VQ_Gen .....................................................................34
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 2
1. Introducción
En el campo de la informática, la reducción del tamaño de la información ha sido uno de
los principales objetivos sobre el cual se han aplicado grandes estudios y donde se han
logrado grandes avances. En la actualidad existen multitud de algoritmos y aplicaciones que
consiguen grandes resultados en compresión de imágenes digitales, audio, vídeo, archivos,… manteniendo la información contenida en ellos.
Desde hace algunos años la implantación de productos multimedia en muchos
aspectos de la sociedad es un hecho real que es necesario controlar desde el punto de vista
del almacenamiento. A pesar de los recursos con los que se cuenta en la actualidad, muy
superiores a los de hace tan sólo unos cuantos años, las enormes bases de datos con las que
se trabaja hoy en día o, incluso, los soportes de almacenamiento estándar con los que se
cuentan no podrían afrontar el problema planteado por las aplicaciones multimedia si no se
contara con métodos para reducir el tamaño de esa información.
Afortunadamente, archivos de imágenes, sonido y vídeo (así como muchos otros)
son comprimidos con éxito en la actualidad y ofertan resultados sorprendentes. Sin embargo, en este punto es necesario reflexionar sobre dichos resultados. En este tipo de aplicaciones el factor que indica el grado de bondad de un proceso de compresión es el humano.
Así, existen dos grandes ramas de estudio en este aspecto: compresión con y sin pérdida de
información. Sin embargo, este punto vuelve a ser objeto de discusión y abre nuevas posibilidades de estudio. Es decir, ¿qué significa pérdida de información? Desde el punto de vista
computacional perder información es la incapacidad del algoritmo de recomponer el producto original a partir de otro al que se le ha aplicado el proceso de compresión. Sin embargo, desde un punto de vista algo más práctico, se ha podido demostrar que aun sacrificando
parte de la información original es posible comprimir la misma sin que el ser humano pueda apreciar los cambios, logrando así mejores factores de compresión (menos información).
El aspecto tratado en el último párrafo queda fielmente reflejado en técnicas de
compresión muy extendidas en la actualidad como MPEG o JPEG, que permiten incluso
reducir considerablemente el tamaño de los archivos aun sacrificando en gran parte la información, algo que resulta útil para ciertas aplicaciones. En este documento se presenta un
estudio dedicado a la compresión de imágenes digitales con pérdida de información.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 3
2. Objetivos
En este documento se presenta un estudio novedoso en el campo de compresión de imágenes digitales. El objetivo será dar a conocer al lector las diferentes técnicas empleadas así
como dar una visión más práctica a través de una aplicación software desarrollada a tal
efecto.
Este estudio estará basado en una técnica denominada cuantización vectorial, de la
cual se ofrece una introducción en el capítulo siguiente. Esta técnica no está muy desarrollada en la actualidad. Aunque goza de buenos fundamentos teóricos, una implementación
eficiente de la misma es muy difícil de llevar a cabo. Este documento propone el uso de un
algoritmo genético para su resolución.
En los siguientes puntos del documento se presentarán las dos técnicas descritas en
el párrafo anterior y la aplicación de las mismas en este estudio, así como su implementación software.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 4
3. Cuantización Vectorial
Vector Quantization (en adelante VQ) o cuantización vectorial es una técnica utilizada en
compresión multimedia, que puede ser utilizada para tratar imágenes 2D y 3D, audio, vídeo, texturas, etc.
Esta técnica es bien conocida en el mundo tecnológico actual, sin embargo plantea
problemas de eficiencia que le han impedido instaurarse como estándar. Con VQ se logran
grandes ratios de compresión1 y por este motivo, a pesar de los problemas que serán descritos a continuación, su estudio resulta una tarea muy interesante.
3.1. Fundamentos de la Cuantización Vectorial
Toda imagen digital puede representarse como una matriz de N x M píxeles2. Dicha matriz
puede dividirse en bloques de tamaño fijo o variable (según la aplicación). La técnica de
cuantización vectorial permite asignar a cada bloque de la imagen un representante dentro
de un diccionario de bloques previamente construido. De esta manera se logra de manera
efectiva comprimir la información contenida dentro del archivo de imagen, sustituyendo
bloques completos de píxeles por referencias al representante más significativo del mismo
dentro un conjunto de bloques disponibles en un diccionario.
1
2
Relación de tamaño entre la imagen original y la imagen comprimida
Punto de una imagen que representa su nivel de gris
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 5
El siguiente gráfico muestra el proceso descrito anteriormente:
Figura 1. Proceso General de VQ
En el siguiente punto se muestra una descripción de las diferentes variantes de la cuantización vectorial en función del tamaño de los bloques que se codifican.
3.1.1. Cuantización Vectorial con tamaño de bloque variable
Esta técnica se basa en la división de la imagen original en bloques de tamaño variable en
función de la similitud del nivel de gris de los puntos que los componen. De esta manera, la
codificación de la imagen necesitará, por lo general, un codebook no demasiado grande,
con lo que la ejecución de la misma será más rápida.
Sin embargo esta técnica plantea problemas de implementación derivados de la
variedad de tipos de individuos del codebook (codewords). En definitiva, los codebooks no
podrán ser reutilizados para diferentes imágenes. Esta situación, especialmente problemática, será tratada en posteriores puntos, donde se planteará la dificultad y el coste que supone
generar un codebook eficiente.
Además, el uso de esta técnica introduce un nuevo problema que aumenta el coste
computacional en la codificación de imágenes. La elección del tamaño de los bloques requiere una búsqueda intensiva dentro de los puntos de la imagen y que debería ser analizada
convenientemente para llegar a una solución rápida y eficiente.
A pesar de lo expuesto en párrafos anteriores no se puede dejar de un lado este
modo de planificar la compresión mediante cuantización vectorial dado que en algunas
aplicaciones puede resultar interesante su uso. Sin embargo, este estudio está basado en la
técnica que se expone a continuación.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 6
3.1.2. Cuantización Vectorial con tamaño de bloque fijo
Un tamaño de bloque fijo permite la construcción de codebooks caracterizados por el tamaño y, por tanto, reutilizables para imágenes que hayan sido codificadas con dichas características.
Una imagen N x M puede ser dividida en bloques de tamaño n x n. Dicho tamaño
se denomina k-dimensión, siendo k = n x n. Esta división de las imágenes plantea un primer
problema, dado que las imágenes con las que luego se va a trabajar difícilmente contendrán
un número entero de bloques n x n. En este estudio se ha optado por utilizar la solución más
sencilla y descartar aquellos píxeles que no formen un bloque completo, dado que dicho
problema queda fuera de los objetivos de este documento. Sin embargo, esta situación propone un nuevo caso de estudio dentro de la cuantización vectorial basada en bloques de
tamaño fijo.
El proceso de cuantización vectorial aplicado a imágenes digitales tiene como
objetivo la compresión de las mismas. En este punto es interesante analizar la influencia del
codebook en el tamaño final de los archivos comprimidos. En principio, existen dos maneras de almacenar el codebook. Si la portabilidad es esencial en los archivos generados será
necesario almacenar la imagen junto con el codebook utilizado para generarla. La aplicación construida para consolidar las nociones expuestas en este documento utiliza esta técnica.
Por otro lado, un mejor ratio de compresión puede lograrse si en lugar de almacenar la imagen junto con su codebook, se guardara simplemente un identificador del mismo.
Esto plantea el problema de no poder decodificar las imágenes con el mismo codebook con
el que se generaron si no se realizan ambos procesos en el mismo sistema. Sin embargo,
esta solución puede resultar de gran interés en aplicaciones como bases de datos.
Una base de datos que almacene imágenes que contengan rostros de personas
(fotografías de carnet) es un ejemplo claro de lo expuesto en el párrafo anterior. En los
siguientes puntos se tratará en profundidad la generación de codebooks, pero como adelanto
para el ejemplo, si se logra construir un codebook adecuado para el tipo de imágenes de la
base de datos, éste se podría almacenar de manera independiente liberando la carga que
supondría guardarlo junto con las imágenes, reduciendo así considerablemente el tamaño de
las imágenes y, por consiguiente, el tamaño total de la base de datos. Análogamente, este
proceso podría repetirse para otros modelos de imágenes y así disponer de un conjunto de
codebooks, cada uno adecuado para cada tipo de imagen, que permitirían reducir el tamaño
de la base de datos.
En la actualidad no se dispone de ningún formato de archivo estándar para compresión con cuantización vectorial, por ese motivo se ha decidido almacenar el codebook
junto con las imágenes comprimidas para este estudio, de manera que las mismas puedan
ser codificadas y decodificadas para su chequeo en diferentes sistemas.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 7
3.2. Proceso de codificación VQ
La codificación de una imagen mediante la técnica de cuantización vectorial se reduce a un
proceso de búsqueda dentro de los elementos del codebook seleccionado. Este proceso
resulta bastante complejo y deriva en serios problemas de rapidez. Se han realizado muchos
algoritmos para solucionar este problema, bien reduciendo los cálculos matemáticos o bien
realizando un preprocesado al codebook con el que se va a trabajar. En el anexo I se incluye
una lista de referencias a dichos algoritmos.
Dentro de este campo el algoritmo más sencillo se basa en realizar una búsqueda
completa dentro del codebook del elemento (codeword) más similar al bloque de la imagen
con el que se trata en cada momento. Esto requiere realizar un recorrido completo del codebook por cada uno de los bloques de la imagen y redunda en un tiempo de ejecución elevado.
Por razones de simplicidad este estudio hace uso del algoritmo descrito en el párrafo anterior en la aplicación construida, para el cual utiliza la siguiente función en el cálculo
del codeword más apropiado para cada bloque:
M
K
∑∑ ( x − c )
j
ij
2
i =1 j =1
donde M representa el número total de codewords, K la dimensión del bloque (n x n), x un
bloque de la imagen y c el codebook. El codeword elegido para un determinado bloque será
aquel que minimice el valor obtenido con la función anterior.
Una vez elegido el representante apropiado para cada bloque, ésta será la información a almacenar en el fichero resultante, con lo que la compresión de datos queda realizada. El resultado final de la compresión dependerá en gran medida de la similitud entre los
bloques de la imagen y los del codebook, por lo que la elección del mismo resulta fundamental. En este documento se propone un algoritmo para realizar un codebook global (es
decir, para multitud de imágenes), sin embargo, para obtener buenos resultados es necesario
tener en cuenta el grado de similitud del conjunto de entrenamiento usado para generar el
codebook y las imágenes que serán codificadas con el mismo.
Este último aspecto es el mayor reto de la cuantización vectorial, el cual no ha
podido ser resuelto de manera general, aunque para aplicaciones locales (imágenes con
rasgos similares) los ratios de compresión que se obtienen mejoran a los de otras técnicas
estándar con una mínima pérdida de información. Esta problemática es tratada en el siguiente punto de este documento.
3.3. Generación de codebooks
El proceso general de compresión con la técnica de cuantización vectorial consta de una
base teórica sencilla que, sin embargo, plantea serios problemas de implementación. Como
ya se ha visto, la división de las imágenes en bloques es un método no homogéneo, dado
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 8
que no todos los píxeles de una imagen podrán ser agrupados. Sin embargo, el principal
problema de la cuantización vectorial es la generación de codebooks apropiados para cada
aplicación. Este problema puede dividirse en varios aspectos como son el tamaño, dimensión, número y algoritmo de generación del codebook.
3.3.1. Tamaño del codebook
El tamaño del codebook utilizado en la codificación influirá en la relación calidad/coste de
la misma. Es decir, un codebook grande ofrecerá, por lo general, mejores resultados visuales de la imagen sin embargo también aumentará el tiempo de procesado de la misma. En
este punto es importante elegir un tamaño adecuado que se adapte a las dos necesidades, sin
embargo no existe ningún método para su cálculo a priori y su elección será fruto de la
experimentación.
3.3.2. Dimensión del codebook
Este parámetro, definido en este documento como k-dimensión, tendrá influencias similares
al anterior en el resultado final del proceso de cuantización vectorial. Sin embargo, su relevancia es mayor dado que influye de manera determinante sobre el proceso de generación
del codebook y, en menor medida, en la codificación de las imágenes.
Desde el punto de vista de la calidad de la imagen y su codificación, una kdimensión pequeña proporcionará, generalmente, mejores resultados visuales, aunque menores ratios de compresión. Análogamente, un valor alto de k reducirá la calidad de la imagen, pero también su tamaño.
Sin embargo, el valor de k tiene serias consecuencias en el algoritmo de generación del codebook. Un valor elevado aumentará la complejidad del proceso de generación
del codebook, un proceso ya complicado de por sí.
Así la combinación de los parámetros de tamaño y dimensión del codebook se
convertirá en un factor fundamental en la eficiencia del algoritmo y, por lo tanto, la elección de ambos debe ser precisa y, para ello, la mejor herramienta de la que se dispone es la
experiencia basada en conjuntos de prueba.
3.3.3. Número de codebooks
Como se ha visto, la elección del codebook apropiado resulta fundamental a la hora de
obtener resultados óptimos en la codificación. En este documento se estudia un algoritmo
cuyo objetivo es lograr un codebook fiable para multitud de imágenes. Desde el punto de
vista del parámetro analizado en este punto, el número de codebooks para la aplicación
sería 1. Este valor resulta interesante para reducir la complejidad computacional, es decir,
para este caso sólo es necesario calcular el codebook en una sola ocasión.
Por otro lado, la generación de múltiples codebooks hace más flexible la codificación de las imágenes y permitiría reducir la carga en el algoritmo de generación de code-
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 9
books. En un caso extremo, si se lograra un método eficiente y rápido de construcción de
codebooks con buenos resultados a nivel local una solución a la codificación de la cuantización vectorial permitiría asociar a cada imagen su propio y único codebook. Esto obligaría a almacenar cada codebook en el mismo fichero junto con la imagen.
Sin embargo, teniendo en cuenta que la generación del codebook es el proceso más
costoso en VQ, la solución planteada en el párrafo anterior resulta todavía más complicada
que la basada en un único codebook.
Así, se propone el uso de unos cuantos codebooks asignables a imágenes dividas
en diferentes categorías clasificadas, por ejemplo, por la escala de grises de las mismas.
Estos codebooks se calcularían en un principio para que la aplicación que haga uso de la
cuantización vectorial pueda seleccionarlos en función de las imágenes objetivo a ser codificadas.
3.3.4. Algoritmo de generación del codebook
Junto con el proceso de codificación, la generación de codebooks plantea un grave problema computacional que ha sido fruto de numerosas líneas de investigación. Cualquier algoritmo dedicado a construir codebooks toma como parámetros un conjunto de entrenamiento
y el valor de k-dimensión. En otros casos es necesario aportar el tamaño final del codebook.
En el anexo II se incluyen referencias a algunos de estos algoritmos.
Para comprender el funcionamiento de este tipo de algoritmos, a continuación se
mostrará el proceso seguido en LBG (Linde-Buzo-Gray), el algoritmo más conocido en este
tipo de aplicaciones. En el siguiente capítulo de este documento se describe el algoritmo
implementado para este estudio.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 10
LBG debe su nombre a los autores de dicho algoritmo. Los siguientes puntos ofrecen una
breve descripción de su funcionamiento:
1.
2.
3.
Determinar el número de elementos del codebook (codewords), es decir, su tamaño: N
Realizar una selección aleatoria de N bloques del conjunto de entrenamiento, que
servirán como codebook inicial. En este punto se pueden emplear un o más imágenes diferentes.
Aproximar los vectores de entrenamiento para cada codeword usando la distancia
euclídea. Este paso se lleva a cabo tomando cada bloque de entrada y calculando la
distancia euclídea para cada uno de los elementos del codebook. Un bloque será
asignado al codeword cuya distancia euclídea sea la menor:
k
∑ (x − y )
i
ij
2
j =1
4.
Recalcular el codebook, para lo cual se tiene en cuenta el número de bloques que
han sido asignados a un determinado codeword. La siguiente función realiza el
cálculo, siendo m el número de bloques asignados a un codebook:
1 m
∑ xij
m j =1
5.
Repetir los pasos 2 y 3 hasta que no haya cambios en el codebook o que éstos sean
insignificantes
LBG es uno de los algoritmos más sencillos utilizados para esta aplicación y, a pesar de
obtener buenos resultados localmente, el coste computacional que supone no recomienda su
uso en aplicaciones prácticas.
Figura 2. Asignación de bloques a codewords
3.4.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 11
Evaluación del resultado
Una vez obtenido el resultado procedente del proceso de codificación, es necesario disponer
de una medida del grado de bondad del mismo. Para ello se empleará la relación señalruido (SNR) entre los valores de la imagen original y los de la imagen codificada, según la
siguiente fórmula:
N
SNR =
M
∑∑ x
N
i =1 j =1
M
∑∑ ( x
ij
2
ij
− yij ) 2
i =1 j =1
donde x representa a la imagen original, y a la imagen comprimida, y N x M el tamaño de
ambas.
Una vez definida esta medida se podrán obtener valores fiables para realizar la
comparación de la calidad de diferentes métodos de compresión.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 12
4. Algoritmos Genéticos
4.1 Introducción
Se denomina Computación Evolutiva a un amplio conjunto de técnicas de resolución de
problemas complejos basados en la emulación de los procesos naturales de la evolución. La
principal aportación de la Computación Evolutiva a la metodología de resolución de problemas consiste en el uso de mecanismos de selección de soluciones potenciales y de construcción de nuevos candidatos por recombinación de características de otros ya presentes,
de modo parecido a como ocurre en la evolución de los seres vivos. Esta evolución se realiza hasta que se cumpla algún criterio de parada previamente establecido, que puede ser un
número determinado de iteraciones u otro criterio.
Begin Algoritmo
P[0]=PoblacionInicial();
FitP[0]=Evaluar(P[0]);
t=0;
Mientras no(CondicionDeParada)
Q[t]=SeleccionarPadres(P[t]);
Q[t]=Reproducir(Q[t]);
FitQ[t]=Evaluar(Q[t]);
P[t]=Seleccionar(P[t],Q[t],FitP[t],FitQ[t]);
FitP[t]=Evaluar(P[t]);
FinMientras
End Algoritmo
Estructura general de un Algoritmo Evolutivo
Los Algoritmos Genéticos son uno de los paradigmas surgidos en el seno de la Computación Evolutiva. Se caracterizan por aplicar a una población de posibles soluciones al problema una serie de operadores de selección determinista y de cruce principalmente, y mutación en menor medida. Tradicionalmente se ha implementado una representación binaria de
los individuos, aunque también se aplica representación real.
Los elementos clave de un Algoritmo Genético son:
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 13
Representación: Cada individuo es una estructura de datos que representa una posible
solución al problema. Esta representación se realizaba en principio mediante un vector
de bits, sin embargo, en la actualidad se suele utilizar una representación mediante vectores (llamados cromosomas) de valores reales. El conjunto de los individuos se denomina población.
Fitness: Es una medida de la capacidad de un individuo para solucionar el problema,
permite comparar la bondad de diferentes individuos.
Reproducción: Es una transformación aplicada a los individuos de la población actual
para generar otros individuos parecidos, candidatos a formar parte de la siguiente población. Existen dos tipos de reproducción:
- Cruce: Se basa en la recombinación de la información de dos o más individuos para generar uno o más nuevos individuos.
- Mutación: Se basa en la modificación de la información de un individuo para
generar un nuevo individuo diferente.
Selección: De los individuos de la población actual y los generados mediante reproducción se escogen los mejores (en base a su Fitness) para pasar a formar parte de la
siguiente generación.
4.2 Algoritmo empleado
4.2.1 Representación
Cada individuo de la población representa un codeword de n x n píxeles. Por simplicidad,
en lugar de implementarse mediante una matriz de píxeles se ha implementado como un
vector de tamaño k de bytes (que permiten 256 niveles de gris), siendo k = n x n. De acuerdo con la tendencia actual de programación de Algoritmos Evolutivos, cada individuo contiene su propia información de Fitness, en lugar de implementarse en un vector de fitness
independiente.
La población se representa mediante un vector de C individuos.
Tanto k como C son parámetros ajustables por el usuario.
4.2.2 Fitness
El fitness de cada individuo se calcula como el error cuadrático entre los píxeles del individuo y los píxeles de los bloques de la imagen para los cuales, el individuo es el más aproximado.
M
Fitness =
K
∑∑ ( x − c )
j
ij
2
i =1 j =1
siendo M el número de bloques examinados y k el número de píxeles de cada bloque. Xij
representa el valor del pixel j-ésimo del bloque i-ésimo de la imagen original, y Cj representa el pixel j-ésimo del individuo evaluado.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 14
4.2.3 Cruce
Se ha aplicado un cruce de aridad 1,1 (de un padre se genera un hijo) basado en los genes
movibles. Los genes movibles fueron descubiertos en 1940 por B. McCintock, ganador de
un premio Nobel de biomedicina en 1983, en los Laboratorios de Cold Spring Harbor,
EEUU. Son genes que tienen la capacidad de “saltar” de un cromosoma a otro y acoplarse
en su interior, provocando de este modo potentes mutaciones en los seres vivos.
El cruce de genes movibles se ha definido para Algoritmos Genéticos de codificación binaria del modo siguiente:
Se definen dos genes, I-gen y D-gen, formados exclusivamente por unos y exclusivamente por ceros respectivamente, de un tamaño “a” determinado, generalmente 1 o 2.
Para cada cromosoma a cruzar se escoge aleatoriamente I o D y se inserta el gen
correspondiente siguiendo la siguiente regla:
Los I-genes se deben insertar en la a-ésima posición a partir del primer cero (empezando por el bit menos significativo).
Los D-genes se deben insertar en la a-ésima posición a partir del primer uno (empezando por el bit menos significativo).
Los bits a la derecha de la inserción se desplazan hacia la derecha para dejar sitio
al nuevo gen.
Por ejemplo, supongamos el cromosoma
01001001
tras insertar un cromosoma I con a=2 quedaría
010001110 (01)
Si insertamos un cromosoma D con a=2 quedaría
010001000 (01)
En el algoritmo genético planteado en este estudio, se aplica el cruce a los píxeles
cuyo fitness es peor que la media del individuo, tomando cada pixel (un unsigned char)
como una cadena de 8 bits útiles.
4.2.4 Mutación
La mutación se aplica sobre uno de los pixeles del individuo a mutar, eligiendo al azar un
píxel del individuo, y dentro de este píxel, un bit concreto, y cambiando su valor.
4.2.5 Selección
Tradicionalmente, los Algoritmos Genéticos se han utilizado para buscar al mejor individuo
posible, que será el individuo de mejor fitness de la población final. En nuestro problema,
cada individuo es un codeword, y la solución al problema es el conjunto de codewords que
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 15
forman el codebook. Por ello no se pueden aplicar los criterios tradicionales de selección,
que se basan exclusivamente en el fitness.
En el algoritmo implementado, se comienza la población inicial con un conjunto de codewords generados a partir de un histograma de la imagen, y se realizan n iteraciones. En
cada iteración, para cada individuo de la población se generan un hijo procedente del cruce
y otro hijo procedente de la mutación. Para cada terna de padre, hijo cruzado e hijo mutado,
se elige al mejor de los tres y ése pasará a formar parte de la siguiente generación. De este
modo se evita que un individuo particularmente bueno propague copias suyas por la población y el resultado final sea un conjunto de individuos con fitness muy bueno, pero que son
similares entre sí y no sirven para sustituir a todos los bloques de la imagen original.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 16
5. Implementación
Los aspectos tratados en este documento han sido implementados en un PC, con el lenguaje
de programación C++. A continuación se detalla dicha implementación. Para el manejo de
ficheros gráficos estándar se ha hecho uso de la librería gratuita DevIL (más información en
el capítulo 8).
5.1. Descripción de las clases implementadas
La construcción de la aplicación se basa en dos clases fundamentales: VQ_Codebook y
VQ_Image. En el anexo III se ofrece un listado del código fuente de las mismas.
Clase VQ_Codebook
La clase VQ_Codebook contiene toda la funcionalidad necesaria para un codebook. Almacena información referente a la k-dimensión, la longitud y los datos del codebook. Las
siguientes funciones son realmente las únicas que un desarrollador que haga uso de esta
clase debe usar:
VQ_Codebook::SetKDimension
Antes de construir un nuevo codebook es necesario establecer
su k-dimensión. Esta función proporciona la mejor manera de hacerlo, ya
que hay que tener en cuenta que el número de filas y columnas de un bloque
debe ser el mismo, es decir, que la raíz cuadrada de k-dimensión debe ser
entera
VQ_Codebook::MakeCodebook
Esta función realiza el proceso de generación del codebook, bien con la
función por defecto basada en un algoritmo genético o bien con otra definida
por el usuario. Para poder llamar a esta función debe haberse establecido
previamente la k-dimensión y el codebook no debe estar construido, es decir, solamente se puede llamar a esta función una vez por cada instancia de
la clase
VQ_Codebook::GetKDimensión
Devuelve la k-dimensión actual del codebook
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 17
VQ_Codebook::GetNumberOfRows
Devuelve la longitud del codebook, es decir el número de codewords que
contiene
Las restantes están orientadas para uso interno dentro de la aplicación:
VQ_Codebook::Función
LoadCodebook
GetCodebookIndex
WriteCodebook
Descripción
Carga un codebook desde el disco. Toma como
parámetro de entrada un objeto ifstream, por lo
que puede usarse para cargar un codebook
desde el disco siempre y cuando se abra el
fichero previamente
Devuelve un puntero al comienzo de los datos
del codebook
Escribe el codebook en el disco. Toma como
parámetro de entrada un objeto ofstream, por lo
que puede usarse para salvar un codebook en el
disco siempre y cuando se abra el fichero previamente
Clase VQ_Image
La clase VQ_Image almacena los datos correspondientes a las imágenes y sus correspondientes codebooks.
VQ_Image::LoadImage
Carga un fichero con formato VQ desde el disco, con su correspondiente
codebook, tal y como se ha definido el almacenamiento del mismo en este
documento
VQ_Image::DecodeImage
Escribe en el disco una imagen BMP con el resultado de la codificación de
la imagen comprimida con VQ. Con este método se pueden comprobar los
resultados visuales de la codificación, dado que no se ha definido ninguna
manera de visualizar directamente una imagen con formato VQ
VQ_Image::SetCodebook
Asigna a una imagen VQ (sin construir) un codebook existente. El procedimiento general será llamar a las funciones SetKDimension y MakeCodebook de una instancia de VQ_Codebook y, a continuación, llamar a este
método para hacer efectiva la asignación del codebook construido a la imagen actual. Si la imagen VQ ya está construida, una llamada a este método
dará un error
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 18
VQ_Image::MakeImage
Toma como entrada una imagen BMP y construye su correspondiente imagen VQ. Como precondición se exige que exista un codebook asignado a la
imagen y que ésta no haya sido construida previamente. Este método se
encarga de actualizar el número de bandas de la imagen, proporcionando así
una manera de comprobar si una imagen ha sido construida correctamente
VQ_Image::WriteImage
Escribe en el disco una imagen con formato VQ, con la condición de que la
misma y su codebook estén construidos
VQ_Image::GetNumberOfBands
Devuelve el número de bandas de la imagen VQ. Si tras llamar a MakeImage ocurre algún error, está función devolvería 0
El resto de clases que componen la aplicación están reservadas para uso interno y definen
las estructuras de datos con las que se trabaja. En el anexo III se incluye el código fuente de
la aplicación, donde se pueden encontrar los detalles específicos de implementación de cada
uno de los métodos descritos.
El algoritmo de codificación de una imagen VQ está definido en el fichero
“VQ_Default.h”; su nombre es DefaultVQImageEncodingAlgorithm y refleja los conceptos
descritos en el punto 3.2 de este documento.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 19
5.2. Ejemplos de uso
Creación de un codebook
El procedimiento general de creación de un codebook se define con las siguientes sentencias C++:
// Declaración
VQ_Codebook codebook;
// Define la k-dimensión del codebook que se va a crear
// Sus valores más habituales son 4 y 9
codebook.SetKDimension(K_DIMENSION);
// Generación del codebook con el algoritmo por defecto descrito en este documento
// IMAGEN_BMP es el nombre del fichero de entrenamiento para la generación del codebook
// LONGITUD es el tamaño en filas del codebook ( de 1 a 65536 )
// Los otros dos parámetros son específicos del algoritmo genético
// El valor de A varía entre 1 y 4; su valor más habitual es 2
codebook.MakeCodebook(IMAGEN_BMP,LONGITUD-1,NUMERO_DE_GENERACIONES,A);
Cargar un codebook desde el disco
// Declaraciones
VQ_Codebook codebook;
ifstream ficheroCodebook (CODEBOOK_FILENAME, ios::in|ios::binary);
codebook.LoadCodebook(ficheroCodebook);
Salvar un codebook en el disco
// Declaraciones
VQ_Codebook codebook;
ofstream ficheroCodebook (CODEBOOK_FILENAME,ios::trunc|ios::binary);
// Creación del codebook. Estas dos líneas pueden sustituirse por una llamada a LoadCodebook
codebook.SetKDimension(K_DIMENSION);
codebook.MakeCodebook(IMAGEN_BMP,LONGITUD-1,NUMERO_DE_GENERACIONES,A);
codebook.WriteCodebook(ficheroCodebook);
Compresión de una imagen BMP
// Declaraciones
VQ_Codebook codebook;
VQ_Image imagen;
// Creación del codebook. Estas dos líneas pueden sustituirse por una llamada a LoadCodebook
codebook.SetKDimension(K_DIMENSION);
codebook.MakeCodebook(IMAGEN_BMP,LONGITUD-1,NUMERO_DE_GENERACIONES,A);
// Establece el codebook a usar en la codificación
imagen.SetCodebook(&codebook);
// Procedimiento de compresion
imagen.MakeImage(IMAGEN_BMP_A_COMPRIMIR);
// Escritura del fichero VQ en disco
imagen.WriteImage(IMAGEN_VQ);
Decodificación de una imagen VQ
// Declaración
VQ_Image imagen;
// Carga una imagen VQ desde el disco
imagen.LoadImage(IMAGEN_VQ);
// Escritura del fichero BMP en disco
imagen.DecodeImage(IMAGEN_BMP);
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 20
5.3. Propuestas de ampliación
En este apartado se proponen unas líneas de mejora de la implementación descrita en el
punto anterior. La generación del codebook es el proceso más costoso dentro del procedimiento general de la cuantización vectorial, sin embargo, es un factor que está suficientemente cubierto en la implementación propuesta con el uso de un algoritmo genético. Por
otro lado, el tiempo empleado en la codificación de una imagen sí supone un problema
serio, para el cual es necesario una solución más eficiente que la planteada en el punto 3.2
de este documento.
En el anexo I se incluyen multitud de estudios relacionados con este problema.
Como primera aproximación al mismo se planteará un algoritmo que reduce los tiempos de
codificación de una imagen a través de algoritmo del apartado 3.2 entre 10 y 15 veces para
valores de K-Dimensión de 4 y 9. Este algoritmo, cuyo código se incluye en este mismo
apartado, consta de los siguientes pasos:
•
•
•
Calcular los valores de gris medios de cada elemento del codebook y almacenarlos
en una matriz auxiliar
Definir un umbral de nivel de gris sobre el que se realizarán las comparaciones entre los bloques de la imagen y del codebook. Por defecto, se toma un valor 10, lo
que significa que un bloque solamente se comparará con aquellos elementos del
codebook cuyo nivel de gris medio se sitúe en el intervalo
[GRIS_MEDIO_DEL_BLOQUE - 10, GRIS_MEDIO_DEL_BLOQUE + 10]
Localizar el elemento más parecido dentro del codebook para los valores del intervalo anterior. Si no existe ninguno, realizar una búsqueda completa dentro de todos los elementos del codebook
La implementación de este procedimiento no ha sido incluida dentro de la interfaz gráfica
creada para facilitar el uso de las clases definidas anteriormente. Sin embargo, se han incluido los ficheros necesarios para que el lector pueda comprobar la funcionalidad de este
algoritmo, así como para disponer de ejemplos de uso del código implementado y de base
de conocimiento para la creación de nuevas funciones de codificación y generación de
codebooks.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 21
//--------------------------------------------------//
// Proyecto VQ_Gen - optimized.h
//
// -------------------------------------------------//
// Definición del parámetro de la función
// optimizada de codificación de una imagen VQ
//
// Autor: Manuel Blanco (whitey(at)manuel-blanco.net)
// Ultima modificacion: 18/01/2003
//
//---------------------------------------------------#ifndef __VQ_OPTIMIZATIONS__
#define __VQ_OPTIMIZATIONS__
#include <VQ_Codebook.h>
#include <VQ_Matrix.h>
#define GRAY_SCALE_LIMIT 10
unsigned char OptimizedEncodingAlgorithm (char* fileName, VQ_Codebook* codebook, VQ_Matrix** matrix);
#endif
//--------------------------------------------------//
// Proyecto VQ_Gen - config.h
//
// -------------------------------------------------//
// Parámetros para la compilación del fichero
// de ejemplo para el uso de las funciones de
// VQ_Gen desde la línea de comandos
//
// Autor: Manuel Blanco (whitey(at)manuel-blanco.net)
// Ultima modificacion: 18/01/2003
//
//---------------------------------------------------#ifndef __VQ_CONFIG__
#define __VQ_CONFIG__
typedef enum {STANDARD, ACC} CODEBOOK_GENERATION_ALGORITHM;
typedef enum {DEFAULT, OPTIMIZED} IMAGE_ENCODING_ALGORITHM;
#define
#define
#define
#define
BMP_FILENAME "original.bmp"
VQ_FILENAME "result.vq"
BMP_TEST_IMAGE "test.bmp"
CODEBOOK_TEST_IMAGE "codetest.bmp"
#define CODEBOOK_OUT_FILENAME "codebook.dic"
#define CODEBOOK_IN_FILENAME "ccb-k4-g8-512.dic"
#define IS_CODEBOOK_GENERATION_ENABLED false
#define K_DIMENSION 9
#define IMAGE_ENCODER OPTIMIZED
#define CODEBOOK_GENERATOR ACC
#define NUMBER_OF_GENERATIONS 6
#define CODEBOOK_LENGTH 256
#define A 2
#endif
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 22
//--------------------------------------------------//
// Proyecto VQ_Gen - optimized.cpp
//
// -------------------------------------------------//
// Función optimizada de codificación de una imagen VQ
//
// Autor: Manuel Blanco (whitey(at)manuel-blanco.net)
// Ultima modificacion: 18/01/2003
//
//---------------------------------------------------#include "optimized.h"
#include <il/il.h>
unsigned char OptimizedEncodingAlgorithm (char* fileName, VQ_Codebook* codebook, VQ_Matrix** matrix) {
ILuint userImage;
ILboolean errorCode;
ILuint imageType;
unsigned int numberOfRows, numberOfCols;
unsigned int rowsToEncode, colsToEncode;
unsigned char numberOfBands, b;
unsigned int kDimension;
unsigned int i,j,k1,k2,c;
unsigned int rK;
unsigned char** codebookIndex;
unsigned char* pointer;
unsigned char* block;
VQ_MATRIX_TYPE minIndex;
unsigned long acum, minF1;
int meanGrayL, minGrayL, maxGrayL;
VQ_Matrix* newMatrix;
VQ_MATRIX_TYPE* codebookMap;
assert(fileName != NULL);
assert(codebook != NULL);
assert(*matrix == NULL);
// DevIL library initialization
ilInit();
ilGenImages(1,&userImage);
ilBindImage(userImage);
// Loads a BMP image from disk
errorCode = ilLoad(IL_BMP,fileName);
if (errorCode != IL_COULD_NOT_OPEN_FILE) {
imageType = ilGetInteger(IL_IMAGE_TYPE);
codebookIndex = codebook->GetCodebookIndex();
kDimension = codebook->GetKDimension();
rK = (unsigned int)(sqrt(kDimension));
numberOfRows = ilGetInteger(IL_IMAGE_HEIGHT);
numberOfCols = ilGetInteger(IL_IMAGE_WIDTH);
numberOfBands = ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
switch (numberOfBands) {
case 1:
ilConvertImage(IL_LUMINANCE,IL_UNSIGNED_BYTE);
break;
case 3:
ilConvertImage(IL_RGB,IL_UNSIGNED_BYTE);
break;
default:
return 0;
}
newMatrix = new VQ_Matrix [numberOfBands];
// Initializes VQ_Image set of matrix
for (b=0;b<numberOfBands;b++) {
[newMatrix[b].NumberOfCols];
newMatrix[b].NumberOfRows = numberOfRows / rK;
newMatrix[b].NumberOfCols = numberOfCols / rK;
newMatrix[b].Matrix = new VQ_MATRIX_TYPE* [newMatrix[b].NumberOfRows];
for (i=0;i<newMatrix[b].NumberOfRows;i++)
newMatrix[b].Matrix[i] = new VQ_MATRIX_TYPE
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 23
// Gets DevIL image data start position
pointer = ilGetData();
block = new unsigned char [kDimension];
rowsToEncode = newMatrix[0].NumberOfRows * rK;
colsToEncode = newMatrix[0].NumberOfCols * rK;
// Order codebook by mean gray scale
codebookMap = new VQ_MATRIX_TYPE[codebook->GetNumberOfRows()];
for (c=0;c<codebook->GetNumberOfRows();c++) {
acum = 0;
for (i=0;i<kDimension;i++)
acum = acum + codebookIndex[c][i];
acum = acum / kDimension;
codebookMap[c] = (VQ_MATRIX_TYPE)acum;
}
// Algorithm
for (i=0;i<rowsToEncode;i+=rK)
for (j=0;j<colsToEncode;j+=rK)
for (b=0;b<numberOfBands;b++) {
for (k1=0;k1<rK;k1++)
for (k2=0;k2<rK;k2++)
block[k1*rK+k2] =
pointer[(i+k1)*(numberOfCols*numberOfBands)+(j+k2)*numberOfBands+b];
meanGrayL = 0;
for (c=0;c<kDimension;c++)
meanGrayL += block[c];
meanGrayL = meanGrayL / kDimension;
minF1 = ULONG_MAX;
minIndex = 0;
for (c=0;c<codebook->GetNumberOfRows();c++) {
minGrayL = codebookMap[c] -
GRAY_SCALE_LIMIT;
if (minGrayL < 0) minGrayL = 0;
maxGrayL = codebookMap[c] +
GRAY_SCALE_LIMIT;
if (maxGrayL > 255) maxGrayL = 255;
if ((meanGrayL >= minGrayL)
<= maxGrayL)) {
&& (meanGrayL
acum = 0;
for (k1=0;k1<rK;k1++)
for (k2=0;k2<rK;k2++)
acum = acum +
(unsigned long)pow((block[k1*rK+k2] - codebookIndex[c][k1*rK+k2]),2);
if (acum < minF1) {
minF1 = acum;
minIndex = c;
}
}
}
if (minF1 == ULONG_MAX) {
minF1 = ULONG_MAX;
minIndex = 0;
for (c=0;c<codebook->GetNumberOfRows();c++)
{
acum = 0;
for (k1=0;k1<rK;k1++)
for (k2=0;k2<rK;k2++)
acum = acum +
(unsigned long)pow((block[k1*rK+k2] - codebookIndex[c][k1*rK+k2]),2);
if (acum < minF1) {
minF1 = acum;
minIndex = c;
}
}
}
newMatrix[b].Matrix[i/rK][j/rK] = minIndex;
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 24
}
delete[] block;
delete[] codebookMap;
*matrix = newMatrix;
}
else numberOfBands = 0;
// Shutdowns DevIL library
ilDeleteImages(1,&userImage);
ilShutDown();
return numberOfBands;
}
//--------------------------------------------------//
// Proyecto VQ_Gen - main.cpp
//
// -------------------------------------------------//
// Uso de las funciones de VQ_Gen desde la línea de comandos
//
// Autor: Manuel Blanco (whitey(at)manuel-blanco.net)
// Ultima modificacion: 18/01/2003
//
//---------------------------------------------------#include
#include
#include
#include
#include
#include
#include
<VQ_Image.h>
<fstream>
<iostream>
<cassert>
<ctime>
"config.h"
"optimized.h"
long fileSize(const char* filename) {
long l,m;
ifstream file (filename, ios::in|ios::binary);
l = file.tellg();
file.seekg (0, ios::end);
m = file.tellg();
file.close();
return (m-l);
}
VQ_MATRIX_TYPE StandardCodebookGenerationAlgorithm(unsigned int k, unsigned char, char**, unsigned
char*** codebook) {
unsigned int i,j;
*codebook = new unsigned char* [256];
for (i=0;i<256;i++) (*codebook)[i] = new unsigned char[k];
for (i=0;i<256;i++)
for (j=0;j<k;j++)
(*codebook)[i][j] = i;
return 255;
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 25
int main(void) {
VQ_Codebook codebook;
VQ_Image vq,result;
ifstream ficheroCodebookEntrada;
ofstream ficheroCodebookSalida;
time_t inicio,fin;
long tbmp,tvq;
long minutos,segundos;
CODEBOOK_GENERATION_ALGORITHM codebookAlgorithm = CODEBOOK_GENERATOR;
IMAGE_ENCODING_ALGORITHM encodingAlgorithm = IMAGE_ENCODER;
bool generarCodebook = IS_CODEBOOK_GENERATION_ENABLED;
if (generarCodebook) {
codebook.SetKDimension(K_DIMENSION);
switch(codebookAlgorithm) {
case ACC:
cout << "Generando codebook (k = " << K_DIMENSION << ") a
partir del fichero " << CODEBOOK_TEST_IMAGE << " ..." << endl;
inicio = time(NULL);
codebook.MakeCodebook(CODEBOOK_TEST_IMAGE,CODEBOOK_LENGTH1,NUMBER_OF_GENERATIONS,A);
break;
case STANDARD:
cout << "Generando codebook (k = " << K_DIMENSION << ") ..." <<
endl;
inicio = time(NULL);
codebook.MakeCodebook(0,NULL,StandardCodebookGenerationAlgorithm);
break;
default:
assert(false);
}
fin = time(NULL);
segundos = (long)fin-inicio;
minutos = segundos / 60;
segundos = segundos - 60*minutos;
cout << "Codebook generado en " << minutos << " min. " << segundos << " seg." <<
endl << endl;
ficheroCodebookSalida.open(CODEBOOK_OUT_FILENAME,ios::trunc|ios::binary);
codebook.WriteCodebook(ficheroCodebookSalida);
ficheroCodebookSalida.close();
}
else {
ficheroCodebookEntrada.open(CODEBOOK_IN_FILENAME,ios::in|ios::binary);
if (ficheroCodebookEntrada.is_open())
codebook.LoadCodebook(ficheroCodebookEntrada);
else {
cout << "Error: no se puede abrir el fichero " << CODEBOOK_IN_FILENAME
<< endl << endl;
return 0;
}
ficheroCodebookEntrada.close();
}
vq.SetCodebook(&codebook);
cout << "Generando imagen VQ a partir del fichero " << BMP_FILENAME << " ..." << endl;
inicio = time(NULL);
switch(encodingAlgorithm) {
case DEFAULT:
vq.MakeImage(BMP_FILENAME);
break;
case OPTIMIZED:
vq.MakeImage(BMP_FILENAME,OptimizedEncodingAlgorithm);
break;
default:
assert(false);
}
fin = time(NULL);
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 26
if (vq.GetNumberOfBands() != 0) {
endl << endl;
segundos = (long)fin-inicio;
minutos = segundos / 60;
segundos = segundos - 60*minutos;
cout << "La codificacion tardo " << minutos << " min. " << segundos << " seg." <<
vq.WriteImage(VQ_FILENAME);
result.LoadImage(VQ_FILENAME);
result.DecodeImage(BMP_TEST_IMAGE);
tbmp = fileSize(BMP_FILENAME);
tvq = fileSize(VQ_FILENAME);
cout << "La longitud del archivo original es de: " << tbmp << " bytes" << endl;
cout << "La longitud del archivo comprimido es de: " << tvq << " bytes" << endl;
cout << "El ratio de compresion es de: " << 100-((float)tvq/(float)tbmp)*100 <<
"%" << endl << endl;
}
else
cout << "Error: No se puede abrir el fichero " << BMP_FILENAME << " o el formato
de entrada incorrecto" << endl << endl;
return 0;
}
La función nombrada como OptimizedEncodingAlgorithm implementa el algoritmo optimizado de codificación descrito con anterioridad, que ofrece resultados visuales similares a
los del algoritmo original con una gran mejora en el tiempo de ejecución. Si bien el problema de la eficiencia no queda suficientemente resuelto, esta función se plantea como
punto de partida para la generación de sucesivos algoritmos de codificación.
Un resultado visual correcto es otro de los objetivos que se intenta alcanzar con
cualquier método de compresión de imágenes digitales. Para el caso en estudio surge el
problema de la aparición de un efecto de cuadriculado en las imágenes comprimidas. Éste
surge por la carencia de bloques suficientemente buenos en el codebook. Sin embargo, la
mejora del algoritmo que se plantea en este punto consiste en considerar bloques vecinos a
la hora de codificar la imagen para que la diferencia entre ellos no sea demasiado grande y
no sea apreciable el efecto descrito en este párrafo. Nuevamente la mejora va dirigida al
algoritmo de codificación, que se plantea como un punto clave tanto en la eficiencia como
en los resultados visuales del proceso de cuantización vectorial.
En este documento ya se ha descrito una posible implementación relacionada con
el almacenamiento del codebook diferente a la finalmente propuesta. Dicha implementación
se basa en no salvar el codebook junto con la imagen comprimida para así ahorrar espacio
en disco. Se propone realizar la programación de esta solución.
Por último, uno de los aspectos que limita el ratio de compresión es el tipo de los
elementos que componen una imagen VQ. En la implementación planteada, dicho tipo se
define con la macro VQ_MATRIX_TYPE, definida como unsigned short, lo cual significa
que se emplearán 2 bytes para direccionar un elemento del codebook. Sin embargo, para
codebooks de 256 elementos (o menos) uno de los bytes no se usa por lo que el ratio de
compresión se reduce a la mitad del teóricamente posible. Se propone parametrizar el tipo
de los elementos de una imagen VQ para evitar este problema.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 27
6. Resultados
El análisis de los resultados obtenidos en este estudio ofrece conclusiones interesantes acerca de la compresión de imágenes con la técnica de cuantización vectorial. En primer lugar,
resulta evidente que el gran coste computacional asociado a la mencionada técnica no está
acorde con los resultados visuales obtenidos. Tecnologías ampliamente extendidas como
JPEG ofrecen mayor calidad con menor tiempo de computación, por lo que la cuantización
vectorial está lejos de competir con las herramientas disponibles en la actualidad. Sin embargo, la base teórica que sostiene a la cuantización vectorial es suficientemente buena
como para tenerla en cuenta, aunque para ello es necesario contar con un gran avance en las
técnicas de codificación y de generación de codebooks. En el apartado anterior de este
documento se plantean los principales problemas que aparecen al implementar una herramienta que permita comprimir imágenes con el uso de cuantización vectorial, para los cuales se dislumbran las líneas de investigación a seguir para lograr mejores resultados.
Las siguientes imágenes han sido obtenidas con la implementación propuesta en
este estudio y por lo tanto son un buen reflejo de todos los aspectos comentados a lo largo
de este documento. Cabe destacar que las imágenes de entrada utilizadas contienen 8 bits
por canal, por lo que las pruebas realizadas se basan en imágenes en formato BMP de escala de grises (256 niveles) o en color (256 niveles de gris por canal). La generación del codebook con el que se obtuvieron los mejores resultados visuales se llevó a cabo en 19 minutos en un PC con procesador Intel Pentium III a 866 MHz con una imagen a color de 1024
x 768 píxeles. Los tiempos indicados a continuación se refieren a la ejecución del algoritmo
de codificación en la misma máquina. El tamaño de la imagen original es de 408 x 306
píxeles, en formato de color RGB.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 28
Imagen Original
La siguiente imagen se obtuvo con un codebook de 256 elementos y k-dimensión 4. Con
este valor de k, el efecto de cuadriculado es menor y se obtienen los mejores resultados
visuales. Las pruebas efectuadas sobre varias imágenes demuestran que 256 elementos
resultan escasos para la codificación. El tiempo de codificación fue de 54 segundos con un
ratio de compresión del 50%. Con el algoritmo optimizado de codificación planteado en el
capítulo anterior, la compresión se realizó en 9 segundos.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 29
Imagen generada con un codebook de 256 elementos y k-dimensión 9. La calidad visual
disminuye sensiblemente respecto a la anterior. Ratio de compresión 77%. Tiempo de ejecución 54 / 11 segundos (optimizado).
La última imagen es la de mayor calidad. Generada con un codebook de k-dimensión 4 y
512 elementos. Ratio de compresión 50%. Tiempo de ejecución 104 / 9 segundos (optimizado).
Para valores de k-dimensión 9, el tamaño del codebook debería ser muy superior a los anteriores para obtener buenos resultados visuales, debido a la mayor diversidad de bloques
diferentes. Este trabajo no ha sido llevado a cabo en este estudio.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 30
7. Componentes
Manuel Blanco Guisado
Documentación
Desarrollador de VQ
David Martínez González
Documentación de algoritmos genéticos
Desarrollador de la interfaz gráfica
Raúl Palomino Sánchez
Documentación de algoritmos genéticos
Desarrollador del algoritmo genético (ACC)
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 31
8. Referencias
Digital Image Compression Using a Genetic Algorithm. Cheng Yimin, Wang Yixiao, Sun
Qibin and Sun Longxiang. Division of Electronics, University of Science & Technology of
China. Academic Press, 1999.
Vector Quantization. M. Qasem.
http://www.geocities.com/mohamedqasem/vectorquantization/vq.html
Developer’s Image Library (DevIL). D. Woods. http://www.imagelib.org
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 32
Anexos
Anexo I. Algoritmos de codificación VQ
D. Cheng and A. Gersho, "A fast codebook search algorithm for nearest neighbor patter
matching," Proceedings IEEE international Conference on Acoustics, Speech and Signal
Processing, pp. 6.14.1-6.14.4, Apr 1986.
M. R. Soleymani and S. D. Morgera, "A fast mmse encoding technique for vector
quantization," IEEE Transactions on Communicatinos 37, pp. 656-659, June 1989.
S. W. Ra and J. K. Kim, "A fast mean-distance-ordered partial codebook search algorithm
for image vector quantization," IEEE transactions on Circuits and Systems - II: Analog and
Digital Processing 40, pp. 576-579, Sept 1993.
L. Guan and M. Kamel, "A vector distribution model and an effective nearest neighbor
search method for image vector quantization," IEEE Transactions on Image Processing 6,
pp. 1688-1691, Dec 1997.
K. K. Paliwal and V. Ramasubramanian, "Effect of ordering the codebook on the efficiency
of the partial distance search algorithm for vector quantization," IEEE Transactions on
Communications 37, pp. 538-540, May 1989.
C. D. Bei and R. M. Gray, "An Improvement of the minimum distortion encoding
algorithm for vector quantization," IEEE Transactions on Communications 33, pp. 11321133, Oct 1985.
K. T. Lo and J. Feng, "Predictive mean search algorithm for vector quantization of images,"
Proceedings IEEE international Conference on Acoustics, Speech and Signal Processing,
pp. V609-V612, Apr 1994.
M. R. Soleymani and S. D. Morgera, "A high speed seach algorithm for vector
quantization," Proceedings IEEE international Conference on Acoustics, Speech and Signal
Processing, pp. 45.6.1-45.6.2, Apr 1987.
L. Torrest and J. Huguet, "An improvement on codebook search for vector quantization,"
IEEE Transactions on Communications 42, pp. 208-210, Feb/Mar/Apr 1994.
M. R. Soleymani and S. D. Morgera, "An efficient nearest neighbor search method," IEEE
Transactions on Communicatoins COM-35, pp. 677-679, June 1987.
B. R. D. Cheng, A. Gersho and Y. Shoham, "Fast search algorithms for vector quantization
and patter matching," Proceedings IEEE international Conference on Acoustics, Speech and
Signal Processing 1, pp. 9.11.1-9.11.4, Mar 1985.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 33
Anexo II. Algoritmos de generación de codebooks
A. B. Y. Linde and R. M. Gray, "An algorithm for vector quantization design," IEEE
Transactions on Communicatinos COM-28, pp. 84-95, Jan 1980.
Y. S. Kulkarni, "Image compression by vector quantization: use of clustering techniques for
codebook design," Course project for CPS 802
S. C. Ahalt and J. E. Fowler, "Vector quantization using artificial neural network models,"
Proceedings of the International Workshop on Adaptive Methods and Emergent Techniques
for Signal Processing and Communications (D. Docampo and A. R. Figueras, eds.),
(Bayona, Spain), pp. 42-61, June 1993.
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 34
Anexo III. Código fuente de VQ_Gen
//--------------------------------------------------//
// Proyecto VQ_Gen - VQ_Common.h
//
// -------------------------------------------------//
// Descripcion:
// Definiciones comunes necesarias a los fuentes
// de VQ_Gen. Este fichero no necesita ser incluido
//
// Autor: Manuel Blanco (whitey(at)manuel-blanco.net)
// Ultima modificacion: 11/01/2003
//
//---------------------------------------------------#ifndef __VQ_COMMON__
#define __VQ_COMMON__
// Standard includes
#include <cassert>
#include <fstream>
#include <cmath>
using namespace std;
// Definition of NULL element
#ifndef NULL
#define NULL 0
#endif
// VQ_Image file checking string
#define VQ_HEADER_CHECK "VQ Image File"
// Definition of data elements of a VQ_Image header in disk
typedef union {
char Buffer[sizeof(VQ_HEADER_CHECK)+sizeof(unsigned char)];
struct {
char HeaderCheck[sizeof(VQ_HEADER_CHECK)];
unsigned char NumberOfBands;
} Elements;
} VQ_Image_Header;
// Macro definition that returns numbers of elements of a matrix
#define MatrixElements(matrix) ((matrix->NumberOfRows)*(matrix->NumberOfCols))
#define VQ_MATRIX_TYPE unsigned short
// Definition of data elements of a VQ_Matrix header in disk
typedef union {
char Buffer[sizeof(unsigned int)*2];
struct {
unsigned int NumberOfRows;
unsigned int NumberOfCols;
} Elements;
} VQ_Matrix_Header;
// Definition of data elements of a VQ_Codebook header in disk
typedef union {
char Buffer[2*sizeof(unsigned int)];
struct {
unsigned int K_Dimension;
unsigned long NumberOfRows;
} Elements;
} VQ_Codebook_Header;
#endif
//---------------------------------------------------
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 35
//
// Proyecto VQ_Gen - VQ_Codebook.h
//
// -------------------------------------------------//
// Definicion de la Clase VQ_Codebook:
// Datos y operaciones relativas a un codebook
// tratado por VQ_Gen
//
// Autor: Manuel Blanco (whitey(at)manuel-blanco.net)
// Ultima modificacion: 15/01/2003
//
//---------------------------------------------------#ifndef __VQ_CODEBOOK__
#define __VQ_CODEBOOK__
#include "VQ_Common.h"
class VQ_Codebook {
protected:
// Codeword K-Dimension
unsigned int k_dimension;
// Codebook length
unsigned long numberOfRows;
// Codewords matrix index
unsigned char** codebook;
public:
// Default constructor
VQ_Codebook();
// Default destructor
~VQ_Codebook();
// Assigns a k-dimension to the codebook
// Codebook pointer must be NULL : you can't change k_dimension of a
// builded codebook
virtual void SetKDimension(unsigned int dimension);
// Builds the codebook with default encoding algorithm
// Codebook pointer must be NULL (empty codebook)
// You'll only need to use this one on most cases
virtual void MakeCodebook(char* fileName, VQ_MATRIX_TYPE codebookLength, unsigned int
numberOfGenerations, unsigned char a);
// Builds the codebook giving a particular enconding algorithm
// Codebook pointer must be NULL (empty codebook)
virtual void MakeCodebook(unsigned char numberOfFiles,
char** fileList,
VQ_MATRIX_TYPE
(*encodingFunction)(unsigned int, unsigned char, char**, unsigned char***));
// Loads a codebook giving a file stream pointer
// Codebook pointer must be NULL (codebooks cannot be reloaded o remaked)
virtual void LoadCodebook(ifstream& filePointer);
// Returns current K-Dimension if codebook is present
virtual unsigned int GetKDimension();
// Returns codebook length if it is present
virtual unsigned long GetNumberOfRows();
// Returns a pointer to codebook structure
// Do not call to this function is you expect a NULL pointer
virtual unsigned char** GetCodebookIndex();
// Writes codebook into a giving file stream
// Codebook pointer cannot be NULL
virtual void WriteCodebook(ofstream& filePointer);
};// END CLASS DEFINITION VQ_Codebook
#endif // __VQ_CODEBOOK__
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 36
//--------------------------------------------------//
// Proyecto VQ_Gen - VQ_Matrix.h
//
// -------------------------------------------------//
// Definicion de la Clase VQ_Matrix:
// Estructura de datos de una matriz correspondiente
// a una banda de color de una imagen
//
// Autor: Manuel Blanco (whitey(at)manuel-blanco.net)
// Ultima modificacion: 25/12/2002
//
//---------------------------------------------------#ifndef __VQ_MATRIX__
#define __VQ_MATRIX__
class VQ_Matrix {
public:
unsigned int NumberOfRows;
unsigned int NumberOfCols;
VQ_MATRIX_TYPE** Matrix;
};// END CLASS DEFINITION VQ_Matrix
#endif // __VQ_MATRIX__
//--------------------------------------------------//
// Proyecto VQ_Gen - VQ_Default.h
//
// -------------------------------------------------//
// Descripcion:
// Definicion de funciones por defecto de codificado
// de imagenes y codebooks VQ_Gen
//
// Autor: Manuel Blanco (whitey(at)manuel-blanco.net)
// Ultima modificacion: 18/01/2003
//
//---------------------------------------------------#ifndef __VQ_DEFAULT__
#define __VQ_DEFAULT__
#include "VQ_Codebook.h"
#include "VQ_Matrix.h"
//
//
//
//
//
Algorithm for VQ images encoding, described on:
"Digital Image Compression Using a Genetic Algorithm"
Division of Electronics, University of Science & Technology of China
Cheng Yimin, Wang Yixiao, Sun Qibin and Sun Longxiang
unsigned char DefaultVQImageEncodingAlgorithm (char* fileName, VQ_Codebook* codebook, VQ_Matrix**
matrix);
//
//
//
//
//
//
Algorithm for VQ codebook generation
Based on a Genetic Algorithm Technology, described on:
"Digital Image Compression Using a Genetic Algorithm"
Division of Electronics, University of Science & Technology of China
Cheng Yimin, Wang Yixiao, Sun Qibin and Sun Longxiang
unsigned char** DefaultVQCodebookGenerator(char* fileName, VQ_MATRIX_TYPE codebookLength, unsigned int
kDimension,
unsigned int numberOfGenerations, unsigned char a);
#endif
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 37
//--------------------------------------------------//
// Proyecto VQ_Gen - VQ_Image.h
//
// -------------------------------------------------//
// Definicion de la Clase VQ_Image:
// Datos y operaciones relativas a una imagen VQ
// tratada por VQ_Gen
//
// Autor: Manuel Blanco (whitey(at)manuel-blanco.net)
// Ultima modificacion: 12/12/2002
//
//---------------------------------------------------#ifndef __VQ_IMAGE__
#define __VQ_IMAGE__
#include "VQ_Common.h"
#include "VQ_Matrix.h"
#include "VQ_Codebook.h"
class VQ_Image {
protected:
unsigned char numberOfBands;
// Index of image matrix
VQ_Matrix* imagePointer;
// Index of the codebook associated to the image
VQ_Codebook* codebook;
public:
VQ_Image();
~VQ_Image();
// Loads a VQ image from disk
// Do not try to load an image into a not null VQ_Image
virtual void LoadImage(const char* fileName);
// Decodes a VQ to a BMP image and writes result into disk
// VQ_Image must already been encoded
virtual void DecodeImage(char* fileName);
// Assigns a codebook to a VQ image
// You should never delete assigned codebook. This function assigns passed pointer
// directly and does not clone content
// Do not try to set a codebook if image has already been assigned to one
virtual void SetCodebook(VQ_Codebook* existingCodebook);
// Encodes a normal image to a VQ image
// Do not call to these functions if the image has been already encoded
virtual void MakeImage(char* fileName); // uses default algorithm
virtual void MakeImage(char* fileName, unsigned char (*encodingFunction)(char*,
VQ_Codebook*, VQ_Matrix**));
// Writes a VQ image into disk
// Both image an codebook pointers cannot be NULL
virtual void WriteImage(const char* fileName);
unsigned char GetNumberOfBands();
};// END CLASS DEFINITION VQ_Image
#endif // __VQ_IMAGE__
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 38
/*
*/
+--------------------------------------------+
| Fichero creado por Raul Palomino Sanchez |
| 5º Ingenieria Informatica
|
| Ultima actualizacion: 15/1/2003 12:40
|
| e-mail: [email protected]
|
+--------------------------------------------+
#ifndef __ACC__
#define __ACC__
#include
#include
#include
#include
<cstdlib>
<il/il.h>
<cmath>
<ctime>
#define MAXDOUBLE 1.7976931348623158e+308;
typedef struct{
int id;
unsigned * v;
int tam;
int l;
double *fitness;
double f;
}Individuo;
Individuo crear_Ind(int * id, unsigned * vector, int tam, int l);
void destruir_Ind(Individuo ind);
Individuo crear_Ind_blanco(int * id, int tam,int l);
Individuo clonar_Ind(int * id, Individuo a);
unsigned rotar_d(unsigned n, int a);
int indice_I_mask(unsigned gen,int a, int l);
int indice_D_mask(unsigned gen,int a, int l);
unsigned calcular_gen_I(int pc, int a);
unsigned cruzar_pixel(unsigned pixel,int a, int l);
void cruzar_Ind_mask(Individuo * ind,unsigned mb,int a);
void cruzar_Ind(Individuo * ind,double umbral,int a);
unsigned mutar_pixel(unsigned pixel, int l);
void mutar_Ind(Individuo * ind, int l);
void evaluar_Ind(Individuo * ind, unsigned ** x,unsigned filas,unsigned cols, unsigned bandas);
void borrar_todo(Individuo * lista, int n);
void evaluar_lista(Individuo * lista, unsigned ** x,unsigned filas,unsigned cols, unsigned bandas,int
n);
void copiar_de_a(int * id, Individuo * de, Individuo * a, int n);
void cruzar_lista(Individuo * lista, unsigned ** x,unsigned filas,unsigned cols, unsigned
bandas,double umb, int a, int n);
void mutar_lista(Individuo * lista, unsigned ** x,unsigned filas,unsigned cols, unsigned bandas, int
n, int l);
void Crear_Iniciales(int *id, Individuo * lista,unsigned *iniciales,int k, int n,unsigned ** x,
unsigned filas, unsigned cols, unsigned bandas);
void elegir(Individuo * cruzados, Individuo * mutados, Individuo * padres, int n) ;
void incrementar_generacion(int * id, Individuo * padres, int n, int l, double umb_c, int a, unsigned
** x,unsigned filas,unsigned cols, unsigned bandas);
unsigned char ** acc(char * fichero, int n, int k, int ngen, int a);
int busca_mayor(unsigned * h);
unsigned * Iniciales(unsigned * h, int n);
unsigned * Histograma(unsigned ** x,unsigned numberOfRows, unsigned numberOfCols, unsigned
numberOfBands, int t);
unsigned ** Load (char * fileName, unsigned * numberOfRows, unsigned * numberOfCols, unsigned *
numberOfBands);
#endif
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 39
//--------------------------------------------------//
// Proyecto VQ_Gen - VQ_Codebook.cpp
//
// -------------------------------------------------//
// Clase VQ_Codebook
//
// Autor: Manuel Blanco (whitey(at)manuel-blanco.net)
// Ultima modificacion: 18/01/2003
//
//---------------------------------------------------#include <VQ_Codebook.h>
#include <VQ_Default.h>
VQ_Codebook::VQ_Codebook() {
k_dimension = 0;
numberOfRows = 0;
codebook = NULL;
}
VQ_Codebook::~VQ_Codebook() {
delete[] codebook;
}
void VQ_Codebook::SetKDimension(unsigned int dimension) {
assert(codebook == NULL);
// sqrt of k_dimension must be an integer
// if not, it is assigned to lowest integer returned by:
k_dimension = (int)pow((int)sqrt(dimension),2);
}
void VQ_Codebook::MakeCodebook(char* fileName, VQ_MATRIX_TYPE codebookLength, unsigned int
numberOfGenerations, unsigned char a) {
assert(a < 5);
assert(fileName != NULL);
assert(codebook == NULL);
codebook =
DefaultVQCodebookGenerator(fileName,codebookLength,k_dimension,numberOfGenerations,a);
if (codebook != NULL) numberOfRows = codebookLength;
}
void VQ_Codebook::MakeCodebook(unsigned char numberOfFiles,
char** fileList,
VQ_MATRIX_TYPE
(*encodingFunction)(unsigned int, unsigned char, char**, unsigned char***)) {
assert(encodingFunction != NULL);
assert(codebook == NULL);
numberOfRows = (*encodingFunction)(k_dimension,numberOfFiles,fileList,&codebook) + 1;
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 40
void VQ_Codebook::LoadCodebook(ifstream& filePointer) {
VQ_Codebook_Header header;
char* buffer;
unsigned int f,c,b;
assert(filePointer != NULL);
assert(codebook == NULL);
if (filePointer.is_open()) {
filePointer.read(header.Buffer,sizeof(VQ_Codebook_Header));
k_dimension = header.Elements.K_Dimension;
numberOfRows = header.Elements.NumberOfRows;
buffer = new char[numberOfRows*k_dimension];
filePointer.read(buffer,sizeof(unsigned char)*numberOfRows*k_dimension);
codebook = new unsigned char* [numberOfRows];
for (f=0;f<numberOfRows;f++) codebook[f] = new unsigned char [k_dimension];
b=0;
for (f=0;f<numberOfRows;f++)
for (c=0;c<k_dimension;c++) {
codebook[f][c] = buffer[b];
b++;
}
delete[] buffer;
}
}
unsigned int VQ_Codebook::GetKDimension() {
assert(codebook != NULL);
return k_dimension;
}
unsigned long VQ_Codebook::GetNumberOfRows() {
assert(codebook != NULL);
return numberOfRows;
}
unsigned char** VQ_Codebook::GetCodebookIndex() {
assert(codebook != NULL);
return codebook;
}
void VQ_Codebook::WriteCodebook(ofstream& filePointer) {
VQ_Codebook_Header header;
char* buffer;
unsigned int f,c,b;
assert(filePointer != NULL);
assert(codebook != NULL);
if (filePointer.is_open()) {
header.Elements.K_Dimension = k_dimension;
header.Elements.NumberOfRows = numberOfRows;
filePointer.write(header.Buffer,sizeof(VQ_Codebook_Header));
buffer = new char[numberOfRows*k_dimension];
b=0;
for (f=0;f<numberOfRows;f++)
for (c=0;c<k_dimension;c++) {
buffer[b] = codebook[f][c];
b++;
}
filePointer.write(buffer,sizeof(unsigned char)*numberOfRows*k_dimension);
delete[] buffer;
}
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 41
//--------------------------------------------------//
// Proyecto VQ_Gen - VQ_Default.cpp
//
// -------------------------------------------------//
// Descripcion:
// Funciones por defecto de codificado
// de imagenes y codebooks VQ_Gen
//
// Autor: Manuel Blanco (whitey(at)manuel-blanco.net)
// Ultima modificacion: 15/01/2003
//
//---------------------------------------------------#include
#include
#include
#include
<VQ_Default.h>
<VQ_Common.h>
<il/il.h>
<acc.h>
unsigned char DefaultVQImageEncodingAlgorithm (char* fileName, VQ_Codebook* codebook, VQ_Matrix**
matrix) {
ILuint userImage;
ILboolean errorCode;
ILuint imageType;
unsigned int numberOfRows, numberOfCols;
unsigned int rowsToEncode, colsToEncode;
unsigned char numberOfBands, b;
unsigned int kDimension;
unsigned int i,j,k1,k2,c;
unsigned int rK;
unsigned char** codebookIndex;
unsigned char* pointer;
unsigned char* block;
VQ_MATRIX_TYPE minIndex;
unsigned long acum, minF1;
VQ_Matrix* newMatrix;
assert(fileName != NULL);
assert(codebook != NULL);
assert(*matrix == NULL);
// DevIL library initialization
ilInit();
ilGenImages(1,&userImage);
ilBindImage(userImage);
// Loads a BMP image from disk
errorCode = ilLoad(IL_BMP,fileName);
if (errorCode != IL_COULD_NOT_OPEN_FILE) {
imageType = ilGetInteger(IL_IMAGE_TYPE);
codebookIndex = codebook->GetCodebookIndex();
kDimension = codebook->GetKDimension();
rK = (unsigned int)(sqrt(kDimension));
numberOfRows = ilGetInteger(IL_IMAGE_HEIGHT);
numberOfCols = ilGetInteger(IL_IMAGE_WIDTH);
numberOfBands = ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
switch (numberOfBands) {
case 1:
ilConvertImage(IL_LUMINANCE,IL_UNSIGNED_BYTE);
break;
case 3:
ilConvertImage(IL_RGB,IL_UNSIGNED_BYTE);
break;
default:
return 0;
}
newMatrix = new VQ_Matrix [numberOfBands];
// Initializes VQ_Image set of matrix
for (b=0;b<numberOfBands;b++) {
newMatrix[b].NumberOfRows = numberOfRows / rK;
newMatrix[b].NumberOfCols = numberOfCols / rK;
newMatrix[b].Matrix = new VQ_MATRIX_TYPE* [newMatrix[b].NumberOfRows];
for (i=0;i<newMatrix[b].NumberOfRows;i++)
newMatrix[b].Matrix[i] = new VQ_MATRIX_TYPE
[newMatrix[b].NumberOfCols];
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 42
// Gets DevIL image data start position
pointer = ilGetData();
block = new unsigned char [kDimension];
rowsToEncode = newMatrix[0].NumberOfRows * rK;
colsToEncode = newMatrix[0].NumberOfCols * rK;
// Algorithm
for (i=0;i<rowsToEncode;i+=rK)
for (j=0;j<colsToEncode;j+=rK)
for (b=0;b<numberOfBands;b++) {
for (k1=0;k1<rK;k1++)
for (k2=0;k2<rK;k2++)
block[k1*rK+k2] =
pointer[(i+k1)*(numberOfCols*numberOfBands)+(j+k2)*numberOfBands+b];
minF1 = ULONG_MAX;
minIndex = 0;
for (c=0;c<codebook->GetNumberOfRows();c++) {
long)pow((block[k1*rK+k2] - codebookIndex[c][k1*rK+k2]),2);
acum = 0;
for (k1=0;k1<rK;k1++)
for (k2=0;k2<rK;k2++)
acum = acum + (unsigned
if (acum < minF1) {
minF1 = acum;
minIndex = c;
}
}
newMatrix[b].Matrix[i/rK][j/rK] = minIndex;
}
delete[] block;
*matrix = newMatrix;
}
else numberOfBands = 0;
// Shutdowns DevIL library
ilDeleteImages(1,&userImage);
ilShutDown();
return numberOfBands;
}
unsigned char** DefaultVQCodebookGenerator(char* fileName, VQ_MATRIX_TYPE codebookLength, unsigned int
kDimension,
unsigned int numberOfGenerations, unsigned char a) {
assert(fileName != NULL);
assert(codebookLength > 0);
return acc(fileName,codebookLength,kDimension,numberOfGenerations,a);
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 43
//--------------------------------------------------//
// Proyecto VQ_Gen - VQ_Image.cpp
//
// -------------------------------------------------//
// Clase VQ_Image
//
// Autor: Manuel Blanco (whitey(at)manuel-blanco.net)
// Ultima modificacion: 26/12/2002
//
//---------------------------------------------------#include <VQ_Image.h>
#include <VQ_Default.h>
#include <il/il.h>
VQ_Image::VQ_Image() {
numberOfBands = 0;
imagePointer = NULL;
codebook = NULL;
}
VQ_Image::~VQ_Image() {
if (imagePointer != NULL) {
for (unsigned char i=0;i<numberOfBands;i++) ;
delete imagePointer->Matrix;
}
delete[] imagePointer;
}
void VQ_Image::LoadImage(const char* fileName) {
VQ_Image_Header iheader;
VQ_Matrix_Header mheader;
VQ_MATRIX_TYPE* mBuffer;
unsigned int i,j;
unsigned int f,c,b;
ifstream vqFile (fileName,ios::in|ios::binary);
VQ_Matrix* matrixPointer;
assert(imagePointer == NULL);
assert(codebook == NULL);
assert(fileName != NULL);
if (vqFile.is_open()) {
vqFile.seekg(0,ios::beg);
vqFile.read(iheader.Buffer,sizeof(VQ_Image_Header));
if (strcmp(iheader.Elements.HeaderCheck,VQ_HEADER_CHECK) == 0) {
numberOfBands = iheader.Elements.NumberOfBands;
imagePointer = new VQ_Matrix[numberOfBands];
for (i=0;i<numberOfBands;i++) {
vqFile.read(mheader.Buffer,sizeof(VQ_Matrix_Header));
matrixPointer = &imagePointer[i];
matrixPointer->NumberOfRows = mheader.Elements.NumberOfRows;
matrixPointer->NumberOfCols = mheader.Elements.NumberOfCols;
matrixPointer->Matrix = new VQ_MATRIX_TYPE* [matrixPointer-
>NumberOfRows];
[(matrixPointer->NumberOfCols)];
for (j=0;j<matrixPointer->NumberOfRows;j++)
matrixPointer->Matrix[j] = new VQ_MATRIX_TYPE
mBuffer = new VQ_MATRIX_TYPE[MatrixElements(matrixPointer)];
vqFile.read((char*)mBuffer,sizeof(VQ_MATRIX_TYPE)*MatrixElements(matrixPointer));
b=0;
for (f=0;f<matrixPointer->NumberOfRows;f++)
for (c=0;c<matrixPointer->NumberOfCols;c++) {
matrixPointer->Matrix[f][c] = mBuffer[b];
b++;
}
delete[] mBuffer;
}
codebook = new VQ_Codebook;
codebook->LoadCodebook(vqFile);
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 44
}
vqFile.close();
}
}
void VQ_Image::DecodeImage(char* fileName) {
ILuint userImage;
ILuint imageFormat;
unsigned int numberOfRows, numberOfCols;
unsigned int i,j,k1,k2;
unsigned char b;
unsigned char* block;
unsigned char* rawBlock;
unsigned char** codebookIndex;
unsigned int kDimension, rK;
assert(imagePointer != NULL);
assert(codebook != NULL);
assert(fileName != NULL);
numberOfRows = imagePointer[0].NumberOfRows;
numberOfCols = imagePointer[0].NumberOfCols;
codebookIndex = codebook->GetCodebookIndex();
kDimension = codebook->GetKDimension();
rK = (unsigned int) sqrt(kDimension);
// DevIL library initialization
ilInit();
ilGenImages(1,&userImage);
ilBindImage(userImage);
switch (numberOfBands) {
case 1:
imageFormat = IL_LUMINANCE;
break;
case 3:
imageFormat = IL_RGB;
break;
default:
assert(false);
break;
}
// Creates a new image
ilTexImage(numberOfCols*rK,numberOfRows*rK,1,numberOfBands,imageFormat,IL_UNSIGNED_BYTE,NULL
);
// Decodes VQ_Image to DevIL format
rawBlock = new unsigned char [kDimension*numberOfBands];
for (i=0;i<numberOfRows;i++)
for (j=0;j<numberOfCols;j++) {
for (b=0;b<numberOfBands;b++) {
block = codebookIndex[(imagePointer[b].Matrix[i][j])];
for (k1=0;k1<rK;k1++)
for (k2=0;k2<rK;k2++)
rawBlock[k1*rK*numberOfBands+k2*numberOfBands+b] = block[k1*rK+k2];
}
for (k1=0;k1<rK;k1++)
for (k2=0;k2<rK;k2++)
ilSetPixels((j*rK+k2),/*(numberOfRows*rK-1)-
*/(i*rK+k1),
0,1,1,1,imageFormat,IL_UNSIGNED_BYTE,
&(rawBlock[k1*rK*numberOfBands+k2*numberOfBands]));
}
delete[] rawBlock;
// Writes new image into disk
ilEnable(IL_FILE_OVERWRITE);
switch (numberOfBands) {
case 1:
ilConvertImage(IL_RGB,IL_UNSIGNED_BYTE);
break;
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 45
case 3:
break;
default:
assert(false);
}
ilSave(IL_BMP,fileName);
// DevIL library use is finished
ilDeleteImages(1,&userImage);
ilShutDown();
}
void VQ_Image::SetCodebook(VQ_Codebook* existingCodebook) {
assert(imagePointer == NULL);
assert(codebook == NULL);
assert(existingCodebook != NULL);
codebook = existingCodebook;
}
void VQ_Image::MakeImage(char* fileName) {
assert(imagePointer == NULL);
assert(codebook != NULL);
assert(fileName != NULL);
numberOfBands = DefaultVQImageEncodingAlgorithm(fileName,codebook,&imagePointer);
}
void VQ_Image::MakeImage(char* fileName,
VQ_Codebook*, VQ_Matrix**)) {
unsigned char (*encodingFunction)(char*,
assert(imagePointer == NULL);
assert(codebook != NULL);
assert(fileName != NULL);
assert(encodingFunction != NULL);
numberOfBands = (*encodingFunction)(fileName,codebook,&imagePointer);
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 46
void VQ_Image::WriteImage(const char* fileName) {
VQ_Image_Header iheader;
VQ_Matrix_Header mheader;
VQ_MATRIX_TYPE* mBuffer;
unsigned char i;
unsigned int f,c,b;
ofstream vqFile (fileName,ios::trunc|ios::binary);
VQ_Matrix* matrixPointer;
assert(imagePointer != NULL);
assert(codebook != NULL);
assert(fileName != NULL);
if (vqFile.is_open()) {
strcpy(iheader.Elements.HeaderCheck,VQ_HEADER_CHECK);
iheader.Elements.NumberOfBands = numberOfBands;
vqFile.write(iheader.Buffer,sizeof(VQ_Image_Header));
for (i=0;i<numberOfBands;i++) {
matrixPointer = &imagePointer[i];
mheader.Elements.NumberOfRows = matrixPointer->NumberOfRows;
mheader.Elements.NumberOfCols = matrixPointer->NumberOfCols;
vqFile.write(mheader.Buffer,sizeof(VQ_Matrix_Header));
mBuffer = new VQ_MATRIX_TYPE[MatrixElements(matrixPointer)];
b=0;
for (f=0;f<matrixPointer->NumberOfRows;f++)
for (c=0;c<matrixPointer->NumberOfCols;c++) {
mBuffer[b] = matrixPointer->Matrix[f][c];
b++;
}
vqFile.write((char*)mBuffer,sizeof(VQ_MATRIX_TYPE)*MatrixElements(matrixPointer));
delete[] mBuffer;
}
codebook->WriteCodebook(vqFile);
vqFile.close();
}
}
unsigned char VQ_Image::GetNumberOfBands() {
return numberOfBands;
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 47
/*
*/
+--------------------------------------------+
| Fichero creado por Raul Palomino Sanchez |
| 5º Ingenieria Informatica
|
| Ultima actualizacion: 15/1/2003 12:30
|
| e-mail: [email protected]
|
+--------------------------------------------+
#include <acc.h>
/* crea un individuo con etiqueta "id", de "tam" alelos y cada alelo
de longitud "l", a partir del array "vector"
*/
Individuo crear_Ind(int * id, unsigned * vector, int tam, int l)
{
int i;
Individuo a;
a.id=*id;
*id=*id+1;
a.v=(unsigned *) malloc (tam * sizeof(unsigned));
for (i=0;i<tam;i++)
a.v[i]=vector[i];
a.tam=tam;
a.l=l;
a.fitness=(double *) malloc (tam * sizeof(double));
for(i=0;i<tam;i++)
a.fitness[i]=MAXDOUBLE;
a.f=MAXDOUBLE;
return a;
}
/* destruye el individuo "ind"
*/
void destruir_Ind(Individuo ind)
{
free(ind.fitness);
free(ind.v);
}
/* crea un individuo con etiqueta "id", de "tam" alelos y cada alelo
de longitud "l", con todos los alelos a valor 0
*/
Individuo crear_Ind_blanco(int * id, int tam,int l)
{
int i;
Individuo a;
a.id=*id;
*id=*id+1;
a.v=(unsigned *) malloc (tam * sizeof(unsigned));
for (i=0;i<tam;i++)
a.v[i]=0;
a.tam=tam;
a.l=l;
a.fitness=(double *) malloc (tam * sizeof(double));
for(i=0;i<tam;i++)
a.fitness[i]=MAXDOUBLE;
a.f=MAXDOUBLE;
return a;
}
/* genera un individuo con identificador "id" idéntico a "a"
*/
Individuo clonar_Ind(int * id, Individuo a)
{
int i;
Individuo b;
b.id=*id;
*id=*id+1;
b.v= (unsigned *) malloc (a.tam * sizeof(unsigned));
for (i=0;i<a.tam;i++)
b.v[i]=a.v[i];
b.tam=a.tam;
b.l=a.l;
b.fitness=(double *) malloc (a.tam * sizeof(double));
for(i=0;i<a.tam;i++)
b.fitness[i]=a.fitness[i];
b.f=a.f;
return b;
}
/* rota el numero "n" hacia la derecha
"a" veces, perdiendo el bit que sale
por la derecha */
unsigned rotar_d(unsigned n, int a)
{
unsigned result;
int i;
result=n;
for (i=0;i<a;i++)
{
result = _rotr(result,1);
result = (unsigned)(result & (unsigned)32767);
}
return result;
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 48
/* calcula a partir de donde insertar un gen I,
para longitud de gen I "a" y longitud de
cromosoma "l" */
int indice_I_mask(unsigned gen,int a, int l)
{
unsigned mask=1;
int contador=0;
int i=-1+a;
do
{
if (!(gen&mask))
contador++;
i++;
mask=_rotl(mask,1);
}while ((contador<1)&&(i<l));
return i;
}
/* calcula a partir de d¢nde insertar un gen D,
para longitud de gen D "a" y longitud de
cromosoma "l" */
int indice_D_mask(unsigned gen,int a, int l)
{
unsigned mask=1;
int contador=0;
int i=-1+a;
do
{
if (gen&mask)
contador++;
i++;
mask=_rotl(mask,1);
}while ((contador<1)&&(i<l));
return i;
}
/* genera un gen I compuesto de "a" unos
a partir del punto pc
*/
unsigned calcular_gen_I(int pc, int a)
{
unsigned result=0;
int i;
for(i=1;i<=a;i++)
result=result+(unsigned)pow(2,pc-i);
return result;
}
/* genera el resultado de cruzar un cromosoma "pixel"
de tamaño "l", añadiendo un gen I o D de tamaño "a"
*/
unsigned cruzar_pixel(unsigned pixel,int a, int l)
{
int prob;
int punto_cruce;
unsigned alta,baja,mascara,result,aux;
result=0;
prob =rand()%2;
if (prob==0)
{// I-gen
punto_cruce = indice_I_mask(pixel,a,l);
mascara=(unsigned)pow(2,punto_cruce)-1;
baja = pixel&mascara;
alta=pixel - baja;
mascara=calcular_gen_I(punto_cruce,a);
aux=rotar_d(baja,a);
result=alta+mascara+aux;
}
else
{// D-gen
punto_cruce = indice_D_mask(pixel,a,l);
mascara=(unsigned)pow(2,punto_cruce)-1;
baja = pixel&mascara;
alta=pixel - baja;
aux=rotar_d(baja,a);
result=alta+aux;
}
}
return result;
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 49
/* realiza el cruce sobre los p¡xeles del individuo "ind" indicados por
la mascara "mb", con un par metro "a" (no se usa)
*/
void cruzar_Ind_mask(Individuo * ind,unsigned mb,int a)
{
int i;
unsigned aux;
aux=1;
for (i=0;i<ind->tam;i++)
{
if((aux&mb)!=0)
{
ind->v[i] = cruzar_pixel(ind->v[i],a,ind->l);
}
aux=_rotl(aux,1);
}
}
/* aplica el cruce a un individuo, cruzando con un
parametro "a" cada pixel cuyo fitness
sobrepase un "umbral"
*/
void cruzar_Ind(Individuo * ind,double umbral,int a)
{
int i,t;
t=ind->tam;
// printf("cruzando pixels ");
for (i=0;i<t;i++)
{
if(ind->fitness[i]>umbral)
{
// printf("%i ",i);
ind->v[i] = cruzar_pixel(ind->v[i],a,ind->l);
}
}
// printf("\n");
}
/* muta uno de los "l" bits del numero "pixel"
*/
unsigned mutar_pixel(unsigned pixel, int l)
{
unsigned mask;
int prob;
prob=rand()%l;
mask =1;
mask=_rotl(mask,prob);
return pixel^mask;
}
/* muta uno de los pixeles del individuo "ind"
*/
void mutar_Ind(Individuo * ind,int l)
{
int prob;
prob=rand()%ind->tam;
ind->v[prob]=mutar_pixel(ind->v[prob],l);
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 50
/* calcula el fitnes por pixel y general del individuo "ind" a partir
de la imagen "x", sabiendo su numero de filas, columnas y bandas
*/
void evaluar_Ind(Individuo * ind, unsigned ** x,unsigned filas,unsigned cols, unsigned bandas)
{
double *suma, *contador;
double aux,qia;
int rk,i,j,k,k2,t;
int nf,nc;
unsigned b;
t=ind->tam;
rk=(int)sqrt(t);
nf=filas/rk;
nc=cols/rk;
suma = (double *) malloc (sizeof(double)*t);
contador = (double *) malloc (sizeof(double)*t);
for(i=0;i<t;i++)
{
suma[i]=0;
contador[i]=1;
}
for(b=0;b<bandas;b++)
{
for(j=0;j<nf;j++)
for(i=0;i<nc;i++)
for(k=0;k<rk;k++)
for(k2=0;k2<rk;k2++)
{
aux=(int)((unsigned
int)(x[b][(j*rk*cols)+(i*rk)+(k*cols)+k2])-(unsigned int)ind->v[2*k+k2]);
aux=aux*aux;
if(aux<(1600))
{
suma[2*k+k2]+=aux;
contador[2*k+k2]++;
}
}
}
}
aux=0;
for(i=0;i<t;i++)
{
suma[i]= suma[i]/(double)(contador[i]);
ind->fitness[i]= suma[i];
qia=suma[i];
aux=aux + suma[i];
}
aux=aux/t;
ind->f=aux;
void borrar_todo(Individuo * lista, int n)
{
int i;
for (i=0;i<n;i++)
destruir_Ind(lista[i]);
}
void copiar_de_a(int * id, Individuo * de, Individuo * a, int n)
{
int i;
for(i=0;i<n;i++)
a[i]=clonar_Ind(id, de[i]);
}
void evaluar_lista(Individuo * lista, unsigned ** x,unsigned filas,unsigned cols, unsigned bandas, int
n)
{
int i;
for (i=0;i<n;i++)
{
evaluar_Ind(&(lista[i]),x,filas,cols,bandas);
}
}
void cruzar_lista(Individuo * lista, unsigned ** x,unsigned filas,unsigned cols, unsigned
bandas,double umb, int a,int n)
{
int i;
double u;
for (i=0;i<n;i++)
{
u=(umb*lista[i].f);
cruzar_Ind(&(lista[i]),u,a);
evaluar_Ind(&(lista[i]),x,filas,cols,bandas);
}
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 51
void mutar_lista(Individuo * lista, unsigned ** x,unsigned filas,unsigned cols, unsigned bandas, int
n,int l)
{
int i;
for (i=0;i<n;i++)
{
mutar_Ind(&(lista[i]),l);
evaluar_Ind(&(lista[i]),x,filas,cols,bandas);
}
}
void Crear_Iniciales(int *id, Individuo * lista,unsigned *iniciales,int k, int n,unsigned ** x,
unsigned filas, unsigned cols, unsigned bandas)
{
int i,j;
unsigned *vector;
Individuo ind;
vector= (unsigned *) malloc (k*sizeof(unsigned));
for(i=0;i<n;i++)
{
for(j=0;j<k;j++)
vector[j]=iniciales[i];
ind=crear_Ind(id,vector,k,8);
evaluar_Ind(&ind,x,filas,cols,bandas);
lista[i]=ind;
}
}
/* dados tres vectores de individuos ("cruzados", "mutados" y "padres")
coloca en "padres" al mejor individuo de cada terna.
*/
void elegir(Individuo * cruzados, Individuo * mutados, Individuo * padres, int n)
{
int i;
for (i=0;i<n;i++)
{
//descartamos mutados
if(cruzados[i].f<mutados[i].f)
{
//cruzados[i] es el mejor iesimo
if(cruzados[i].f<padres[i].f)
{
padres[i]=cruzados[i];
}
}
//descartamos cruzados
else
{
//mutados[i] es el mejor iesimo
if(mutados[i].f<padres[i].f)
{
padres[i]=mutados[i];
}
}
}
}
/* hace evolucionar la población "padres" de "n" individuos cuyos
alelos tienen "l" bits de largo. "id" es el identificador del
proximo individuo a crear, "umb_c" es el umbral relativo para
el cruce, "a" es un parámetro de cruce, "x" es la imagen fuente,
de "filas" filas, "cols" columnas y "bandas" bandas.
*/
void incrementar_generacion(int * id, Individuo * padres, int n, int l, double umb_c, int a, unsigned
** x,unsigned filas,unsigned cols, unsigned bandas)
{
Individuo * cruzados;
Individuo * mutados;
cruzados= (Individuo *) malloc(n*sizeof(Individuo));
mutados= (Individuo *) malloc(n*sizeof(Individuo));
copiar_de_a(id,padres,cruzados,n);
copiar_de_a(id,padres,mutados,n);
cruzar_lista(cruzados,x,filas,cols,bandas,umb_c,a,n);
mutar_lista(mutados,x,filas,cols,bandas,n,l);
}
elegir(cruzados, mutados, padres,n);
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 52
/* Algoritmo de Cofificacion del Codebook
genera el codebook usando un algoritmo genetico de "ngen" generaciones,
con poblacion de "n" individuos y tamaño de alelo "k"
*/
unsigned char ** acc(char * fichero, int n, int k, int ngen, int a)
{
int i,j,l;
// poblacion de individuos
Individuo * lista;
// solucion final
unsigned char ** result;
time_t t;
// contador que sirve para generar el identificador de cada individuo
int id=0;
// numero de filas, columnas y bandas de la imagen fuente
unsigned filas, cols, bandas;
// n vectores (tantos como bandas) con los pixeles de la imagen
unsigned ** x;
// histograma agrupado
unsigned *h;
// vector con los valores de los alelos de la poblacion inicial
unsigned *iniciales;
l=8;
lista= (Individuo *) malloc(n*sizeof(Individuo));
// inicializar los numeros aleatorios
srand((unsigned)time(&t));
// recuperar los datos de la imagen
x = Load(fichero,&filas, &cols,&bandas);
// generar el vector que indica el individuo más ajustado a cada bloque
// tamaño del vector
if(bandas!=0)
{
h=Histograma(x,filas,cols,bandas,k);
iniciales=Iniciales(h,n);
Crear_Iniciales(&id, lista ,iniciales,k,n,x,filas,cols,bandas);
for(i=0;i<ngen;i++)
incrementar_generacion(&id,lista,n,l,1,a,x,filas,cols,bandas);
result= (unsigned char **) malloc (n*sizeof(unsigned char *));
for(i=0;i<n;i++)
{
result[i]=(unsigned char *) malloc (k*sizeof(unsigned char));
for(j=0;j<k;j++)
result[i][j]=lista[i].v[j];
}
}
else//el fichero era incorrecto
{
result= (unsigned char **) malloc (n*sizeof(unsigned char *));
for(i=0;i<n;i++)
{
result[i]=(unsigned char *) malloc (k*sizeof(unsigned char));
for(j=0;j<k;j++)
result[i][j]=0;
}
}
return result;
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 53
int busca_mayor(unsigned * h)
{
int i,indice;
unsigned mayor, aux;
mayor=0;
indice=0;
for(i=0;i<256;i++)
{
if (h[i]>mayor)
{
mayor=h[i];
indice=i;
}
}
if(mayor>0)
{
if(indice>0)//esto es sin suavizar los picos de un elemento
{
aux=mayor;
i=indice-1;
while((i>0)&&(h[i]<aux)&&h[i]!=0)
{
aux=h[i];
h[i]=0;
i--;
}
}
if(indice<255)
{
aux=mayor;
i=indice+1;
while((i<256)&&(h[i]<aux)&&h[i]!=0)
{
aux=h[i];
h[i]=0;
i++;
}
}
/*
if(indice>1)//esto es ignorando los picos de un elemento
{
aux=mayor;
aux2=aux;
i=indice-1;
while((i>0)&&((h[i]<=aux)||(h[i]<=aux2))&&h[i]!=0)
{
aux2=aux;
aux=h[i];
h[i]=0;
i--;
}
}
if(indice<63)
{
aux=mayor;
aux2=mayor;
i=indice+1;
while((i<64)&&((h[i]<=aux)||(h[i]<=aux2))&&h[i]!=0)
{
aux2=aux;
aux=h[i];
h[i]=0;
i++;
}
}
*/
}
else
}
h[indice]=0;
return indice;
return -1;
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 54
unsigned * Iniciales(unsigned * h, int n)
{
unsigned * vector;
int i,j;
int mayor;
int prob;
//
vector=(unsigned *) malloc (n*sizeof(unsigned));
i=0;
vector[0]=32;
while(i<n)
{
mayor=busca_mayor(h);
if(mayor!=-1)
{
vector[i]=mayor;
i++;
}
else
break;
}
if(i<n)
{
j=0;
while(i<n)
{
if(j>=i)
j=0;
prob=rand()%2;
if(prob<1)
{
vector[i]=vector[j];
i++;
}
j++;
}
}
}
return vector;
unsigned * Histograma(unsigned ** x,unsigned numberOfRows, unsigned numberOfCols, unsigned
numberOfBands, int t)
{
unsigned n,b,i,j,r,c,indice;
unsigned * H;
double aux;
long cuenta;
cuenta=0;
H = (unsigned *) malloc (256*sizeof(unsigned));
n=(int)sqrt(t);
for(i=0;i<256;i++)
H[i]=0;
for(b=0;b<numberOfBands;b++)
for(j=n;j<numberOfRows;j=j+n)
for(i=n;i<numberOfCols;i=i+n)
{
aux=0;
for(r=0;r<n;r++)
for(c=0;c<n;c++)
{
indice=((j-r)*(numberOfCols))+(i-c);
aux+=x[b][indice];
}
aux=aux/t;
H[(int)aux]++;
cuenta++;
}
return H;
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Compresión de Imágenes Digitales. Algoritmos Genéticos en VQ. 55
unsigned ** Load (char * fileName, unsigned * numberOfRows, unsigned * numberOfCols, unsigned *
numberOfBands)
{
ILuint userImage;
ILboolean errorCode;
ILuint imageType;
unsigned i,j,b;
unsigned char * pointer;
unsigned ** result;
unsigned nTotal;
//inicializacion
ilInit();
ilGenImages(1,&userImage);
ilBindImage(userImage);
// Loads a BMP image from disk
errorCode = ilLoad(IL_BMP,fileName);
if (errorCode ==1) {
imageType = ilGetInteger(IL_IMAGE_TYPE);
ilEnable(IL_CONV_PAL);
*numberOfRows = ilGetInteger(IL_IMAGE_HEIGHT);
*numberOfCols = ilGetInteger(IL_IMAGE_WIDTH);
*numberOfBands = ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
nTotal=(*numberOfRows) * (*numberOfCols) * (*numberOfBands);
switch (*numberOfBands) {
case 1:
ilConvertImage(IL_LUMINANCE,IL_UNSIGNED_BYTE);
break;
case 3:
ilConvertImage(IL_RGB,IL_UNSIGNED_BYTE);
ilConvertPal(IL_PAL_RGB24);
break;
default:
printf("Numero de bandas inapropiado");
}
// Gets DevIL image data start position
pointer = ilGetData();
// result is an array of size "numberOfBands"
result= (unsigned **) malloc ((sizeof(unsigned *))*(*numberOfBands));
// each band has an array of size "cols*rows"
for (i=0;i<(*numberOfBands);i++)
result[i]=(unsigned *) malloc ((sizeof(unsigned
))*(*numberOfCols)*(*numberOfRows));
// result is filled
for(b=0;b<(*numberOfBands);b++)
for(j=0;j<(*numberOfRows);j++)
for(i=0;i<(*numberOfCols);i++)
result[b][(j*(*numberOfCols))+i]=
(unsigned)pointer[(((*numberOfRows)-j1)*(*numberOfCols)*(*numberOfBands))+(i*(*numberOfBands))+b];
}
else
{
*numberOfBands=0;
}
return result;
}
PID. Curso 02/03. Manuel Blanco Guisado. David Martínez González. Raúl Palomino Sánchez.
Descargar