【发布时间】:2016-04-05 13:35:08
【问题描述】:
我正在尝试使用 c++ 读取.bmp 文件,并将标准化的灰度值(RGB 值的平均值)保存到 Ubuntu 14.04 下的向量中。不知何故,向量的值最终完全错误。你能想象为什么吗?
std::vector<double> readBMP(const char* filename, int* width, int* height){
std::vector<double> bmp;
FILE* f = fopen(filename, "rb");
if(f == NULL){
std::cerr << "file not found!" << std::endl;
std::vector<double> empty;
width = NULL;
height = NULL;
return empty;
}
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header
// extract image height and width from header
*width = *(int*)&info[18];
*height = *(int*)&info[22];
int data_offset = *(int*)(&info[0x0A]);
fseek(f, (long int)(data_offset - 54), SEEK_CUR);
int row_padded = (*width*3 + 3) & (~3);
unsigned char* data = new unsigned char[row_padded];
unsigned char tmp;
for(int i = 0; i < *height; i++)
{
fread(data, sizeof(unsigned char), row_padded, f);
for(int j = 0; j < *width*3; j += 3)
{
// Convert (B, G, R) to (R, G, B)
tmp = data[j];
data[j] = data[j+2];
data[j+2] = tmp;
bmp.push_back(((double)data[j]+(double)data[j+1]+(double)data[j+2])/(3*255));
std::cout << "R: "<< (int)data[j] << " G: " << (int)data[j+1]<< " B: " << (int)data[j+2]<< std::endl;
}
}
return bmp;
}
我打印了 rgb 值,并用一个有四个像素的示例图像进行了检查:
black | black | black
---------------------
grey | grey | grey
---------------------
white | white | white
预期的输出应该是(它被颠倒了):
R: 255 G: 255 B: 255
R: 255 G: 255 B: 255
R: 255 G: 255 B: 255
R: 128 G: 128 B: 128
R: 128 G: 128 B: 128
R: 128 G: 128 B: 128
R: 0 G: 0 B: 0
R: 0 G: 0 B: 0
R: 0 G: 0 B: 0
但它是:
R: 255 G: 255 B: 255
R: 255 G: 255 B: 255
R: 255 G: 255 B: 255
R: 128 G: 128 B: 255
R: 128 G: 255 B: 128
R: 255 G: 128 B: 128
R: 0 G: 0 B: 255
R: 0 G: 255 B: 0
R: 255 G: 0 B: 0
注意: 该代码是此问题答案的修改版本: read pixel value in bmp file
【问题讨论】:
-
尺寸值是否与宽*高匹配? (标头中的地址 0x22)。还要确保除了 54 字节标头之外没有要考虑的偏移量 (0x0A)。
-
我检查了宽度和高度,读取正确。你的意思是什么偏移量?
-
有时标头不是标准的并且大于 54 字节。如果是这种情况,您需要使用
fseek将光标移动到数据块的开头。后续问题,您使用的是什么操作系统? -
我更新了问题,我使用的是 Ubuntu 14.04。我怎么看它的标题不标准?
-
int data_offset = *(int*)(&info[0x0A]); fseek(f, (long int)(data_offset - 54), SEEK_CUR);