使用visual C++读取pgm文件
Reading a pgm file using visual C++
我想从pgm文件中读取像素值,然后计算积分图像并将结果保存到文本文件中(我使用visual studio 2012来运行代码)。但代码中存在一些错误,它可以正确读取标题,显示正确的版本、注释和大小。但是pgm文件的像素值是错误的。只有前两行是正确的。有人知道问题出在哪里吗?
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
int row = 0, col = 0, num_of_rows = 0, num_of_cols = 0;
stringstream ss;
ifstream infile("testfile.pgm", ios::binary);
string inputLine = "";
getline(infile,inputLine); // read the first line : P5
if(inputLine.compare("P5") != 0) cerr << "Version error" << endl;
cout << "Version : " << inputLine << endl;
getline(infile,inputLine); // read the second line : comment
cout << "Comment : " << inputLine << endl;
ss << infile.rdbuf(); //read the third line : width and height
ss >> num_of_cols >> num_of_rows;
cout << num_of_cols << " columns and " << num_of_rows << " rows" << endl;
int max_val; //maximum intensity value : 255
ss >> max_val;
cout<<max_val;
unsigned char pixel;
int **pixel_value = new int*[num_of_rows];
for(int i = 0; i < num_of_rows; ++i) {
pixel_value[i] = new int[num_of_cols];
}
int **integral = new int*[num_of_rows];
for(int i = 0; i < num_of_rows; ++i) {
integral[i] = new int[num_of_cols];
}
for (row = 0; row < num_of_rows; row++){ //record the pixel values
for (col = 0; col < num_of_cols; col++){
ss >> pixel;
pixel_value[row][col]= pixel;
}
}
integral[0][0]=pixel_value[0][0];
for(int i=1; i<num_of_cols;i++){ //compute integral image
integral[0][i]=integral[0][i-1]+pixel_value[0][i];
}
for (int i=1;i<num_of_rows; i++){
integral[i][0]=integral[i-1][0]+pixel_value[i][0];
}
for (int i = 1; i < num_of_rows; i++){
for (int j = 1; j < num_of_cols; j++){
integral[i][j] = integral[i - 1 ][j] + integral [i][j - 1] - integral[i - 1] [j - 1] + pixel_value[i][j];
}
}
ofstream output1("pixel_value.txt"); // output the intensity values of the pgm file
for (int k=0; k<num_of_rows; k++)
{
for (int r=0; r<num_of_cols; r++)
{
output1 << pixel_value[k][r] << " ";
}
output1 << ";" << endl;
}
ofstream output2("integral_value.txt"); // output the integral image
for (int a=0; a<num_of_rows; a++)
{
for (int b=0; b<num_of_cols; b++)
{
output2 << integral[a][b] << " ";
}
output2 << ";" << endl;
}
for(int i = 0; i < num_of_rows; ++i) {
delete [] pixel_value[i];
}
delete [] pixel_value;
for(int i = 0; i < num_of_rows; ++i) {
delete [] integral[i];
}
delete [] integral;
infile.close();
system("pause");
return 0;
}
问题是pgm文件使用ascii字符,但0到32之间的ascii值没有字符。因此,您的代码适用于前两行,因为这些行没有任何介于0和32之间的强度值,小于33的第一个值出现在第三行,并且您的代码忽略该像素,因为没有字符来显示该像素。因此差异从第三行开始
当我检查你的代码时,你有这个:
for (int j = 0; j < num_of_rows; j++){ //compute integral image
for (int i = 0; i < num_of_cols; i++){
integral[i, j] = integral[i - 1, j] +
integral[i, j - 1] -
integral[i - 1, j - 1] +
pixel_value[i, j];
}
}
我想你的本意是这样的:
for (int j = 0; j < num_of_rows; j++){ //compute integral image
for (int i = 0; i < num_of_cols; i++){
integral[i, j] = integral[i - 1][j] +
integral[i][j - 1] -
integral[i - 1][j - 1] +
pixel_value[i][j];
}
}
编辑
您的代码的这一部分可能会引起关注:
int max_val; //255
ss >> max_val;
cout<<max_val;
char pixel;
unsigned int pixel_value[num_of_rows][num_of_cols];
unsigned int integral[num_of_rows][num_of_cols];
for (row = 0; row < num_of_rows; row++){ //pixel values
for (col = 0; col < num_of_cols; col++){
ss >> pixel;
pixel_value[row][col]= pixel;
}
cout << endl;
}
当像素数据被保存到char类型时,您声明您的数组包含unsigned int,然后尝试将此char类型保存到unsigned整型数组中。如果将char更改为unsigned char,可能会有所帮助。我还在下面的TGA文件中向我的一个类演示了一个方法。
我正在研究你如何读取数据的方法,这可能有助于你了解我的一个类的函数定义的实现,该类将从TGA文件中读取数据。以下是提供的结构和功能定义。
// TextureInfo -------------------------------------------------------------
struct TextureInfo {
enum FilterQuality {
FILTER_NONE = 1,
FILTER_GOOD,
FILTER_BETTER,
FILTER_BEST
}; // FilterQuality
unsigned uTextureId;
bool hasTransparency;
glm::uvec2 size;
TextureInfo() :
uTextureId( INVALID_UNSIGNED ),
hasTransparency( false ),
size( glm::uvec2( 0, 0 ) )
{}
}; // TextureInfo
// -------------------------------------------------------------------------
// Texture
struct Texture {
bool hasAlphaChannel;
bool generateMipMap;
bool wrapRepeat;
unsigned uWidth;
unsigned uHeight;
TextureInfo::FilterQuality filterQuality;
std::vector<unsigned char> vPixelData;
Texture( TextureInfo::FilterQuality filterQualityIn, bool generateMipMapIn, bool wrapRepeatIn ) :
hasAlphaChannel( false ),
generateMipMap( generateMipMapIn ),
wrapRepeat( wrapRepeatIn ),
uWidth( 0 ),
uHeight( 0 ),
filterQuality( filterQualityIn )
{}
}; // Texture
// -------------------------------------------------------------------------
// loadTga()
void TextureFileReader::loadTga( Texture* pTexture ) {
if ( nullptr == pTexture ) {
throw ExceptionHandler( __FUNCTION__ + std::string( " invalid pTexture passed in" ) );
}
struct TgaHeader {
unsigned char idLength;
unsigned char colorMapType;
unsigned char imageType;
unsigned char colorMapSpecifications[5];
short xOrigin;
short yOrigin;
short imageWidth;
short imageHeight;
unsigned char pixelDepth;
unsigned char imageDescriptor;
} tgaHeader;
enum TgaFileType {
TGA_RGB = 2,
TGA_RLE_RGB = 10,
}; // TgaFileType
// Error Message Handling
std::ostringstream strStream;
strStream << __FUNCTION__ << " ";
// Open File For Reading
m_fileStream.open( m_strFilenameWithPath, std::ios_base::in | std::ios_base::binary );
if ( !m_fileStream.is_open() ) {
strStream << "can not open file for reading";
throwError( strStream );
}
// Get TGA File Header
if ( !m_fileStream.read( reinterpret_cast<char*>( &tgaHeader ), sizeof( tgaHeader ) ) ) {
strStream << "error reading header";
throwError( strStream );
}
// This TGA File Loader Can Only Load Uncompressed Or Compressed True-Color Images
if ( (tgaHeader.imageType != TGA_RGB ) && (tgaHeader.imageType != TGA_RLE_RGB ) ) {
strStream << "TGA loader only supports loading RGB{" << TGA_RGB << "} and RLE_RGB{" << TGA_RLE_RGB
<< "} encoded files. This file contains pixels encoded in an unsupported type{" << tgaHeader.imageType << "}";
throwError( strStream );
}
// Convert Bits Per Pixel To Bytes Per Pixel
unsigned uBytesPerPixel = tgaHeader.pixelDepth / 8;
if ( (uBytesPerPixel != 3) && (uBytesPerPixel != 4) ) {
strStream << "TGA loader only supports 24bpp or 32bpp images. This image uses " << tgaHeader.pixelDepth << " bits per pixel";
throwError( strStream );
}
// Make Room For All Pixel Data
if ( 0 == tgaHeader.imageWidth || 0 == tgaHeader.imageHeight ) {
strStream << "invalid image size (" << tgaHeader.imageWidth << "," << tgaHeader.imageHeight << ")";
throwError( strStream );
}
unsigned uTotalNumBytes = tgaHeader.imageWidth * tgaHeader.imageHeight * uBytesPerPixel;
pTexture->vPixelData.resize( uTotalNumBytes );
// Move Read Pointer To Beginning Of Image Data
if ( tgaHeader.idLength > 0 ) {
m_fileStream.ignore( tgaHeader.idLength );
}
// Used To Get And Flip Pixels Data
std::vector<unsigned char> vTempPixel( uBytesPerPixel, 0 );
if ( tgaHeader.imageType == TGA_RLE_RGB ) {
// TGA Data Is Compressed
// All Error Messages The Same If Error Occurs Below
strStream << "file is corrupted, missing pixel data";
unsigned char ucRepetitionCounter = 0;
unsigned uTotalNumberPixels = tgaHeader.imageWidth * tgaHeader.imageHeight;
unsigned uCurrentPixel = 0;
while( uCurrentPixel < uTotalNumberPixels ) {
// Get Repetition Count Value
if ( !m_fileStream.read( reinterpret_cast<char*>( &ucRepetitionCounter ), sizeof( unsigned char ) ) ) {
throwError( strStream );
}
if ( ucRepetitionCounter < 128 ) {
// Raw Packet. Counter Indicates How Many Different Pixels Need To Be Read
++ucRepetitionCounter;
// Get Pixel Values
if ( !m_fileStream.read( reinterpret_cast<char*>( &pTexture->vPixelData[uCurrentPixel * uBytesPerPixel] ), uBytesPerPixel * ucRepetitionCounter ) ) {
throwError( strStream );
}
} else {
// Run-Length Packet. Counter Indicates How Many Times The Text Pixel Needs To Repeat
ucRepetitionCounter -= 127;
// Get Pixel Value
if ( !m_fileStream.read( reinterpret_cast<char*>( &vTempPixel[0] ), uBytesPerPixel ) ) {
throwError( strStream );
}
// Save Pixel Multiple Times
for ( unsigned int u = uCurrentPixel; u < ( uCurrentPixel + ucRepetitionCounter ); ++u ) {
memcpy( &pTexture->vPixelData[u * uBytesPerPixel], &vTempPixel[0], uBytesPerPixel );
}
}
// Increment Counter
uCurrentPixel += ucRepetitionCounter;
}
} else {
// TGA Data Is Uncompressed
// Get Pixel Data
if ( !m_fileStream.read( reinterpret_cast<char*>( &pTexture->vPixelData[0] ), pTexture->vPixelData.size() ) ) {
strStream << "file is corrupted, missing pixel data";
throwError( strStream );
}
}
m_fileStream.close();
// Convert All Pixel Data from BGR To RGB
unsigned char ucTemp;
for ( unsigned int u = 0; u < uTotalNumBytes; u += uBytesPerPixel ) {
ucTemp = pTexture->vPixelData[u]; // Save Blue Color
pTexture->vPixelData[u] = pTexture->vPixelData[u + 2]; // Set Red Color
pTexture->vPixelData[u + 2] = ucTemp; // Set Blue Color
}
// Flip Image Horizontally
if ( tgaHeader.imageDescriptor & 0x10 ) {
short sHalfWidth = tgaHeader.imageWidth >> 1;
for ( short h = 0; h < tgaHeader.imageHeight; ++h ) {
for ( short w = 0; w < sHalfWidth; ++w ) {
unsigned uPixelLeft = uBytesPerPixel * ( h * tgaHeader.imageWidth + w );
unsigned uPixelRight = uBytesPerPixel * ( h * tgaHeader.imageWidth + tgaHeader.imageWidth - 1 - w );
memcpy( &vTempPixel[0], &pTexture->vPixelData[uPixelLeft], uBytesPerPixel ); // Store Left Pixel
memcpy( &pTexture->vPixelData[uPixelLeft], &pTexture->vPixelData[uPixelRight], uBytesPerPixel ); // Save Right Pixel @ Left
memcpy( &pTexture->vPixelData[uPixelRight], &vTempPixel[0], uBytesPerPixel ); // Save Left Pixel @ Right
}
}
}
// Flip Vertically
if ( tgaHeader.imageDescriptor & 0x20 ) {
short sHalfHeight = tgaHeader.imageHeight >> 1;
for ( short w = 0; w < tgaHeader.imageWidth; ++w ) {
for ( short h = 0; h < sHalfHeight; ++h ) {
unsigned uPixelTop = uBytesPerPixel * ( w + tgaHeader.imageWidth * h );
unsigned uPixelBottom = uBytesPerPixel * ( w + tgaHeader.imageWidth * ( tgaHeader.imageHeight - 1 - h ) );
memcpy( &vTempPixel[0], &pTexture->vPixelData[uPixelTop], uBytesPerPixel ); // Store Top Pixel
memcpy( &pTexture->vPixelData[uPixelTop], &pTexture->vPixelData[uPixelBottom], uBytesPerPixel ); // Save Bottom Pixel @ Top
memcpy( &pTexture->vPixelData[uPixelBottom], &vTempPixel[0], uBytesPerPixel ); // Save Top Pixel @ Bottom
}
}
}
// Store Other Values In Texture
pTexture->uWidth = tgaHeader.imageWidth;
pTexture->uHeight = tgaHeader.imageHeight;
pTexture->hasAlphaChannel = ( tgaHeader.pixelDepth == 32 );
} // loadTga
注意:-如果您复制并粘贴它,它将无法编译,因为它依赖于此处未列出或显示的其他类和库。这是我的一个三维图形引擎解决方案的有效工作代码。
正如你在这里看到的,我正在使用TGA标题的结构;我还有一个纹理对象的结构。现在,所有这些可能都超出了你的需求;但重要的部分是看我是如何从文件中读取数据并存储它们的值的。
重要的部分是我在文件流read()
方法中使用C++关键字reinterpret_cast<>( )
的位置。这可能有助于您重写用于读取图像文件的解析器,以便读取和存储的数据与您期望的图像结构字节对齐。这也将取决于您正在读取的文件的结构和您在代码中使用的图像结构。
我也有一个类似的方法来读取这个类使用的PNG文件,这取决于我在电脑上安装的PGN库,并链接到我的IDE,这样就可以找到读取PGN文件的函数。这比我在TGA文件中向您展示的函数要简单得多。
当你想使用TGA文件时,你必须知道文件结构,并编写自己的文件解析器,与PNG文件一样,大部分工作都是在PNG库中为你完成的,你所要做的就是以正确的顺序调用适当的函数,并检查是否有适当的错误。我还没有显示loadPNG()函数。
当然,你阅读的是PGM文件,而不是TGA或PNG,但概念是一样的。在到达实际像素数据之前,您必须确切地知道要读取多少字节,然后您应该知道图像的大小,如像素宽度*像素长度*每个像素的字节。标头信息应该在您读取并将其存储到变量或结构中时告诉您这些信息,但这非常重要。一个例子是图像是256像素X 256像素,然而还需要知道的是每个像素的宽度!每个像素是8位(1字节)、16位(2字节)、24位(3字节)、32位(4字节)。另一件需要知道的重要事情是什么是颜色模式,例如黑色&白色、灰度、RGB、RGBA、CYM等,以及颜色信息的存储顺序。此外,存储为不仅通过颜色信息反转的图像,而且是水平和/或垂直反转的图像。图像文件的头信息中通常有一些标志可以告诉您这一点。还有压缩、未压缩的数据,是原始数据还是游程长度编码(RLE)。在解析图像文件时,所有这些信息都很重要。当你使用BMP-JPEG时,它甚至会变得有点复杂,因为它们还存储了一个可能的调色板。
我希望这有助于为您提供指导,以便您在开始对图像数据进行任何处理或工作之前能够正确读取图像文件。
- .cpp和.h文件中的模板专用化声明
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 文本文件中的单词链表
- CMake-按正确顺序将项目与C运行时对象文件链接
- 使用新行和不使用新行读取文件
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 挂起和取消挂起一个文件DLL
- 如何确定我已使用非编码文件到达 EOF?
- 命名空间中具有.h和.cpp文件的类
- 这些PGM文件是如何编码的?
- 如何顺时针旋转PGM文件
- C++程序读取ppm和pgm文件,对其进行操作并输出.编译错误
- 编写一个C++ pgm 以从文件"input.txt"读取,每当遇到句点时插入换行符并将修改的内容写入"output.txt"
- 读取二进制16位流文件并写入16位PGM(C++)
- 写入 PGM 文件
- 使用visual C++读取pgm文件
- 读取纯文本PGM p5文件后读取数据字节
- 如何在c++中从pgm文件中读取数据
- 如何读取/写入ASCI.pgm文件
- 如何将.pgm纹理文件加载到openGL中