Compresión de imágenes usando la codificación Huffman

La codificación Huffman es uno de los métodos de compresión básicos, que ha demostrado ser útil en los estándares de compresión de imágenes y videos. Al aplicar la técnica de codificación de Huffman en una imagen, los símbolos de origen pueden ser intensidades de píxeles de la imagen o la salida de una función de mapeo de intensidad.

Prerrequisitos: Codificación Huffman | Manejo de archivos

El primer paso de la técnica de codificación de Huffman es reducir la imagen de entrada a un histograma ordenado, donde la probabilidad de ocurrencia de un cierto valor de intensidad de píxel es como

 prob_pixel = numpix/totalnum

donde numpix es el número de aparición de un píxel con un determinado valor de intensidad y totalnum es el número total de píxeles en la imagen de entrada.

Tomemos una imagen de 8 X 8

Los valores de intensidad de píxel son:

Esta imagen contiene 46 valores de intensidad de píxel distintos, por lo tanto, tendremos 46 palabras de código Huffman únicas.

Es evidente que no todos los valores de intensidad de píxel pueden estar presentes en la imagen y, por lo tanto, no tendrán una probabilidad de ocurrencia distinta de cero.

A partir de aquí, los valores de intensidad de píxel en la imagen de entrada se abordarán como Nodes hoja.

Ahora, hay 2 pasos esenciales para construir un árbol de Huffman:

  1. Construye un árbol de Huffman:
    1. Combine los dos Nodes hoja de menor probabilidad en un nuevo Node.
    2. Reemplace los dos Nodes hoja por el nuevo Node y ordene los Nodes de acuerdo con los nuevos valores de probabilidad.
    3. Continúe con los pasos (a) y (b) hasta que obtengamos un solo Node con un valor de probabilidad de 1.0. Llamaremos a este Node como raíz.
  2. Retroceda desde la raíz, asignando ‘0’ o ‘1’ a cada Node intermedio, hasta llegar a los Nodes hoja

En este ejemplo, asignaremos ‘0’ al Node secundario izquierdo y ‘1’ al derecho.

Ahora, veamos la implementación:
Paso 1:
lea la imagen en una array 2D ( imagen )
Si la imagen está en formato .bmp , entonces la imagen se puede leer en la array 2D, utilizando este código proporcionado en este enlace aquí .

int i, j;
char filename[] = "Input_Image.bmp";
int data = 0, offset, bpp = 0, width, height;
long bmpsize = 0, bmpdataoff = 0;
int** image;
int temp = 0;
   
// Reading the BMP File
FILE* image_file;
image_file = fopen(filename, "rb");
if (image_file == NULL)
{
    printf("Error Opening File!!");
    exit(1);
}
else 
{
  
    // Set file position of the 
    // stream to the beginning
    // Contains file signature 
    // or ID "BM"
    offset = 0;
      
    // Set offset to 2, which 
    // contains size of BMP File
    offset = 2;
      
    fseek(image_file, offset, SEEK_SET);
      
    // Getting size of BMP File
    fread(&bmpsize, 4, 1, image_file);
      
    // Getting offset where the
    // pixel array starts
    // Since the information 
    // is at offset 10 from 
    // the start, as given 
    // in BMP Header
    offset = 10; 
      
    fseek(image_file, offset, SEEK_SET);
      
    // Bitmap data offset
    fread(&bmpdataoff, 4, 1, image_file);
      
    // Getting height and width of the image
    // Width is stored at offset 18 and height
    // at offset 22, each of 4 bytes
    fseek(image_file, 18, SEEK_SET);
      
    fread(&width, 4, 1, image_file);
      
    fread(&height, 4, 1, image_file);
      
    // Number of bits per pixel
    fseek(image_file, 2, SEEK_CUR);
      
    fread(&bpp, 2, 1, image_file);
      
    // Setting offset to start of pixel data
    fseek(image_file, bmpdataoff, SEEK_SET);
      
    // Creating Image array
    image = (int**)malloc(height * sizeof(int*));
    for (i = 0; i < height; i++)
    {
        image[i] = (int*)malloc(width * sizeof(int));
    }
      
    // int image[height][width] 
    // can also be done
    // Number of bytes in the 
    // Image pixel array
    int numbytes = (bmpsize - bmpdataoff) / 3; 
      
    // Reading the BMP File 
    // into Image Array
    for (i = 0; i < height; i++) 
    {
        for (j = 0; j < width; j++)
        {
            fread(&temp, 3, 1, image_file);
              
            // the Image is a 
            // 24-bit BMP Image
            temp = temp & 0x0000FF; 
            image[i][j] = temp;
        }
    }
}

