【问题标题】:convolution using a 3X3 low pass filter for a .pgm image in C++在 C++ 中使用 3X3 低通滤波器对 .pgm 图像进行卷积
【发布时间】:2015-02-18 05:54:18
【问题描述】:

我正在尝试用 C++ 编写一个具有以下 3 个功能的程序: (i) read_pgm_image() - 从文件中读取 .pgm 格式的图像; (ii) convolve() - 使用 3X3 低通滤波器对图像执行卷积;和, (iii) write_pgm_image() - 将图像数据写回到单独的文件中

这是我的代码:

#include<iostream>
#include<fstream>
#include<string>
using namespace std;

void read_pgm_image(char name[]);
void convolve(int img[][256], int M, int N, int img_intensity);
void write_pgm_image(char name[], int img[256][256], int img_data[]);

int main()
{   read_pgm_image("lenna2.pgm");

    getchar();
    return 0;
}

void read_pgm_image(char name[])
{   string magic, creator_info;
    int img_intensity, M, N;
    ifstream file(name, ios::binary);
    if(file.is_open())
    {   cout<<"File successfully opened! \n\n";
        cout<<"Reading the file...\n";
        cout<<"Name of the file:\t"<<name<<'\n';

        getline(file,magic); // get the magic number

        getline(file,creator_info); // get the creator information

        file>>M; // get width of the image
        cout<<"Width of the Image:\t"<<M<<'\n';

        file>>N; // get length of the image
        cout<<"Length of the Image:\t"<<N<<'\n';

        file>>img_intensity; // get the image intensity
        cout<<"Maximum Intensity:\t"<<img_intensity<<'\n'; 

        int img[256][256]; // create an array to store image data
        for(int i=0; i<N; i++)
        {   for(int j=0; j<M; j++)
            {   file.read((char*)&img[i][j],sizeof(int));
            }
        }
        file.close();

        convolve(img, M, N, img_intensity); // Calling the Convolve function
    }
    else
    {   cout<<"Error in opening image!";
        file.close();
    }
}



void convolve(int img[256][256], int M, int N, int img_intensity)
{   int con_img[256][256], sum=0, img_data[3]={M,N,img_intensity};

    for(int i=0; i<N; i++)
    {   for(int j=0; j<M; j++)
        {   con_img[i][j]=img[i][j];
        }
    }

    for(int i=1; i<(N-1); i++)
{   for(int j=1; j<(M-1); j++)
    {   for(int k=(i-1); k<(i+1); k++)
        {   for(int l=(j-1); l<(j+1); l++)
            {   sum = sum + img[k][l];
            }
        }
        con_img[i][j] = sum/9;
        sum=0;
    }
}

write_pgm_image("image_convolve.pgm", con_img, img_data);
}



void write_pgm_image(char name[], int img[256][256], int img_data[3])
{ cout<<"\nCreating image file...\n";

  ofstream file(name,ios::binary);

  if(file.is_open())
  {   cout<<"File successfully created!\n";
      cout<<"Writing image data...\n";

      file<<"P5\n"<<img_data[0]<<' '<<img_data[1]<<' '<<img_data[2]; //Writing P5, image width, image length and maximum intensity

      cout<<"Image data written!\n";

      for(int i=0; i<img_data[1]; i++)  //Write image data to the file
        {   for(int j=0; j<img_data[0]; j++)
            {   file.write((char*)&(img[i][j]), sizeof(int));
            }
        }
      cout<<"Image pixel info written!\n";
      file.close();
  }
  else
  { cout <<"Error in creating file!";
    file.close();
  }
}

convolve() 函数似乎有问题。理想情况下,我应该得到输入图像的模糊版本(我无法上传)。但我得到的是一个垃圾图像。

非常感谢任何帮助... 谢谢。

【问题讨论】:

  • 这取决于您所说的“垃圾”是什么意思。除了 elias 指出的小错误外,您的卷积函数看起来不错。输出图像与输入图像完全不同吗?如果不是,则问题可能出在您的文件读取器/写入器中,或两者兼而有之。 PGM 文件规范说像素强度被赋予 1 或 2 个字节的内存,但自 sizeof(int) == 4 以来,您一次读取 4 个字节。您应该在读取图像后尝试打印出一些像素值,看看它们是否符合您的预期。
  • 如果我在读取原始图像后保存了图像(即在调用 convolve() 函数之前在 read_pgm_image() 函数中调用 write_pgm_image() 函数,我会得到完全相同的图像 - 这是预期的.如果我在执行任何操作之前调用convolve函数中的write函数也是同样的情况。
  • 但是,我尝试了一件事。如果我将特定值(例如 0 或 255 或 -1)分配给 2D 数组 con_img[][] 中的元素,则会发生这种情况。如果我分配 0 或正值,我会得到一个黑色像素。如果我分配一个负值,我会得到一个白色像素。这就是我所说的获取“垃圾”图像的意思。
  • 在 file.read 和 file.write 行中,我将 sizeof(int) 更改为 (sizeof(int)/4)。这似乎奏效了。对于图像的大部分,我得到了一个模糊的图像。但是,在最后 7 行(从底部算起 7 行)中,我仍然得到“垃圾”。请帮忙!

标签: c++ image convolution


【解决方案1】:

k 和 l 的循环边界存在一个小错误(

【讨论】:

  • 感谢 elias 指出错误。即使纠正了您指出的错误,我仍然收到“垃圾”图像。
【解决方案2】:

您将 img 声明为一个二维整数数组,也就是说数组中的每个条目都是 4 个字节。您还使用sizeof(int) 一次读取文件 4 个字节。

 int img[256][256]; // create an array to store image data
 for(int i=0; i<N; i++)
 {   for(int j=0; j<M; j++)
     {   file.read((char*)&img[i][j],sizeof(int));
     }
 }

根据PGM file specification,像素值是1或2字节,(charshorts)取决于最大强度值是否大于255。你是将文件中的 2 或 4 个像素值读取到 img 数组中的 1 个条目中。

您的文件阅读器应该看起来更喜欢这个。我们可以一次读取所有文件,因为 C++ 和 PGM 数组都以行优先顺序存储数据。

char img[N][M];
file.ignore(); // ignore one character (as described in file specification)
file.read((char*)img,(streamsize)sizeof(img));

如果仍然无法正常工作,请确保您可以重现此 PGM 文件 test.pgm 的结果:

P5
# this is a comment
5 5
255
!!!!!AAAAA~~~~~AAAAA!!!!!

打印出矩阵给出这些值:

33 33 33 33 33 
65 65 65 65 65 
126 126 126 126 126 
65 65 65 65 65 
33 33 33 33 33

我电脑上的图片查看器会这样显示(放大 2000%):

【讨论】:

  • 我已更改代码。我没有将像素值作为 int 输入,而是将它们作为 char 输入。这似乎工作得很好。非常感谢eigenchris!
  • @pras 很高兴听到。如果您觉得它有帮助,您可以考虑接受或支持答案。 :)
猜你喜欢
  • 2020-05-26
  • 2011-03-06
  • 2017-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-31
  • 2011-12-17
  • 2011-07-07
相关资源
最近更新 更多