📜  如何用C读取PGMB格式的图像

📅  最后修改于: 2021-05-26 02:47:14             🧑  作者: Mango

PGM或可移植灰度图文件是一种灰度图像,其中每个像素都使用1或2个字节进行编码。它以矩阵形式包含标题信息和像素灰度值。

方法:遵循的思想是读取PGMB格式的图像如下:

  • 打开PGMB(二进制格式的PGM图像)。
  • 提取像素信息,然后可以将其用于进一步处理。
  • 标头信息以ASCII格式存储,可以使用任何文本编辑器读取,但像素信息以二进制格式存储,并且文本编辑器将显示该文本为乱码。

以下是示例pgm图像。


标头信息

  • 标识文件类型的幻数
    • 二进制PGM文件(PGMB):“ P5”
    • ASCII PGM文件(PGMA):“ P2”
  • ASCII十进制格式的宽度
  • ASCII十进制格式的高度
  • 最大灰度值,ASCII十进制格式,介于0-255之间
  • 可以包含注释,以“#”开头
  • 全部用空格分隔(空格,制表符,CR,LF)

gfg_logo.pgm中的标题信息:

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

在标题信息之后,有一个尺寸为高度*重量的网格,其中包含二进制格式的图像的灰度像素值。

读取PGMB图片

  • 以读取的二进制rb模式打开图像。
  • 检查是否存在任何注释,并忽略它们。
  • 阅读魔幻数字
  • 阅读任何注释/空白行/空白。
  • 读取宽度和高度,用空格隔开。
  • 在任何空白/注释之前和之后读取最大灰度值。
  • 读取像素值的网格(宽度*高度) ,以空格分隔。

下面是上述方法的程序:

C
// C Programe to read a PGMB image
// and print its parameters
#include 
#include 
#include 
#include 
#include 
  
// 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");
  
    // Retreiving 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;
}


输出:

解释:

  • 创建用于存储PGMB图像详细信息的结构,并为其分配内存。
  • 将文件名输入作为命令行参数或在程序中进行硬编码。
  • openPGM()函数处理输入的图像文件,并获取内存指针和文件名。
  • ignoreComments()函数用于跳过文件中的任何注释。注释通常出现在标题部分,因此,我们在读取每个属性后都会对其进行检查。
  • openPGM()函数,读取文件头信息,即。文件类型,高度,重量等。
  • 然后根据图像的高度分配内存,并针对每一行为图像的宽度分配内存。
  • fread()方法读取灰度值,并将其存储在为pgm结构的2d字符矩阵分配的内存中。
  • printImageDetails()用于打印从PGMB图像文件检索的值。
想要从精选的最佳视频中学习和练习问题,请查看《基础知识到高级C的C基础课程》。