Cree un histograma de los valores de intensidad de píxeles presentes en la imagen

// Creating the Histogram
int hist[256];
  
for (i = 0; i < 256; i++)
    hist[i] = 0;
  
for (i = 0; i < height; i++)
    for (j = 0; j < width; j++)
        hist[image[i][j]] += 1;

Encuentre el número de valores de intensidad de píxel que tienen una probabilidad de ocurrencia distinta de cero
. Dado que los valores de intensidad de píxel varían de 0 a 255, y es posible que no todos los valores de intensidad de píxel estén presentes en la imagen (como se desprende del histograma y también de la array de imagen). ) y, por lo tanto, no tendrá una probabilidad de ocurrencia distinta de cero. También otro propósito de este paso es que la cantidad de valores de intensidad de píxeles que tienen valores de probabilidad distintos de cero nos dará la cantidad de Nodes de hoja en la imagen.

// Finding number of 
// non-zero occurrences
int nodes = 0;
for (i = 0; i < 256; i++) 
{
    if (hist[i] != 0)
        nodes += 1;
}

Cálculo de la longitud máxima de las palabras de código de Huffman
Como lo muestran YSAbu-Mostafa y RJMcEliece en su artículo «Longitudes máximas de palabra de código en los códigos de Huffman» , que, si p > 1/F_{K+3}, entonces en cualquier código de prefijo eficiente para una fuente cuya probabilidad mínima es p, la palabra de código más larga la longitud es como máximo K & Si p \leq 1/F_{K+2}, existe una fuente cuya probabilidad más pequeña es p, y que tiene un código de Huffman cuya palabra más larga tiene una longitud K. Si p < 1/F_{K+2}, existe una fuente para la cual cada código óptimo tiene una palabra más larga de longitud K
Aquí, está F_{K}el K^{th}número de Fibonacci.

Gallager [1] noted that every Huffman tree is efficient, but in fact it is easy to see more
generally that every optimal tree is efficient

La serie de Fibonacci es: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …

En nuestro ejemplo, la probabilidad más baja (p) es 0.015625

Por eso,

 1/p = 64
For K = 9,
F(K+2) = F(11) = 55
F(K+3) = F(12) = 89

Por lo tanto,

1/F(K+3) < p < 1/F(K+2)
Hence optimal length of code is K=9
// Calculating max length 
// of Huffman code word
i = 0;
while ((1 / p) < fib(i))
    i++;
int maxcodelen = i - 3;
// Function for getting Fibonacci
// numbers defined outside main
int fib(int n)
{
    if (n <= 1)
        return n;
    return fib(n - 1) + fib(n - 2);
}

Paso 2
Defina una estructura que contendrá los valores de intensidad de píxeles ( pix ), sus probabilidades correspondientes ( frecuencia ), el puntero a los Nodes secundarios izquierdo ( *izquierda ) y derecho( *derecha ) y también la array de strings para la palabra clave de Huffman ( código ).

Estas estructuras se definen dentro de main() , para usar la longitud máxima del código ( maxcodelen ) para declarar el campo de array de código de la estructura pixfreq

// Defining Structures pixfreq
struct pixfreq 
{
    int pix;
    float freq;
    struct pixfreq *left, *right;
    char code[maxcodelen];
};

Paso 3
Defina otra Struct que contendrá los valores de intensidad de píxeles ( pix ), sus probabilidades correspondientes ( freq ) y un campo adicional, que se utilizará para almacenar la posición de los nuevos Nodes generados ( arrloc ).

// Defining Structures huffcode
struct huffcode
 {
    int pix, arrloc;
    float freq;
};

Paso 4
Declarar una array de estructuras . Cada elemento de la array corresponde a un Node en el árbol de Huffman.

// Declaring structs
struct pixfreq* pix_freq;
struct huffcode* huffcodes;

¿Por qué usar dos arrays de estructura?

