使用纯C显示PGM图像(p5)中的直方图像素值,无需任何图像处理库

使用纯C显示PGM图像(p5)中的直方图像素值,无需任何图像处理库,c,image,binary,pgm,C,Image,Binary,Pgm,这个问题很难理解使用纯C进行的图像处理。我用GCC编译的C编写了一个读取非二进制PGM文件的简单程序。现在,当我试图读取二进制PGM文件时,这就成了一个问题。可通过使用将JPG转换为PGM来获取该二进制PGM文件 注意:请不要使用任何图像处理库(例如:OpenCV)进行回答 我目前的代码是: #include <stdio.h> #include <stdlib.h> #define WIDTH 1024 #define HEIGHT 768 #defi

这个问题很难理解使用纯C进行的图像处理。我用GCC编译的C编写了一个读取非二进制PGM文件的简单程序。现在,当我试图读取二进制PGM文件时,这就成了一个问题。可通过使用将JPG转换为PGM来获取该二进制PGM文件

注意:请不要使用任何图像处理库(例如:OpenCV)进行回答

我目前的代码是:

#include    <stdio.h> 
#include    <stdlib.h>
#define WIDTH 1024  
#define HEIGHT 768
#define READ_IMAGE_NAME "MY_PGM_FILE_NAME.pgm"

void print_histogram_table(int *histog);

main() {
  FILE *fp;

  int i,j, height= HEIGHT, width=WIDTH;
  char line[100];

  // Color depth is 255. 
  unsigned char pixel_value;

  fp = fopen(READ_IMAGE_NAME,"r");

  // get the first four lines.
  fgets (line,100,fp); 
  fgets (line,100,fp);
  fgets (line,100,fp);
  fgets (line,100,fp);

  // Histogram helper
  int histo[65536];
  int x;
  for ( x =0; x < 65536; x++) {    
        histo[x] = 0;
  }

  for(j=0;j<height;j++) {
     for(i=0;i<width;i++) {
         fread(&pixel_value, sizeof(unsigned char), 1, fp);
         // Turn on the code below, if you want to check color on specific row and column.
//             printf("row num. %d column num. %d    pixel value=%d\n",j,i,pixel_value);  

       histo[pixel_value]++;
     }
  }

  // Make histogram
  print_histogram_table(histo);

  fclose(fp);       
  getch();
}

