Cómo leer una imagen en formato PGMB en C

El archivo PGM o Portable Gray Map es una imagen en escala de grises donde cada píxel está codificado con 1 o 2 bytes. Contiene información de encabezado y valores de escala de grises de píxeles en forma de array.

Planteamiento: La idea que se sigue para leer la imagen en formato PGMB es la siguiente:

  • Abra una PGMB (imagen PGM en formato binario).
  • Extraiga la información de píxeles, que luego se puede utilizar para su posterior procesamiento.
  • La información del encabezado se almacena en formato ASCII y se puede leer con cualquier editor de texto, pero la información de los píxeles se almacena en una formación binaria y el editor de texto lo mostrará como un texto incomprensible.

A continuación se muestra la imagen pgm de muestra.

Información del encabezado :

  • número mágico para identificar el tipo de archivo:
    • Archivo binario PGM (PGMB): “P5”
    • Archivo ASCII PGM (PGMA): “P2”
  • Ancho en formato decimal ASCII
  • Altura en formato decimal ASCII
  • Valor gris máximo , formato decimal ASCII, entre 0-255
  • Puede contener comentarios, indicados al comenzar la línea con un ‘#’
  • Todo separado con espacios en blanco (espacios en blanco, tabulaciones, CR, LF)

Información del encabezado en gfg_logo.pgm:

P5
# sample PGMB image
# gfg_logo.pgm
200 200
255

Después de la información del encabezado, hay una cuadrícula de dimensiones alto * peso que contiene los valores de píxeles en escala de grises de la imagen en formato binario.

Lectura de imagen PGMB :

  • Abra la imagen en modo binario de lectura, rb .
  • Compruebe si hay algún comentario presente e ignórelo.
  • Lee el Número Mágico .
  • Lea cualquier comentario/línea en blanco/espacio en blanco.
  • Leer ancho y alto separados por espacios en blanco.
  • Lea el valor máximo de gris, antes y después de cualquier espacio en blanco/comentario.
  • Lea la cuadrícula (ancho * alto) de valores de píxeles, separados por espacios en blanco.

A continuación se muestra el programa para el enfoque anterior:

C

// C Program to read a PGMB image
// and print its parameters
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
// Structure for storing the
// image data
typedef struct PGMImage {
    char pgmType[3];
    unsigned char** data;
    unsigned int width;
    unsigned int height;
    unsigned int maxValue;
} PGMImage;
 
// Function to ignore any comments
// in file
void ignoreComments(FILE* fp)
{
    int ch;
    char line[100];
 
    // Ignore any blank lines
    while ((ch = fgetc(fp)) != EOF
           && isspace(ch))
        ;
 
    // Recursively ignore comments
    // in a PGM image commented lines
    // start with a '#'
    if (ch == '#') {
        fgets(line, sizeof(line), fp);
        ignoreComments(fp);
    }
    else
        fseek(fp, -1, SEEK_CUR);
}
 
// Function to open the input a PGM
// file and process it
bool openPGM(PGMImage* pgm,
             const char* filename)
{
    // Open the image file in the
    // 'read binary' mode
    FILE* pgmfile
        = fopen(filename, "rb");
 
    // If file does not exist,
    // then return
    if (pgmfile == NULL) {
        printf("File does not exist\n");
        return false;
    }
 
    ignoreComments(pgmfile);
    fscanf(pgmfile, "%s",
           pgm->pgmType);
 
    // Check for correct PGM Binary
    // file type
    if (strcmp(pgm->pgmType, "P5")) {
        fprintf(stderr,
                "Wrong file type!\n");
        exit(EXIT_FAILURE);
    }
 
    ignoreComments(pgmfile);
 
    // Read the image dimensions
    fscanf(pgmfile, "%d %d",
           &(pgm->width),
           &(pgm->height));
 
    ignoreComments(pgmfile);
 
    // Read maximum gray value
    fscanf(pgmfile, "%d", &(pgm->maxValue));
    ignoreComments(pgmfile);
 
    // Allocating memory to store
    // img info in defined struct
    pgm->data
        = malloc(pgm->height
                 * sizeof(unsigned char*));
 
    // Storing the pixel info in
    // the struct
    if (pgm->pgmType[1] == '5') {
 
        fgetc(pgmfile);
 
        for (int i = 0;
             i < pgm->height; i++) {
            pgm->data[i]
                = malloc(pgm->width
                         * sizeof(unsigned char));
 
            // If memory allocation
            // is failed
            if (pgm->data[i] == NULL) {
                fprintf(stderr,
                        "malloc failed\n");
                exit(1);
            }
 
            // Read the gray values and
            // write on allocated memory
            fread(pgm->data[i],
                  sizeof(unsigned char),
                  pgm->width, pgmfile);
        }
    }
 
    // Close the file
    fclose(pgmfile);
 
    return true;
}
 
// Function to print the file details
void printImageDetails(PGMImage* pgm,
                       const char* filename)
{
    FILE* pgmfile = fopen(filename, "rb");
 
    // Retrieving the file extension
    char* ext = strrchr(filename, '.');
 
    if (!ext)
        printf("No extension found"
               "in file %s",
               filename);
    else
        printf("File format"
               "    : %s\n",
               ext + 1);
 
    printf("PGM File type  : %s\n",
           pgm->pgmType);
 
    // Print type of PGM file, in ascii
    // and binary format
    if (!strcmp(pgm->pgmType, "P2"))
        printf("PGM File Format:"
               "ASCII\n");
    else if (!strcmp(pgm->pgmType,
                     "P5"))
        printf("PGM File Format:"
               " Binary\n");
 
    printf("Width of img   : %d px\n",
           pgm->width);
    printf("Height of img  : %d px\n",
           pgm->height);
    printf("Max Gray value : %d\n",
           pgm->maxValue);
 
    // close file
    fclose(pgmfile);
}
 
// Driver Code
int main(int argc, char const* argv[])
{
    PGMImage* pgm = malloc(sizeof(PGMImage));
    const char* ipfile;
 
    if (argc == 2)
        ipfile = argv[1];
    else
        ipfile = "gfg_logo.pgm";
 
    printf("\tip file : %s\n", ipfile);
 
    // Process the image and print
    // its details
    if (openPGM(pgm, ipfile))
        printImageDetails(pgm, ipfile);
 
    return 0;
}

Producción:

Explicación:

  • Cree una estructura para almacenar los detalles de la imagen PGMB y asigne memoria para la misma.
  • Tome la entrada del nombre del archivo ya sea como un argumento de la línea de comandos o codificándolo en el programa.
  • La función openPGM() procesa los archivos de imagen de entrada y toma el puntero de memoria y el nombre del archivo.
  • La función ignoreComments() se usa para omitir cualquier comentario en el archivo. Los comentarios suelen estar presentes en la parte del encabezado y, por lo tanto, los buscamos después de leer cada propiedad.
  • En la función openPGM() , lea la información del encabezado del archivo, es decir. tipo de archivo, altura, peso, etc. como se indicó anteriormente.
  • Luego asigne memoria según la altura de la imagen y para cada fila, asigne memoria para el ancho de la imagen.
  • El método fread() lee los valores grises y los almacena en la memoria asignada para la array de caracteres 2d de la estructura pgm .
  • printImageDetails() se utiliza para imprimir los valores recuperados del archivo de imagen PGMB. 

Publicación traducida automáticamente

Artículo escrito por the_alphaEye 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 *