Inicialmente, la array struct pix_freq , así como la array struct huffcodes solo contendrán la información de todos los Nodes hoja en el Huffman Tree.

La array struct pix_freq se usará para almacenar todos los Nodes del árbol de Huffman y la array huffcodes se usará como el árbol actualizado (y ordenado).

Recuerde que solo se ordenarán los huffcodes en cada iteración, y no pix_freq

Los nuevos Nodes creados al combinar dos Nodes de frecuencia más baja, en cada iteración, se agregarán al final de la array pix_freq y también a la array huffcodes .

Pero la array huffcodes se ordenará nuevamente de acuerdo con la probabilidad de ocurrencia, después de agregarle el nuevo Node.

La posición del nuevo Node en la array pix_freq se almacenará en el campo arrloc de la estructura huffcode .
El campo arrloc se utilizará al asignar el puntero al elemento secundario izquierdo y derecho de un nuevo Node.

Paso 4 continuación…

Ahora, si hay un número N de Nodes hoja, el número total de Nodes en todo el árbol de Huffman será igual a 2N-1

Y después de combinar dos Nodes y reemplazarlos por el nuevo Node principal , la cantidad de Nodes disminuye en 1 en cada iteración. Por lo tanto, es suficiente tener una longitud de Nodes para la array huffcodes , que se usará como los Nodes de Huffman actualizados y ordenados.

int totalnodes = 2 * nodes - 1;
pix_freq = (struct pixfreq*)malloc(sizeof(struct pixfreq) * totalnodes);
huffcodes = (struct huffcode*)malloc(sizeof(struct huffcode) * nodes);

Paso 5
Inicialice las dos arrays pix_freq y huffcodes con información de los Nodes hoja.

j = 0;
int totpix = height * width;
float tempprob;
for (i = 0; i < 256; i++) 
{
    if (hist[i] != 0)
    {
          
        // pixel intensity value
        huffcodes[j].pix = i; 
        pix_freq[j].pix = i;
          
        // location of the node
        // in the pix_freq array
        huffcodes[j].arrloc = j; 
          
        // probability of occurrence
        tempprob = (float)hist[i] / (float)totpix; 
        pix_freq[j].freq = tempprob;
        huffcodes[j].freq = tempprob;
          
        // Declaring the child of 
        // leaf node as NULL pointer
        pix_freq[j].left = NULL; 
        pix_freq[j].right = NULL;
          
        // initializing the code
        // word as end of line
        pix_freq[j].code[0] = '\0'; 
        j++;
    }
}

Paso 6
Ordenar la array de huffcodes según la probabilidad de ocurrencia de los valores de intensidad de píxel

Tenga en cuenta que es necesario ordenar la array huffcodes , pero no la array pix_freq , ya que estamos almacenando la ubicación de los valores de píxel en el campo arrloc de la array huffcodes .

// Sorting the histogram
struct huffcode temphuff;
  
// Sorting w.r.t probability 
// of occurrence
for (i = 0; i < nodes; i++)
 {
    for (j = i + 1; j < nodes; j++) 
{
        if (huffcodes[i].freq < huffcodes[j].freq) 
{
            temphuff = huffcodes[i];
            huffcodes[i] = huffcodes[j];
            huffcodes[j] = temphuff;
        }
    }
}

Paso 7
Construyendo el árbol de Huffman

Comenzamos combinando los dos Nodes con las probabilidades de ocurrencia más bajas y luego reemplazando los dos Nodes por el nuevo Node. Este proceso continúa hasta que tenemos un Node raíz . El primer Node principal formado se almacenará en los Nodes de índice en la array pix_freq y los Nodes principales posteriores obtenidos se almacenarán en valores más altos de índice.

// Building Huffman Tree
  
float sumprob;
int sumpix;
int n = 0, k = 0;
int nextnode = nodes;
  
