私はC++(Windows上)でコードを書いていて、グレースケールbmpのピクセル値を抽出しようとしています。メタデータを保持する必要はなく、ピクセル値をchar配列に格納したいだけです。これを手動で行う標準的または「典型的な」方法を見つけることができなかったので、ビットマップをメモリにロードするために人々が使用する単純なライブラリがあるのではないかと思います。
前もって感謝します!
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;
ファイル全体をメモリに読み込みます。先頭に小さなヘッダーがあり、残りはピクセル値になります。
最初の部分はBITMAPFILEHEADER構造になります。気にする唯一の部分は、ファイルの先頭からピクセル値までのバイト数を示す bfOffBits です。
の次の部分はBITMAPFILEHEADERになりますBITMAPINFOHEADER。これは、ピクセルのフォーマットを決定するのに役立ちます。
ビット深度で必要な場合は、この後にパレットが続きます。
ピクセル値にはいくつかの問題があります。1 つ目は、順序が (青、緑、赤) であり、他の人が行う方法とは正反対であることです。2 つ目は、行が画像の下から上に移動することです。最後に、行のバイト数は常に次の 4 の倍数までパディングされます。
言い忘れそうになりましたが、JPEG または PNG ファイルを BMP としてエンコードすることは可能ですが、これは一般的ではありません。のbiCompressionフィールドを見てくださいBITMAPINFOHEADER。BI_RGB以外の場合は、もう少し助けが必要です。
Visual Studio でコーディングする場合は、tagBITMAPFILEHEADER および tagBITMAPINFOHEADER 構造体 (Yola の応答に表示) を宣言する前に、必ず「#pragma pack(2)」を含めてください。そうしないと、構造体は次の 2 バイト境界ではなく、次の 4 バイト境界にパディングされ、データはガベージになります。
参照http://tipsandtricks.runicsoft.com/Cpp/BitmapTutorial.html
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;
}
ImageMagicライブラリのMagicWandAPIを試すことができます。
確かにそこにはライブラリがありますが(他の回答を参照)、簡単に言えば、非常に簡単に解析できる、脳死した単純なファイル形式です。詳細はこちら:
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/ )
2 つの適切なオプションがあります。
BMP ファイルを自分で読み込んで解析します。BMP ファイルは、BITMAPFILEHADER で始まり、BITMAPINFOHEADER が続き、その後に 0 個以上の RGBQUAD (パレット エントリ) が続きます。ピクセル データへのオフセットは BITMAPFILEHADER にありますが、BITMAPINFOHEADER をチェックして、イメージ フォーマットが期待/サポートされているものであることを確認する必要があります。
LR_CREATEDIBSECTION フラグを指定して LoadImage() API を呼び出すと、DIB セクションへのハンドルが返されます。次に、GetObject() を呼び出して、返されたハンドルと DIBSECTION 構造体へのポインターを渡します。次に、ビットマップのサイズ、フォーマット、ピクセル データへのポインターなどの DIBSECTION 構造体を読み取ります。
おそらく LoadImage() が無効なファイル形式をチェックし、BMP ファイル以外のものをロードできるため、Windows を使用している場合はオプション 2 が適しています。
Windows BMP ピクセルにアクセスする場合、行は常に DWORD で整列されることに注意してください。