图像中存储的数据既有可能是 0.0 ~ 1.0 代表颜色强度的值,也有可能是代表 0 ~ 255 的序号。如果是序号,则用普通的观察方式会比较困难,尤其是当序号差别较小时,眼睛是无法区分的,比如:
(不过我并不确定上图中数据的含义是否真的是序号)
因此,我想做一段C++小程序来读取TGA图片中的数据,然后将值输出到文本中。
我最开始参考的是C++读写Tga文件_猫哥-CSDN博客,这里的程序很简洁,但是对于文件头并没有解释,而且似乎只针对于“32位色的无压缩”。我之后又看到了https://github.com/aseprite/tga,这个比较全,也定义了文件头结构体,我的代码中的TGA文件头的定义也拷贝自它。
另外,TGA的wiki上有对这个格式包括文件头更详细的描述。我在附录中贴出wiki上的文件头解释。
代码#include#include #include using namespace std; //TGA文件头 struct TGAHeader { uint8_t idLength; uint8_t colormapType; uint8_t imageType; //图像类型 uint16_t colormapOrigin; uint16_t colormapLength; uint8_t colormapDepth; uint16_t xOrigin; uint16_t yOrigin; uint16_t width; //宽度 uint16_t height; //高度 uint8_t bitsPerPixel; //每像素多少位 uint8_t imageDescriptor; }; //ImageType对应的含义,来源于Wiki:https://en.wikipedia.org/wiki/Truevision_TGA string GetImageTypeString(uint8_t imageType) { if (imageType == 0) return "no image data is present"; else if (imageType == 1) return "uncompressed color-mapped image"; else if (imageType == 2) return "uncompressed true-color image"; else if (imageType == 3) return "uncompressed black-and-white(grayscale) image"; else if (imageType == 9) return "run-length encoded color-mapped image"; else if (imageType == 10) return "run-length encoded true-color image"; else if (imageType == 11) return "run-length encoded black-and-white(grayscale) image"; } int main() { //TGA文件名: const string TGAFileName = "PP2_rgb_XVect_a_XExtent.TGA"; //打开TGA文件 FILE* file_tga; fopen_s(&file_tga, TGAFileName.c_str(), "rb"); //读取文件头 TGAHeader data_header; { //fread(&data_header, sizeof(TGAHeader), 1, file_tga);//直接读取会有结构体的对齐问题 fread(&data_header.idLength, sizeof(uint8_t), 1, file_tga); fread(&data_header.colormapType, sizeof(uint8_t), 1, file_tga); fread(&data_header.imageType, sizeof(uint8_t), 1, file_tga); fread(&data_header.colormapOrigin, sizeof(uint16_t), 1, file_tga); fread(&data_header.colormapLength, sizeof(uint16_t), 1, file_tga); fread(&data_header.colormapDepth, sizeof(uint8_t), 1, file_tga); fread(&data_header.xOrigin, sizeof(uint16_t), 1, file_tga); fread(&data_header.yOrigin, sizeof(uint16_t), 1, file_tga); fread(&data_header.width, sizeof(uint16_t), 1, file_tga); fread(&data_header.height, sizeof(uint16_t), 1, file_tga); fread(&data_header.bitsPerPixel, sizeof(uint8_t), 1, file_tga); fread(&data_header.imageDescriptor, sizeof(uint8_t), 1, file_tga); } //输出文件头的一些信息 { cout << "Image Type : " << GetImageTypeString(data_header.imageType) << endl; cout << "每像素位数 : " << (int)data_header.bitsPerPixel << endl; cout << "宽度 : " << data_header.width << endl; cout << "高度 : " << data_header.height << endl; } if (data_header.bitsPerPixel != 32)//只考虑32位的数据 return 0; //像素数据从尺寸: int dataSize = data_header.width * data_header.height * 4; //读取颜色数据 uint8_t* data_color = new uint8_t[dataSize]; fread(data_color, sizeof(uint8_t), dataSize, file_tga); //存储到TXT中: { //TXT名字: string TXTFileName = TGAFileName; TXTFileName.replace(TXTFileName.length() - 3, 3, "txt"); //打开写入的txt文件 ofstream file_txt; file_txt.open(TXTFileName, ios::out); for (int h = 0; h < data_header.height; h++) { for (int w = 0; w < data_header.width; w++) { int index = data_header.width * h + w; file_txt << "("; file_txt << setw(3) << (int)data_color[index * 4 + 0];//R file_txt << ","; file_txt << setw(3) << (int)data_color[index * 4 + 1];//G file_txt << ","; file_txt << setw(3) << (int)data_color[index * 4 + 2];//B file_txt << ","; file_txt << setw(3) << (int)data_color[index * 4 + 3];//A file_txt << ") "; } file_txt << endl; } file_txt.close(); } }
最后将输出txt文本:
这样就可以看清具体的值了。
一开始出了问题,因为没有考虑到结构体的对齐问题。这个问题在这里【原创&交流】使用标准C库读文件时需要注意的一个问题也有讨论。
比如对于我这里的TGA文件头,其实只有18Byte的尺寸,但是如果以sizeof输出则有20:
因此最后我选择了单独为每段数据读取。