// Since total number of 
// nodes in Huffman Tree 
// is 2*nodes-1
while (n < nodes - 1) 
{
      
    // Adding the lowest 
    // two probabilities
    sumprob = huffcodes[nodes - n - 1].freq + huffcodes[nodes - n - 2].freq;
    sumpix = huffcodes[nodes - n - 1].pix + huffcodes[nodes - n - 2].pix;
      
    // Appending to the pix_freq Array
    pix_freq[nextnode].pix = sumpix;
    pix_freq[nextnode].freq = sumprob;
    pix_freq[nextnode].left = &pix_freq[huffcodes[nodes - n - 2].arrloc];
      
    // arrloc points to the location
    // of the child node in the
    // pix_freq array
    pix_freq[nextnode].right = &pix_freq[huffcodes[nodes - n - 1].arrloc];
    pix_freq[nextnode].code[0] = '\0';
      
    // Using sum of the pixel values as 
    // new representation for the new node
    // since unlike strings, we cannot 
    // concatenate because the pixel values 
    // are stored as integers. However, if we
    // store the pixel values as strings
    // we can use the concatenated string as 
    // a representation of the new node.
    i = 0;
      
    // Sorting and Updating the huffcodes 
    // array simultaneously New position
    // of the combined node
    while (sumprob <= huffcodes[i].freq)
        i++;
          
    // Inserting the new node in
    // the huffcodes array
    for (k = nnz; k >= 0; k--) 
    {
        if (k == i)
        {
            huffcodes[k].pix = sumpix;
            huffcodes[k].freq = sumprob;
            huffcodes[k].arrloc = nextnode;
        }
        else if (k > i)
          
            // Shifting the nodes below
            // the new node by 1
            // For inserting the new node 
            // at the updated position k
            huffcodes[k] = huffcodes[k - 1];
    }
    n += 1;
    nextnode += 1;
}

¿Cómo funciona este código?

Veámoslo con un ejemplo:

Inicialmente

Después de la primera iteración

Como puede ver, después de la primera iteración, el nuevo Node se agregó a la array pix_freq y su índice es 46. Y en huffcode, el nuevo Node se agregó en su nueva posición después de la clasificación, y el arrloc apunta al índice. del nuevo Node en la array pix_freq . Además, tenga en cuenta que todos los elementos de la array después del nuevo Node (en el índice 11) en la array huffcodes se han desplazado en 1 y el elemento de la array con el valor de píxel 188 se excluye en la array actualizada.

Ahora, en la próxima (2da) iteración se combinarán 170 y 174, ya que 175 y 188 ya se combinaron.
Índice de los dos Nodes más bajos en términos de los Nodes variables y n es

left_child_index=(nodes-n-2)

y

right_child_index=(nodes-n-1)

En la segunda iteración, el valor de n es 1 (ya que n comienza desde 0).

Para Node con valor 170

 left_child_index=46-1-2=43

Para Node con valor 174

 right_child_index=46-1-1=44

Por lo tanto, incluso si 175 sigue siendo el último elemento de la array actualizada, se excluirá.

Otra cosa a tener en cuenta en este código es que, si en cualquier iteración posterior, el nuevo Node formado en la primera iteración es el hijo de otro nuevo Node, entonces se puede acceder al puntero del nuevo Node obtenido en la primera iteración usando el arrloc almacenado en la array huffcodes , como se hace en esta línea de código

pix_freq[nextnode].right = &pix_freq[huffcodes[nodes - n - 1].arrloc];

Paso 8
Retroceda desde la raíz hasta los Nodes hoja para asignar palabras de código

Comenzando desde la raíz, asignamos ‘0’ al Node secundario izquierdo y ‘1’ al Node secundario derecho.

Ahora, dado que estábamos agregando los Nodes recién formados a la array pix_freq , se espera que la raíz sea el último elemento de la array en el índice totalnodes-1 .

Por lo tanto, comenzamos desde el último índice e iteramos sobre la array, asignando palabras de código a los Nodes secundarios izquierdo y derecho, hasta llegar al primer Node principal formado en los Nodes de índice . No iteramos sobre los Nodes de hoja ya que esos Nodes tienen punteros NULL como su hijo izquierdo y derecho.

// Assigning Code through backtracking
char left = '0';
char right = '1';
int index;
for (i = totalnodes - 1; i >= nodes; i--) {
    if (pix_freq[i].left != NULL) {
        strconcat(pix_freq[i].left->code, pix_freq[i].code, left);
    }
    if (pix_freq[i].right != NULL) {
        strconcat(pix_freq[i].right->code, pix_freq[i].code, right);
    }
}
void strconcat(char* str, char* parentcode, char add)
{
    int i = 0;
    while (*(parentcode + i) != '\0') {
        *(str + i) = *(parentcode + i);
        i++;
    }
    str[i] = add;
    str[i + 1] = '\0';
}

