TGA文件绿色通道修改异常求助(附C++实现代码)
TGA图像绿色通道调整异常问题
我尝试给加载的TGA文件绿色通道添加指定数值,但输出结果不符合预期——哪怕加0都会生成修改后的图像。
当前输出图像:
预期输出图像:
怀疑问题出在代码结构或逻辑上,以下是实现的C++代码:
#ifndef PROJECT2_TGA_READER_H #define PROJECT2_TGA_READER_H #include <iostream> #include <fstream> #include <vector> using namespace std; struct TGA_HeaderData{ char idLength; char colorMapType; char dataTypeCode; short colorMapOrigin; short colorMapLength; char colorMapDepth; short xOrigin; short yOrigin; short width; short height; char bitsPerPixel; char imageDescriptor; }; struct Pixel_Data{ char blue; char green; char red; }; class TGA_Reader { public: TGA_Reader(string file_name); TGA_HeaderData HeaderData{}; vector<Pixel_Data> pixels; void DeclareFile(string file_name); void createFile(const char *name, const TGA_HeaderData &headerData, const vector<Pixel_Data> &pixels); TGA_Reader add_green_channel(int value); }; #include "TGA_Reader.h" TGA_Reader::TGA_Reader(string file_name) { DeclareFile(file_name); } void TGA_Reader::DeclareFile(string file_name) { ifstream file(file_name, ios::binary); if (!file){ cout<<"not open"<<endl; return; } file.read((char*)&HeaderData.idLength, sizeof(HeaderData.idLength)); file.read((char*)&HeaderData.colorMapType, sizeof(HeaderData.colorMapType)); file.read((char*)&HeaderData.dataTypeCode, sizeof(HeaderData.dataTypeCode)); file.read((char*)&HeaderData.colorMapOrigin, sizeof(HeaderData.colorMapOrigin)); file.read((char*)&HeaderData.colorMapLength, sizeof(HeaderData.colorMapLength)); file.read((char*)&HeaderData.colorMapDepth, sizeof(HeaderData.colorMapDepth)); file.read((char*)&HeaderData.xOrigin, sizeof(HeaderData.xOrigin)); file.read((char*)&HeaderData.yOrigin, sizeof(HeaderData.yOrigin)); file.read((char*)&HeaderData.width, sizeof(HeaderData.width)); file.read((char*)&HeaderData.height, sizeof(HeaderData.height)); file.read((char*)&HeaderData.bitsPerPixel, sizeof(HeaderData.bitsPerPixel)); file.read((char*)&HeaderData.imageDescriptor, sizeof(HeaderData.imageDescriptor)); pixels.reserve(HeaderData.width*HeaderData.height); for (int i = 0; i < HeaderData.width*HeaderData.height; i++) { Pixel_Data pixel; file.read((char*)&pixel.blue, sizeof(unsigned char)); file.read((char*)&pixel.green, sizeof(unsigned char)); file.read((char*)&pixel.red, sizeof(unsigned char)); pixels.push_back(pixel); } file.close(); } void TGA_Reader::createFile(const char *name, const TGA_HeaderData &headerData, const vector<Pixel_Data> &pixels) { ofstream outfile; outfile.open("/Users/diegogomez/CLionProjects/Project2/cmake-build-debug/Hello3.tga",ios::binary); outfile.write((char*)&headerData.idLength, sizeof(headerData.idLength)); outfile.write((char*)&headerData.colorMapType, sizeof(headerData.colorMapType)); outfile.write((char*)&headerData.dataTypeCode, sizeof(headerData.dataTypeCode)); outfile.write((char*)&headerData.colorMapOrigin, sizeof(headerData.colorMapOrigin)); outfile.write((char*)&headerData.colorMapLength, sizeof(headerData.colorMapLength)); outfile.write((char*)&headerData.colorMapDepth, sizeof(headerData.colorMapDepth)); outfile.write((char*)&headerData.xOrigin, sizeof(headerData.xOrigin)); outfile.write((char*)&headerData.yOrigin, sizeof(headerData.yOrigin)); outfile.write((char*)&headerData.width, sizeof(headerData.width)); outfile.write((char*)&headerData.height, sizeof(headerData.height)); outfile.write((char*)&headerData.bitsPerPixel, sizeof(headerData.bitsPerPixel)); outfile.write((char*)&headerData.imageDescriptor, sizeof(headerData.imageDescriptor)); cout<<pixels.size()<<endl; for (int i = 0; i < pixels.size(); i++) { outfile.write((char*)&pixels[i].blue, sizeof(unsigned char)); outfile.write((char*)&pixels[i].green, sizeof(unsigned char)); outfile.write((char*)&pixels[i].red, sizeof(unsigned char)); } outfile.close(); } TGA_Reader TGA_Reader::add_green_channel(int value) { TGA_Reader copy(*this); // make a copy of the object for (int i = 0; i < copy.pixels.size(); i++) { int pixel = (int) (copy.pixels[i].green + value); if (pixel < 0) { int pixel = 0; } if (pixel > 255) { int pixel = 255; } (unsigned char)(pixel); copy.pixels[i].green = pixel; } return copy; // return the modified copy }
问题根源分析
- 有符号char的解析错误:
Pixel_Data中的green是默认有符号的char类型,TGA图像的颜色值是0-255的无符号数据,读取时128-255会被解析为负数,哪怕加0也会因为类型转换导致数值异常。 - 变量作用域错误:
add_green_channel函数的if块内重新定义了pixel变量,外层的pixel根本不会被修改,等于白做了范围钳制。 - 无效的类型转换:
(unsigned char)(pixel);只是做了转换但没有赋值给任何变量,最终还是把未正确处理的int值直接塞给char类型的绿色通道。 - 硬编码输出路径:
createFile函数写死了输出路径,不仅不灵活,还可能因路径权限或不存在导致输出异常。
修复后的代码
头文件部分
#ifndef PROJECT2_TGA_READER_H #define PROJECT2_TGA_READER_H #include <iostream> #include <fstream> #include <vector> #include <algorithm> // 用于max/min函数 using namespace std; struct TGA_HeaderData{ unsigned char idLength; unsigned char colorMapType; unsigned char dataTypeCode; short colorMapOrigin; short colorMapLength; unsigned char colorMapDepth; short xOrigin; short yOrigin; short width; short height; unsigned char bitsPerPixel; unsigned char imageDescriptor; }; struct Pixel_Data{ unsigned char blue; unsigned char green; unsigned char red; }; class TGA_Reader { public: TGA_Reader(string file_name); TGA_HeaderData HeaderData{}; vector<Pixel_Data> pixels; void DeclareFile(string file_name); void createFile(const char *name, const TGA_HeaderData &headerData, const vector<Pixel_Data> &pixels); TGA_Reader add_green_channel(int value); }; #endif // PROJECT2_TGA_READER_H
实现文件部分
#include "TGA_Reader.h" TGA_Reader::TGA_Reader(string file_name) { DeclareFile(file_name); } void TGA_Reader::DeclareFile(string file_name) { ifstream file(file_name, ios::binary); if (!file){ cout<<"not open"<<endl; return; } file.read((char*)&HeaderData.idLength, sizeof(HeaderData.idLength)); file.read((char*)&HeaderData.colorMapType, sizeof(HeaderData.colorMapType)); file.read((char*)&HeaderData.dataTypeCode, sizeof(HeaderData.dataTypeCode)); file.read((char*)&HeaderData.colorMapOrigin, sizeof(HeaderData.colorMapOrigin)); file.read((char*)&HeaderData.colorMapLength, sizeof(HeaderData.colorMapLength)); file.read((char*)&HeaderData.colorMapDepth, sizeof(HeaderData.colorMapDepth)); file.read((char*)&HeaderData.xOrigin, sizeof(HeaderData.xOrigin)); file.read((char*)&HeaderData.yOrigin, sizeof(HeaderData.yOrigin)); file.read((char*)&HeaderData.width, sizeof(HeaderData.width)); file.read((char*)&HeaderData.height, sizeof(HeaderData.height)); file.read((char*)&HeaderData.bitsPerPixel, sizeof(HeaderData.bitsPerPixel)); file.read((char*)&HeaderData.imageDescriptor, sizeof(HeaderData.imageDescriptor)); pixels.reserve(HeaderData.width*HeaderData.height); for (int i = 0; i < HeaderData.width*HeaderData.height; i++) { Pixel_Data pixel; file.read((char*)&pixel.blue, sizeof(pixel.blue)); file.read((char*)&pixel.green, sizeof(pixel.green)); file.read((char*)&pixel.red, sizeof(pixel.red)); pixels.push_back(pixel); } file.close(); } void TGA_Reader::createFile(const char *name, const TGA_HeaderData &headerData, const vector<Pixel_Data> &pixels) { ofstream outfile(name, ios::binary); if (!outfile) { cout<<"Failed to create output file"<<endl; return; } outfile.write((char*)&headerData.idLength, sizeof(headerData.idLength)); outfile.write((char*)&headerData.colorMapType, sizeof(headerData.colorMapType)); outfile.write((char*)&headerData.dataTypeCode, sizeof(headerData.dataTypeCode)); outfile.write((char*)&headerData.colorMapOrigin, sizeof(headerData.colorMapOrigin)); outfile.write((char*)&headerData.colorMapLength, sizeof(headerData.colorMapLength)); outfile.write((char*)&headerData.colorMapDepth, sizeof(headerData.colorMapDepth)); outfile.write((char*)&headerData.xOrigin, sizeof(headerData.xOrigin)); outfile.write((char*)&headerData.yOrigin, sizeof(headerData.yOrigin)); outfile.write((char*)&headerData.width, sizeof(headerData.width)); outfile.write((char*)&headerData.height, sizeof(headerData.height)); outfile.write((char*)&headerData.bitsPerPixel, sizeof(headerData.bitsPerPixel)); outfile.write((char*)&headerData.imageDescriptor, sizeof(headerData.imageDescriptor)); cout<<pixels.size()<<endl; for (const auto& pixel : pixels) { outfile.write((char*)&pixel.blue, sizeof(pixel.blue)); outfile.write((char*)&pixel.green, sizeof(pixel.green)); outfile.write((char*)&pixel.red, sizeof(pixel.red)); } outfile.close(); } TGA_Reader TGA_Reader::add_green_channel(int value) { TGA_Reader copy(*this); for (auto& pixel : copy.pixels) { int green_val = static_cast<int>(pixel.green) + value; // 钳制到0-255的合法范围 green_val = max(0, min(green_val, 255)); pixel.green = static_cast<unsigned char>(green_val); } return copy; }
修复说明
- 改用无符号字符类型:将所有存储图像数据和TGA头的
char替换为unsigned char,彻底避免有符号类型的解析和溢出问题。 - 修复变量作用域:移除if块内的变量重定义,直接修改外层的颜色值变量,确保范围钳制生效。
- 有效类型转换:使用
static_cast进行安全的类型转换,并将转换后的值赋值给绿色通道。 - 替换硬编码路径:
createFile函数使用传入的参数作为输出路径,增强灵活性。 - 添加文件检查:创建输出文件时检查是否成功打开,避免后续无意义操作。
- 优化循环写法:使用范围for循环遍历像素,代码更简洁且不易出错。
内容的提问来源于stack exchange,提问作者DJA15
相关产品推荐
相关产品推荐

