我正在尝试用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
答案 0 :(得分:2)
根据编码方式,您的BMP标头可能不是标准标头,其大小将大于54个字节。如果是这种情况,则需要使用fseek
将光标移动到数据块的开头。
int data_offset = *(int*)(&info[0x0A]);
if (data_offset > 54) {
fseek(f, (long int)(data_offset - 54), SEEK_CUR);
}
正如Brandon所指出的那样,您的图片是按照格式规范(由于您指定在Ubuntu上)指定的颠倒编码:
像素阵列是32位DWORD的块,用于逐像素地描述图像。通常,像素相对于正常图像光栅扫描顺序“倒置”存储,从左下角开始,从左到右,然后从图像的底部到顶部逐行。[5]除非使用BITMAPCOREHEADER,否则当图像高度值为负时,未压缩的Windows位图也可以从上到下存储。
答案 1 :(得分:1)
停止对补偿进行硬编码。实际上在info[10] + (info[11] << 8)
处找到像素的偏移量,其中info是标题。
#include <cstdio>
#include <cstdlib>
#include <cstdint>
#include <vector>
typedef struct bitmap
{
unsigned short bpp;
unsigned int width, height;
std::vector<unsigned char> pixels;
} bitmap;
bool LoadBmp(const char *filepath, bitmap *bmp)
{
FILE *f = fopen(filepath, "rb");
if (f)
{
bmp->bpp = 0;
bmp->width = 0;
bmp->height = 0;
bmp->pixels.clear();
unsigned char info[54] = {0};
fread(info, sizeof(unsigned char), 54, f);
bmp->width = info[18] + (info[19] << 8); //Width
bmp->height = info[22] + (info[23] << 8); //Height
bmp->pixels.resize(((((bmp->width * bmp->height) + 31) & ~31) / 8) * bmp->height); //Size of the pixels in the bitmap.
fseek(f, info[10] + (info[11] << 8), SEEK_SET); //Seek to Pixel Offset.
fread(&bmp->pixels[0], sizeof(unsigned char), bmp->pixels.size(), f); //Read the pixels.
fclose(f);
//Do whatever with pixels.. Flip them.. Swap BGR to RGB, etc..
return true;
}
return false;
}
最后,您的黑色像素位于白色像素下方,因为位图存储为颠倒。你必须自己翻转或自下而上阅读。
答案 2 :(得分:1)
最后我的代码是正确的,万一有人偶然发现了这个问题:我的错误是,图像是在ABGR中,我认为是BGR。
#include <cstdio>
#include <iostream>
#include <vector>
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]);
if(data_offset > 0)
fseek(f, (long int)(data_offset - 53), SEEK_CUR);
std::cout << " Name: " << filename << std::endl;
std::cout << " Width: " << *width << std::endl;
std::cout << "Height: " << *height << std::endl;
std::cout << "Offset: " << data_offset << std::endl;
int row_padded = (*width*4 + 4) & (~4);
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 < row_padded; j += 4)
{
// 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+2]+(double)data[j+1]+(double)data[j+2])/(3*255));
//std::cout << "R: "<< (int)data[j+1] << " G: " << (int)data[j+2]<< " B: " << (int)data[j+3]<< std::endl;
}
}
free(data);
//reverse order of the vector
std::vector<double>bmp_final;
std::cout << bmp.size() << std::endl;
for(int i=*height-1; i>=0; --i){
for(int j=0; j<*width; ++j){
bmp_final.push_back(bmp.at(*width*i+j));
}
}
return bmp_final;
}
感谢大家的帮助!