Paso final
Codificar la imagen

// Encode the Image
int pix_val;
  
// Writing the Huffman encoded
//  Image into a text file
FILE* imagehuff = fopen("encoded_image.txt", "wb");
for (r = 0; r < height; r++)
    for (c = 0; c < width; c++) {
        pix_val = image[r];
        for (i = 0; i < nodes; i++)
            if (pix_val == pix_freq[i].pix)
                fprintf(imagehuff, "%s", pix_freq[i].code);
    }
fclose(imagehuff);
  
// Printing Huffman Codes
printf("Huffmann Codes::\n\n");
printf("pixel values ->   Code\n\n");
for (i = 0; i < nodes; i++) {
    if (snprintf(NULL, 0, "%d", pix_freq[i].pix) == 2)
        printf("     %d      -> %s\n", pix_freq[i].pix, pix_freq[i].code);
    else
        printf("    %d      -> %s\n", pix_freq[i].pix, pix_freq[i].code);
}

Otro punto importante a tener en cuenta
Número promedio de bits necesarios para representar cada píxel.

// Calculating Average number of bits
float avgbitnum = 0;
for (i = 0; i < nodes; i++)
    avgbitnum += pix_freq[i].freq * codelen(pix_freq[i].code);

La función codelen calcula la longitud de las palabras clave O el número de bits necesarios para representar el píxel.

int codelen(char* code)
{
    int l = 0;
    while (*(code + l) != '\0')
        l++;
    return l;
}

Para esta imagen de ejemplo específica

Average number of bits = 5.343750

Los resultados impresos para la imagen de ejemplo

    pixel values -> Code
         72      -> 011001
         75      -> 010100
         79      -> 110111
         83      -> 011010
         84      -> 00100
         87      -> 011100
         89      -> 010000
         93      -> 010111
         94      -> 00011
         96      -> 101010
         98      -> 101110
        100      -> 000101
        102      -> 0001000
        103      -> 0001001
        105      -> 110110
        106      -> 00110
        110      -> 110100
        114      -> 110101
        115      -> 1100
        118      -> 011011
        119      -> 011000
        122      -> 1110
        124      -> 011110
        125      -> 011111
        127      -> 0000
        128      -> 011101
        130      -> 010010
        131      -> 010011
        136      -> 00111
        138      -> 010001
        139      -> 010110
        140      -> 1111
        142      -> 00101
        143      -> 010101
        146      -> 10010
        148      -> 101011
        149      -> 101000
        153      -> 101001
        155      -> 10011
        163      -> 101111
        167      -> 101100
        169      -> 101101
        170      -> 100010
        174      -> 100011
        175      -> 100000
        188      -> 100001

Imagen codificada:

0111010101000110011101101010001011010000000101111
00010001101000100100100100010010101011001101110111001
00000001100111101010010101100001111000110110111110010
10110001000000010110000001100001100001110011011110000
10011001101111111000100101111100010100011110000111000
01101001110101111100000111101100001110010010110101000
0111101001100101101001010111

Esta imagen codificada tiene una longitud de 342 bits, mientras que el número total de bits en la imagen original es de 512 bits. (64 píxeles cada uno de 8 bits).

Image Compression Code

// C Code for
// Image Compression
#include <stdio.h>
#include <stdlib.h>
  
// function to calculate word length 
int codelen(char* code)
{
    int l = 0;
    while (*(code + l) != '\0')
        l++;
    return l;
}
   
// function to concatenate the words
void strconcat(char* str, char* parentcode, char add)
{
    int i = 0;
    while (*(parentcode + i) != '\0') 
    {
        *(str + i) = *(parentcode + i);
        i++;
    }
    if (add != '2') 
    {
        str[i] = add;
        str[i + 1] = '\0';
    }
    else
        str[i] = '\0';
}
  
// function to find fibonacci number 
int fib(int n)
{
    if (n <= 1)
        return n;
    return fib(n - 1) + fib(n - 2);
}
   
