如何将BMP像素值读入数组?

我用C ++编写代码(在Windows上),我试图提取灰度bmp的像素值。 我不关心保留任何元数据,只想将像素值存储在char数组中。 我一直无法find一个手动的标准或“典型”的方式,所以我想知道是否有一个简单的库,人们用来加载位图到内存中。

提前致谢!

将整个文件读入内存。 前面会有一个小标题,剩下的就是像素值。

第一部分将是一个BITMAPFILEHEADER结构。 您唯一关心的部分是bfOffBits,它提供从文件开头到像素值的字节数。

BITMAPFILEHEADER之后的下一部分将是BITMAPINFOHEADER 这将有助于确定像素的格式。

如果位深度需要一个调色板,那么后面会有一个调色板。

有几个像素值的问题。 首先是顺序是(蓝色,绿色,红色),正如其他人所做的那样。 其次是行从图像的底部到顶部,再次从其他人向后。 最后,一行中的字节数总是被填充到4的下一个倍数。

我几乎忘了提及,JPEG或PNG文件可能被编码为BMP,但这并不常见。 看看BITMAPINFOHEADER的biCompression字段,如果它不是BI_RGB,你需要多一点帮助。

并准备去代码,用g ++(不是Windows,但可以帮助某人)测试:

 #pragma pack(1) #include <iostream> #include <fstream> #include <vector> using namespace std; #include "bmp.h" vector<char> buffer; PBITMAPFILEHEADER file_header; PBITMAPINFOHEADER info_header; void fill() { std::ifstream file("data.bmp"); if (file) { file.seekg(0,std::ios::end); streampos length = file.tellg(); file.seekg(0,std::ios::beg); buffer.resize(length); file.read(&buffer[0],length); file_header = (PBITMAPFILEHEADER)(&buffer[0]); info_header = (PBITMAPINFOHEADER)(&buffer[0] + sizeof(BITMAPFILEHEADER)); } } int main() { fill(); cout << buffer[0] << buffer[1] << endl; cout << file_header->bfSize << endl; cout << info_header->biWidth << " " << info_header->biHeight << endl; return 0; } 

在bmp.hi中定义了结构:

 #pragma once typedef int LONG; typedef unsigned short WORD; typedef unsigned int DWORD; typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, *PBITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER, *PBITMAPINFOHEADER; 

如果在Visual Studios中编码,在声明tagBITMAPFILEHEADER和tagBITMAPINFOHEADER结构(显示在Yola的响应中)之前,一定要包含“#pragma pack(2)”。 此外,结构将填充到下一个4字节的边界,而不是下一个2字节的边界,数据将是垃圾。

参考http://tipsandtricks.runicsoft.com/Cpp/BitmapTutorial.html

您可以尝试MagicWand ImageMagic库的API。

那里肯定有图书馆(见其他答案),但在一个很快,它坦率地说是一个大脑死亡简单的文件格式,你可以很容易地解析自己。 细节在这里:

http://www.fileformat.info/format/bmp/egff.htm