void print_histogram_table(int *histog)
{
  int x; 
  for (x= 0; x < 255; x++) {
     if ( histog[x] != 0)
        printf("Color number %d count %d\n", x, histog[x]); 
  }
}
#包括
#包括
#定义宽度1024
#定义高度768
#定义READ_IMAGE_NAME“MY_PGM_FILE_NAME.PGM”
无效打印柱状图表格(int*histog);
main(){
文件*fp;
int i,j,高度=高度,宽度=宽度;
字符行[100];
//颜色深度为255。
无符号字符像素值;
fp=fopen(读取图像名称,“r”);
//获取前四行。
fgets(第100行,fp);
fgets(第100行,fp);
fgets(第100行,fp);
fgets(第100行,fp);
//直方图辅助程序
国际历史[65536];
int x;
对于(x=0;x<65536;x++){
histo[x]=0;
}

对于(j=0;j和…问题是什么?您的代码在读取二进制PGM(P5?)时看起来几乎没有问题,只是缺少每个像素数据行的换行检查(根据wikipedia文章,ASCII和二进制格式在每个像素数据行的末尾都有换行符)

一些评论:

  • 不要硬编码宽度和高度,应该使用标题中的信息
  • 检查幻数,如果不是P5,则抛出/返回错误(或正确处理)
  • <> LI>文件可以有行注释,考虑
我上面的脚本无法显示正确的颜色直方图,因为如果你理性思考,你可能会得到100以上的像素颜色(不仅仅是100以下)。因此,主要问题是如何解决这个问题

我想你的意思是:

现在,在链接图像上运行此程序只会显示100以下像素值的非零直方图条目。我知道100以上的图像中至少有一个像素值,所以我的代码中有一个bug。有人能帮我弄清楚为什么会发生这种情况吗

我建议你重新措辞你的问题,以明确这一点

假设您只希望它对链接到的图像起作用,那么代码表面上看起来还可以。但是,可能会有很多小错误。以下是一些建议:

直方图大小

首先,你不能打印整个直方图。考虑将直方图大小传递给打印直方图的函数。此外,即使大小匹配(256个),仍然会有错误。你从不打印第二百五十六值。

int histo[65536];
// ...
print_histogram_table(histo);
// ...
void print_histogram_table(int *histog)
{
    int x; 
    for (x= 0; x < 255; x++) {
       if ( histog[x] != 0)
          printf("Color number %d count %d\n", x, histog[x]); 
}
其他小问题 有很多事情不是由您的代码处理的:

  • PNM文件的开头可能有注释
  • 行的长度可以超过100个字符
  • 图像大小不强制为1024x768
  • 在程序中硬编码文件名没有多大用处,即使只是为了测试代码
  • 如果您实际得到的是每像素16位的灰度图像,则直方图足够大,但您应该读取2字节的值

  • 关于您的计划的一些注意事项:

    • 您应该读取标题,而不是硬编码宽度、高度和最大像素值
    • 将整个图像加载到内存并从内存进行处理是一种更有效的方法
    • PGM文件是二进制文件,您应该在fopen中使用“rb”(如果您在Windows上运行此文件,其中二进制文件与文本不同)
    • 直方图打印函数缺少最后一个像素(255是有效的像素值)
    • 不知道为什么直方图数组会变为64K,您是否也计划支持16位PGM
    • 您应该进行错误处理,以避免崩溃或其他意外行为
    下面是你的程序的改进版本,上面提到的几点。我希望它能有所帮助

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(int argc, char* argv[])
    {
        char line[100];
        int width, height, maxval;
        unsigned char* image;
        unsigned int* histo;
        int i;
        FILE *fd;
    
        fd = fopen(argv[1], "rb");
        if (fd == NULL) {
            printf("could not open image file\n");
            exit(1);
        }
    
        // magic number
        fgets(line, sizeof(line), fd);
        if (strcmp(line, "P5\n") != 0) {
            printf("image is not in PGM format!\n");
            fclose(fd);
            exit(1);
        }
    
        // skip comment
        fgets(line, sizeof(line), fd);
    
        // read header
        if (fscanf(fd, "%d %d %d\n", &width, &height, &maxval) != 3) {
            printf("invalid header\n");
            fclose(fd);
            exit(1);
        }
        if (maxval > 255) {
            printf("sorry, only 8-bit PGMs are supported at this time!\n");
            fclose(fd);
            exit(1);
        }
    
        printf("width: %d\nheight: %d\nmaxval: %d\n", width, height, maxval);
    
        // read image data
        image = malloc(width * height);
        if (fread(image, sizeof(unsigned char), width * height, fd) != width * height) {
            printf("could not read image\n");
            fclose(fd);
            exit(1);
        }
        fclose(fd);
    
        // compute histogram
        histo = (int*)calloc(maxval+1, sizeof(int));
        for (i = 0; i < width * height; i++)
            histo[image[i]]++;
    
        // print histogram
        for (i = 0; i <= maxval; i++)
            printf("Color number %d count %d\n", i, histo[i]);
    
        // release memory
        free(image);
        free(histo);
    }
    
    #包括
    #包括
    #包括
    int main(int argc,char*argv[])
    {
    字符行[100];
    整数宽度、高度、最大值;
    无符号字符*图像;
    无符号整数*历史;
    int i;
    文件*fd;
    fd=fopen(argv[1],“rb”);
    如果(fd==NULL){
    printf(“无法打开图像文件\n”);
    出口(1);
    }
    //幻数
    fgets(行,sizeof(行),fd);
    如果(strcmp(第“P5\n”行)!=0){
    printf(“图像不是PGM格式!\n”);
    fclose(fd);
    出口(1);
    }
    //跳过评论
    fgets(行,sizeof(行),fd);
    //读标题
    如果(fscanf(fd,“%d%d%d\n”、&宽度、高度和最大值)!=3){
    printf(“无效标题\n”);
    fclose(fd);
    出口(1);
    }
    如果(最大值>255){
    printf(“对不起,目前只支持8位PGM!\n”);
    fclose(fd);
    出口(1);
    }
    printf(“宽度:%d\n高度:%d\n最大值:%d\n”,宽度,高度,最大值);
    //读取图像数据
    图像=malloc(宽度*高度);
    if(fread(图像,sizeof(无符号字符),宽度*高度,fd)!=宽度*高度){
    printf(“无法读取图像\n”);
    fclose(fd);
    出口(1);
    }
    fclose(fd);
    //计算直方图
    histo=(int*)calloc(maxval+1,sizeof(int));
    对于(i=0;i对于(i=0;i好的,当我创建直方图读取颜色变化时,我无法得到任何合理的结果。我将提供我的PGM文件进行测试。顺便说一句,我的标题是我的问题。你没有读过吗?:)一个想法:尝试将其转换为ASCII格式(P2)并查看它,这应该检查您是否正确阅读了它not@exodream:标题可能是一个问题,但您似乎已经发布了一个解决方案。因此,我们唯一的问题已经回答,没有问题了。示例问题是:“当它应该执行“…”操作时,它在“情境”…“中的行为类似于“…”。有人能看到错误吗?”C/C++不是语言选择错误。您可以
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(int argc, char* argv[])
    {
        char line[100];
        int width, height, maxval;
        unsigned char* image;
        unsigned int* histo;
        int i;
        FILE *fd;
    
        fd = fopen(argv[1], "rb");
        if (fd == NULL) {
            printf("could not open image file\n");
            exit(1);
        }
    
        // magic number
        fgets(line, sizeof(line), fd);
        if (strcmp(line, "P5\n") != 0) {
            printf("image is not in PGM format!\n");
            fclose(fd);
            exit(1);
        }
    
        // skip comment
        fgets(line, sizeof(line), fd);
    
        // read header
        if (fscanf(fd, "%d %d %d\n", &width, &height, &maxval) != 3) {
            printf("invalid header\n");
            fclose(fd);
            exit(1);
        }
        if (maxval > 255) {
            printf("sorry, only 8-bit PGMs are supported at this time!\n");
            fclose(fd);
            exit(1);
        }
    
        printf("width: %d\nheight: %d\nmaxval: %d\n", width, height, maxval);
    
        // read image data
        image = malloc(width * height);
        if (fread(image, sizeof(unsigned char), width * height, fd) != width * height) {
            printf("could not read image\n");
            fclose(fd);
            exit(1);
        }
        fclose(fd);
    
        // compute histogram
        histo = (int*)calloc(maxval+1, sizeof(int));
        for (i = 0; i < width * height; i++)
            histo[image[i]]++;
    
        // print histogram
        for (i = 0; i <= maxval; i++)
            printf("Color number %d count %d\n", i, histo[i]);
    
        // release memory
        free(image);
        free(histo);
    }