// Driver code
int main()
{
    int i, j;
    char filename[] = "Input_Image.bmp";
    int data = 0, offset, bpp = 0, width, height;
    long bmpsize = 0, bmpdataoff = 0;
    int** image;
    int temp = 0;
   
    // Reading the BMP File
    FILE* image_file;
      
    image_file = fopen(filename, "rb");
    if (image_file == NULL) 
    {
        printf("Error Opening File!!");
        exit(1);
    }
    else
    {
          
        // Set file position of the 
        // stream to the beginning
        // Contains file signature 
        // or ID "BM"
        offset = 0; 
          
        // Set offset to 2, which 
        // contains size of BMP File
        offset = 2;
          
        fseek(image_file, offset, SEEK_SET);
          
        // Getting size of BMP File
        fread(&bmpsize, 4, 1, image_file);
          
        // Getting offset where the
        // pixel array starts
        // Since the information is 
        // at offset 10 from the start, 
        // as given in BMP Header
        offset = 10; 
          
        fseek(image_file, offset, SEEK_SET);
          
        // Bitmap data offset
        fread(&bmpdataoff, 4, 1, image_file);
          
        // Getting height and width of the image
        // Width is stored at offset 18 and 
        // height at offset 22, each of 4 bytes
        fseek(image_file, 18, SEEK_SET);
          
        fread(&width, 4, 1, image_file);
          
        fread(&height, 4, 1, image_file);
          
        // Number of bits per pixel
        fseek(image_file, 2, SEEK_CUR);
          
        fread(&bpp, 2, 1, image_file);
          
        // Setting offset to start of pixel data
        fseek(image_file, bmpdataoff, SEEK_SET);
          
        // Creating Image array
        image = (int**)malloc(height * sizeof(int*));
          
        for (i = 0; i < height; i++)
        {
            image[i] = (int*)malloc(width * sizeof(int));
        }
          
        // int image[height][width]
        // can also be done
        // Number of bytes in 
        // the Image pixel array
        int numbytes = (bmpsize - bmpdataoff) / 3; 
          
        // Reading the BMP File
        // into Image Array
        for (i = 0; i < height; i++) 
        {
            for (j = 0; j < width; j++) 
            {
                fread(&temp, 3, 1, image_file);
                  
                // the Image is a 
                // 24-bit BMP Image
                temp = temp & 0x0000FF; 
                image[i][j] = temp;
            }
        }
    }
      
    // Finding the probability
    // of occurrence
    int hist[256];
    for (i = 0; i < 256; i++)
        hist[i] = 0;
    for (i = 0; i < height; i++)
        for (j = 0; j < width; j++)
            hist[image[i][j]] += 1;
              
    // Finding number of 
    // non-zero occurrences
    int nodes = 0;
    for (i = 0; i < 256; i++)
        if (hist[i] != 0)
            nodes += 1;
              
    // Calculating minimum probability
    float p = 1.0, ptemp;
    for (i = 0; i < 256; i++) 
    {
        ptemp = (hist[i] / (float)(height * width));
        if (ptemp > 0 && ptemp <= p)
            p = ptemp;
    }
      
    // Calculating max length
    // of code word
    i = 0;
    while ((1 / p) > fib(i))
        i++;
    int maxcodelen = i - 3;
      
    // Defining Structures pixfreq
    struct pixfreq
    {
        int pix, larrloc, rarrloc;
        float freq;
        struct pixfreq *left, *right;
        char code[maxcodelen];
    };
      
    // Defining Structures
    // huffcode
    struct huffcode 
    {
        int pix, arrloc;
        float freq;
    };
      
    // Declaring structs
    struct pixfreq* pix_freq;
    struct huffcode* huffcodes;
    int totalnodes = 2 * nodes - 1;
    pix_freq = (struct pixfreq*)malloc(sizeof(struct pixfreq) * totalnodes);
    huffcodes = (struct huffcode*)malloc(sizeof(struct huffcode) * nodes);
      
    // Initializing
    j = 0;
    int totpix = height * width;
    float tempprob;
    for (i = 0; i < 256; i++)
    {
        if (hist[i] != 0) 
        {
              
            // pixel intensity value
            huffcodes[j].pix = i; 
            pix_freq[j].pix = i;
              
            // location of the node
            // in the pix_freq array
            huffcodes[j].arrloc = j;
              
            // probability of occurrence
            tempprob = (float)hist[i] / (float)totpix; 
            pix_freq[j].freq = tempprob;
            huffcodes[j].freq = tempprob;
              
            // Declaring the child of leaf 
            // node as NULL pointer
            pix_freq[j].left = NULL; 
            pix_freq[j].right = NULL;
              
            // initializing the code 
            // word as end of line
            pix_freq[j].code[0] = '\0'; 
            j++;
        }
    }
      
    // Sorting the histogram
    struct huffcode temphuff;
      
    // Sorting w.r.t probability 
    // of occurrence
    for (i = 0; i < nodes; i++)
    {
        for (j = i + 1; j < nodes; j++)
        {
            if (huffcodes[i].freq < huffcodes[j].freq) 
            {
                temphuff = huffcodes[i];
                huffcodes[i] = huffcodes[j];
                huffcodes[j] = temphuff;
            }
        }
    }
      
    // Building Huffman Tree
    float sumprob;
    int sumpix;
    int n = 0, k = 0;
    int nextnode = nodes;
      
    // Since total number of 
    // nodes in Huffman Tree 
    // is 2*nodes-1
    while (n < nodes - 1) 
    {
          
        // Adding the lowest two probabilities
        sumprob = huffcodes[nodes - n - 1].freq + huffcodes[nodes - n - 2].freq;
        sumpix = huffcodes[nodes - n - 1].pix + huffcodes[nodes - n - 2].pix;
          
        // Appending to the pix_freq Array
        pix_freq[nextnode].pix = sumpix;
        pix_freq[nextnode].freq = sumprob;
        pix_freq[nextnode].left = &pix_freq[huffcodes[nodes - n - 2].arrloc];
        pix_freq[nextnode].right = &pix_freq[huffcodes[nodes - n - 1].arrloc];
        pix_freq[nextnode].code[0] = '\0';
        i = 0;
          
        // Sorting and Updating the 
        // huffcodes array simultaneously
        // New position of the combined node
        while (sumprob <= huffcodes[i].freq)
              i++;
              
        // Inserting the new node 
        // in the huffcodes array
        for (k = nodes; k >= 0; k--) 
        {
            if (k == i)
            {
                huffcodes[k].pix = sumpix;
                huffcodes[k].freq = sumprob;
                huffcodes[k].arrloc = nextnode;
            }
            else if (k > i)
              
                // Shifting the nodes below 
                // the new node by 1
                // For inserting the new node
                // at the updated position k
                huffcodes[k] = huffcodes[k - 1];
              
        }
        n += 1;
        nextnode += 1;
    }
      
    // Assigning Code through
    // backtracking
    char left = '0';
    char right = '1';
    int index;
    for (i = totalnodes - 1; i >= nodes; i--) 
    {
        if (pix_freq[i].left != NULL)
            strconcat(pix_freq[i].left->code, pix_freq[i].code, left);
        if (pix_freq[i].right != NULL)
            strconcat(pix_freq[i].right->code, pix_freq[i].code, right);
    }
      
    // Encode the Image
    int pix_val;
    int l;
      
    // Writing the Huffman encoded
    // Image into a text file
    FILE* imagehuff = fopen("encoded_image.txt", "wb");
    for (i = 0; i < height; i++)
        for (j = 0; j < width; j++) 
        {
            pix_val = image[i][j];
            for (l = 0; l < nodes; l++)
                if (pix_val == pix_freq[l].pix)
                    fprintf(imagehuff, "%s", pix_freq[l].code);
        }
          
    // Printing Huffman Codes
    printf("Huffmann Codes::\n\n");
    printf("pixel values ->   Code\n\n");
    for (i = 0; i < nodes; i++) {
        if (snprintf(NULL, 0, "%d", pix_freq[i].pix) == 2)
            printf("     %d      -> %s\n", pix_freq[i].pix, pix_freq[i].code);
        else
            printf("    %d      -> %s\n", pix_freq[i].pix, pix_freq[i].code);
    }
      
    // Calculating Average Bit Length
    float avgbitnum = 0;
    for (i = 0; i < nodes; i++)
        avgbitnum += pix_freq[i].freq * codelen(pix_freq[i].code);
    printf("Average number of bits:: %f", avgbitnum);
}

Publicación traducida automáticamente

Artículo escrito por SiladittyaManna y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *