读取bmp文件中的像素值

如何在Windows上以C或C ++的所有像素[h * w]读取24位BMP图像的颜色值[更好,没有任何第三方库]。 我得到了Dev-C ++
一个工作代码将非常受欢迎,因为我从未参与过图像阅读,并且在谷歌搜索后来到了SO [如果你能比我更好,请提供链接]。

你可以尝试这个:

unsigned char* readBMP(char* filename) { int i; FILE* f = fopen(filename, "rb"); unsigned char info[54]; fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header // extract image height and width from header int width = *(int*)&info[18]; int height = *(int*)&info[22]; int size = 3 * width * height; unsigned char* data = new unsigned char[size]; // allocate 3 bytes per pixel fread(data, sizeof(unsigned char), size, f); // read the rest of the data at once fclose(f); for(i = 0; i < size; i += 3) { unsigned char tmp = data[i]; data[i] = data[i+2]; data[i+2] = tmp; } return data; } 

现在data应该包含像素的(R,G,B)值。 像素(i,j)的颜色存储在data[3 * (i * width + j)]data[3 * (i * width + j) + 1]data[3 * (i * width + j) + 2]

在最后一部分中,完成每个第一和第三像素之间的交换,因为窗口将颜色值存储为(B,G,R)三元组,而不是(R,G,B)。

填充修复后的readBMP函数代码:

 unsigned char* ReadBMP(char* filename) { int i; FILE* f = fopen(filename, "rb"); if(f == NULL) throw "Argument Exception"; unsigned char info[54]; fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header // extract image height and width from header int width = *(int*)&info[18]; int height = *(int*)&info[22]; cout << endl; cout << " Name: " << filename << endl; cout << " Width: " << width << endl; cout << "Height: " << height << endl; 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; cout << "R: "<< (int)data[j] << " G: " << (int)data[j+1]<< " B: " << (int)data[j+2]<< endl; } } fclose(f); return data; } 

这是一个有效的C ++版本的答案:

 #include  #include  #include  #include  #include  #include  std::vector readBMP(const std::string &file) { static constexpr size_t HEADER_SIZE = 54; std::ifstream bmp(file, std::ios::binary); std::array header; bmp.read(header.data(), header.size()); auto fileSize = *reinterpret_cast(&header[2]); auto dataOffset = *reinterpret_cast(&header[10]); auto width = *reinterpret_cast(&header[18]); auto height = *reinterpret_cast(&header[22]); auto depth = *reinterpret_cast(&header[28]); std::cout << "fileSize: " << fileSize << std::endl; std::cout << "dataOffset: " << dataOffset << std::endl; std::cout << "width: " << width << std::endl; std::cout << "height: " << height << std::endl; std::cout << "depth: " << depth << "-bit" << std::endl; std::vector img(dataOffset - HEADER_SIZE); bmp.read(img.data(), img.size()); auto dataSize = ((width * 3 + 3) & (~3)) * height; img.resize(dataSize); bmp.read(img.data(), img.size()); char temp = 0; for (auto i = dataSize - 4; i >= 0; i -= 3) { temp = img[i]; img[i] = img[i+2]; img[i+2] = temp; std::cout << "R: " << int(img[i] & 0xff) << " G: " << int(img[i+1] & 0xff) << " B: " << int(img[i+2] & 0xff) << std::endl; } return img; } 

我无法对顶级答案发表评论,因为我还没有足够的stackoverflow代表,但我只是想指出一个非常关键的错误。

某些位图可以写入负高度,因此当您尝试分配图像数据缓冲区时,代码将与std::bad_alloc一起崩溃。 负高度的位图意味着图像数据从上到下而不是传统的从下到上存储。 因此,顶级答案的稍微好一点的版本(仍然不包括具有不同字节序和字节大小的系统的可移植性):

 unsigned char* readBMP(char* filename) { int i; FILE* f = fopen(filename, "rb"); unsigned char info[54]; fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header // extract image height and width from header int width = *(int*)&info[18]; int height = *(int*)&info[22]; int heightSign =1; if(height<0){ heightSign = -1; } int size = 3 * width * abs(height); unsigned char* data = new unsigned char[size]; // allocate 3 bytes per pixel fread(data, sizeof(unsigned char), size, f); // read the rest of the data at once fclose(f); if(heightSign == 1){ for(i = 0; i < size; i += 3) { //code to flip the image data here.... } } return data; } 

您必须首先读取位图标头。 在获得位图标题中的数据偏移量并逐行读取像素后,请注意bmp文件格式的填充。

看看msdn http://msdn.microsoft.com/en-us/library/aa452883.aspx

http://msdn.microsoft.com/en-us/library/windows/desktop/dd318229(v=vs.85).aspx

我创建了一个BitMap类,适用于每像素24位的bmp文件。 如果bmp不兼容,则应该收到相关错误。

它几乎与维基百科文章完全一致。 (一个问题是它不适用于像素数组偏移大于255的文件。这在代码中注明,应该很容易修复。)

我一直在使用mspaint创建的bmp文件。

这是一个示例用法

example.cpp

 #include "bmp.h" int main() { // load the file. The constructor now does most of the work BitMap example_bmp("examplefile.bmp"); // get the vector  for the pixel at (1,1) std::vector example_vector = example_bmp.getPixel(1,1); } 

example_vector现在包含从图像顶部索引的坐标(1,1)处的像素的rgb(按此顺序)值,向下。 指数从0开始。请参阅维基百科示例。

这是头文件:

 #ifndef BMP_H #define BMP_H #include  #include  #include  class BitMap { private: unsigned char m_bmpFileHeader[14]; unsigned int m_pixelArrayOffset; unsigned char m_bmpInfoHeader[40]; int m_height; int m_width; int m_bitsPerPixel; int m_rowSize; int m_pixelArraySize; unsigned char* m_pixelData; char * m_copyname; const char * m_filename; public: BitMap(const char * filename); ~BitMap(); std::vector getPixel(int i,int j); void makeCopy(char * filename); void writePixel(int i,int j, int R, int G, int B); void swapPixel(int i, int j, int i2, int j2); void dispPixelData(); int width() {return m_width;} int height() {return m_height;} int vd(int i, int j); int hd(int i, int j); bool isSorted(); }; BitMap::BitMap( const char * filename) { using namespace std; m_filename = filename; ifstream inf(filename); if(!inf) { cerr<<"Unable to open file: "<>hex>>a; m_bmpFileHeader[i] = a; } if(m_bmpFileHeader[0]!='B' || m_bmpFileHeader[1]!='M') { cerr<<"Your info header might be different!\nIt should start with 'BM'.\n"; } /* THE FOLLOWING LINE ONLY WORKS IF THE OFFSET IS 1 BYTE!!!!! (it can be 4 bytes max) That should be fixed now. old line was m_pixelArrayOffset = m_bmpFileHeader[10]; */ unsigned int * array_offset_ptr = (unsigned int *)(m_bmpFileHeader + 10); m_pixelArrayOffset = *array_offset_ptr; if( m_bmpFileHeader[11] != 0 || m_bmpFileHeader[12] !=0 || m_bmpFileHeader[13] !=0 ) { std::cerr<< "You probably need to fix something. bmp.h("<<__LINE__<<")\n"; } //unsigned char m_bmpInfoHeader[40]; for(int i=0;i<40;i++) { inf>>hex>>a; m_bmpInfoHeader[i]=a; } int * width_ptr = (int*)(m_bmpInfoHeader+4); int * height_ptr = (int*)(m_bmpInfoHeader+8); m_width = *width_ptr; m_height = *height_ptr; printf("W: %i, H: %i", m_width, m_height); m_bitsPerPixel = m_bmpInfoHeader[14]; if(m_bitsPerPixel!=24) { cerr<<"This program is for 24bpp files. Your bmp is not that\n"; } int compressionMethod = m_bmpInfoHeader[16]; if(compressionMethod!=0) { cerr<<"There's some compression stuff going on that we might not be able to deal with.\n"; cerr<<"Comment out offending lines to continue anyways. bpm.h line: "<<__LINE__<<"\n"; } m_rowSize = int( floor( (m_bitsPerPixel*m_width + 31.)/32 ) ) *4; m_pixelArraySize = m_rowSize* abs(m_height); m_pixelData = new unsigned char [m_pixelArraySize]; inf.seekg(m_pixelArrayOffset,ios::beg); for(int i=0;i>hex>>a; m_pixelData[i]=a; } } BitMap::~BitMap() { delete[] m_pixelData; } void BitMap::dispPixelData() { for(int i=0;i BitMap::getPixel(int x, int y) { if(x v; v.push_back(0); v.push_back(0); v.push_back(0); y = m_height -1- y; //to flip things //std::cout<<"y: "<>c; copyfile< p1 = (*this).getPixel(i,j); std::vector p2 = (*this).getPixel(i2,j2); (*this).writePixel(i,j,p2[0],p2[1],p2[2]); (*this).writePixel(i2,j2,p1[0],p1[1],p1[2]); } #endif 

如何在Python中读取给定像素的RGB值,提供了一个简单的,可移植的便携式Python解决方案? 。 适应多种图像格式,负责填充等。

我通过didil尝试了上面的代码,我在下面引用作为参考(对不起,我没有足够的声誉来发表评论)。

代码编译好,但在for循环迭代期间崩溃。 我认为这与’我’是uint32_t而不是int有关 。 当’i’到达零时,for循环仍然有效,’i’减3,变为负值。 由于’i’是uint32_t,它的值变为正值并且大于0.因此,当’i’指向超出img存储的边界时,for循环永远不会完成并导致执行崩溃。

 #include  #include  #include  #include  #include  #include  std::vector readBMP(const std::string &file) { static constexpr size_t HEADER_SIZE = 54; std::ifstream bmp(file, std::ios::binary); std::array header; bmp.read(header.data(), header.size()); auto fileSize = *reinterpret_cast(&header[2]); auto dataOffset = *reinterpret_cast(&header[10]); auto width = *reinterpret_cast(&header[18]); auto height = *reinterpret_cast(&header[22]); auto depth = *reinterpret_cast(&header[28]); std::cout << "fileSize: " << fileSize << std::endl; std::cout << "dataOffset: " << dataOffset << std::endl; std::cout << "width: " << width << std::endl; std::cout << "height: " << height << std::endl; std::cout << "depth: " << depth << "-bit" << std::endl; std::vector img(dataOffset - HEADER_SIZE); bmp.read(img.data(), img.size()); auto dataSize = ((width * 3 + 3) & (~3)) * height; img.resize(dataSize); bmp.read(img.data(), img.size()); char temp = 0; for (auto i = dataSize - 4; i >= 0; i -= 3) { temp = img[i]; img[i] = img[i+2]; img[i+2] = temp; std::cout << "R: " << int(img[i] & 0xff) << " G: " << int(img[i+1] & 0xff) << " B: " << int(img[i+2] & 0xff) << std::endl; } return img; }