(我已经退出Win32几年了,但LoadImage函数可以从BMP文件中获取HBITMAP,我不确定如何直接将它转换为像素数组,但我想可能会出现一些扭曲与DC,可以让你抢的价值http://support.microsoft.com/kb/158898

更多提示: http : //alexkr.com/source-code/26/accessing-bitmap-pixels-in-gdi/ )

你有两个很好的选择:

  1. 自己加载和解析BMP文件。 BMP文件以BITMAPFILEHADER开头,接着是BITMAPINFOHEADER,接着是0或更多的RGBQUAD(调色板条目)。 像素数据的偏移位于BITMAPFILEHADER中,但您应该检查BITMAPINFOHEADER以确保图像格式是您所期望/支持的。

  2. 使用LR_CREATEDIBSECTION标志调用LoadImage()API,它将返回一个DIB节的句柄。 接下来调用GetObject()传递返回的句柄和一个指向DIBSECTION结构的指针。 然后,您可以阅读DIBSECTION结构中的位图大小,格式,指向像素数据的指针等。

如果你在Windows上,选项2更好,因为大概LoadImage()会为你检查无效的文件格式,并且可以加载更多的不仅仅是BMP文件。

当访问Windows BMP像素时,记住行总是DWORD对齐的。

在Yola写的内容上,应该能够读入和输出文件。 它没有很好的测试,但似乎工作。 它使用输出时读入的文件的格式。

 #include <iostream> #include <unistd.h> #include <fstream> using std::cout; using std::endl; using std::ofstream; using std::ifstream; #pragma pack(1) #pragma once typedef int LONG; typedef unsigned short WORD; typedef unsigned int DWORD; typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, *PBITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER, *PBITMAPINFOHEADER; unsigned char** reds; unsigned char** greens; unsigned char** blues; int rows; int cols; void ColorTest() { // Makes Red Rectangle in top left corner. Rectangle stretches to right alot for (int i = rows / 10; i < 3 * rows / 10; i++) for (int j = cols / 10; j < 7 * cols / 10; j++) reds[i][j] = 0xff; // Makes small green box in bottom right for (int i = 8 * rows / 10; i < rows; i++) for (int j = 8 * cols / 10; j < cols; j++) greens[i][j] = 0xff; // Makes White box in the middle of the screeene for (int i = rows * 4 / 10; i < rows * 6 / 10; i++) for (int j = cols * 4 / 10; j < cols * 6 / 10; j++) { greens[i][j] = 0xff; reds[i][j] = 0xff; blues[i][j] = 0xff; } // Blue verticle rectangle bottom left for (int i = rows * 6 / 10; i < rows; i++) for (int j = cols * 0; j < cols * 1 / 10; j++) blues[i][j] = 0xff; } void RGB_Allocate(unsigned char**& dude) { dude = new unsigned char*[rows]; for (int i = 0; i < rows; i++) dude[i] = new unsigned char[cols]; } bool FillAndAllocate(char*& buffer, const char* Picture, int& rows, int& cols, int& BufferSize) { //Returns 1 if executed sucessfully, 0 if not sucessfull std::ifstream file(Picture); if (file) { file.seekg(0, std::ios::end); std::streampos length = file.tellg(); file.seekg(0, std::ios::beg); buffer = new char[length]; file.read(&buffer[0], length); PBITMAPFILEHEADER file_header; PBITMAPINFOHEADER info_header; file_header = (PBITMAPFILEHEADER) (&buffer[0]); info_header = (PBITMAPINFOHEADER) (&buffer[0] + sizeof(BITMAPFILEHEADER)); rows = info_header->biHeight; cols = info_header->biWidth; BufferSize = file_header->bfSize; return 1; } else { cout << "File" << Picture << " don't Exist!" << endl; return 0; } } void GetPixlesFromBMP24(unsigned char** reds, unsigned char** greens, unsigned char** blues, int end, int rows, int cols, char* FileReadBuffer) { // end is BufferSize (total size of file) int count = 1; int extra = cols % 4; // The nubmer of bytes in a row (cols) will be a multiple of 4. for (int i = 0; i < rows; i++){ count += extra; for (int j = cols - 1; j >= 0; j--) for (int k = 0; k < 3; k++) { switch (k) { case 0: reds[i][j] = FileReadBuffer[end - count++]; break; case 1: greens[i][j] = FileReadBuffer[end - count++]; break; case 2: blues[i][j] = FileReadBuffer[end - count++]; break; } } } } void WriteOutBmp24(char* FileBuffer, const char* NameOfFileToCreate, int BufferSize) { std::ofstream write(NameOfFileToCreate); if (!write) { cout << "Failed to write " << NameOfFileToCreate << endl; return; } int count = 1; int extra = cols % 4; // The nubmer of bytes in a row (cols) will be a multiple of 4. for (int i = 0; i < rows; i++){ count += extra; for (int j = cols - 1; j >= 0; j--) for (int k = 0; k < 3; k++) { switch (k) { case 0: //reds FileBuffer[BufferSize - count] = reds[i][j]; break; case 1: //green FileBuffer[BufferSize - count] = greens[i][j]; break; case 2: //blue FileBuffer[BufferSize - count] = blues[i][j]; break; } count++; } } write.write(FileBuffer, BufferSize); } int main(int args, char** cat) { char* FileBuffer; int BufferSize; #define Picture "ReadInPicture.bmp" if (!FillAndAllocate(FileBuffer, Picture, rows, cols, BufferSize)){cout << "File read error" << endl; return 0;} cout << "Rows: " << rows << " Cols: " << cols << endl; RGB_Allocate(reds); RGB_Allocate(greens); RGB_Allocate(blues); GetPixlesFromBMP24( reds, greens, blues,BufferSize, rows, cols, FileBuffer); ColorTest(); #define WriteOutFile "OutputPicture.bmp" WriteOutBmp24(FileBuffer, WriteOutFile,BufferSize); return 1; }