web-dev-qa-db-ja.com

BMPピクセル値を配列に読み込むにはどうすればよいですか?

私はC++(Windows上)でコードを書いていて、グレースケールbmpのピクセル値を抽出しようとしています。メタデータを保持する必要はなく、ピクセル値をchar配列に格納したいだけです。これを手動で行う標準的または「典型的な」方法を見つけることができなかったので、ビットマップをメモリにロードするために人々が使用する単純なライブラリがあるのではないかと思います。

前もって感謝します!

ファイル全体をメモリに読み込みます。前面に小さなヘッダーがあり、残りはピクセル値になります。

最初の部分は BITMAPFILEHEADER 構造になります。気になるのはbfOffBitsだけです。これは、ファイルの先頭からピクセル値までのバイト数を示します。

BITMAPFILEHEADERの次の部分は BITMAPINFOHEADER になります。これは、ピクセルのフォーマットを決定するのに役立ちます。

ビット深度に必要な場合は、この後にパレットが続きます。

ピクセル値にはいくつかの落とし穴があります。まず、順序が(青、緑、赤)であり、他の人とは正反対です。 2つ目は、行が画像の下から上に移動し、他のすべての人から逆方向に移動することです。最後に、行のバイト数は常に次の4の倍数まで埋め込まれます。

JPEGまたはPNGファイルをBMPとしてエンコードすることは可能ですが、これは一般的ではありません。 BITMAPINFOHEADERのbiCompressionフィールドを見てください。それがBI_RGB以外の場合は、もう少し助けが必要です。

5
Mark Ransom

そして、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.hで、私は構造を定義しました:

#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;
15
Yola

visual Studioでコーディングする場合は、tagBITMAPFILEHEADERおよびtagBITMAPINFOHEADER構造体(Yolaの応答に表示)を宣言する前に、必ず「#pragmapack(2)」を含めてください。それ以外の場合、構造体は次の2バイト境界ではなく、次の4バイト境界に埋め込まれ、データはガベージになります。

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

4
Yoshimitsu

2つの良いオプションがあります:

  1. BMPファイルを自分でロードして解析します。BMPファイルはBITMAPFILEHADERで始まり、次にBITMAPINFOHEADERが続き、その後に0個以上のRGBQUAD(パレットエントリ)が続きます。オフセットピクセルデータへの変換はBITMAPFILEHADERにありますが、BITMAPINFOHEADERをチェックして、画像形式が期待どおり/サポートされていることを確認する必要があります。

  2. LR_CREATEDIBSECTIONフラグを指定してLoadImage()APIを呼び出すと、DIBセクションへのハンドルが返されます。次に、返されたハンドルとDIBSECTION構造体へのポインタを渡してGetObject()を呼び出します。次に、ビットマップサイズ、形式、ピクセルデータへのポインタなどのDIBSECTION構造を読み取ります。

オプション2は、Windowsを使用している場合に適しています。おそらく、LoadImage()が無効なファイル形式をチェックし、BMPファイル以上のものをロードできるためです。

Windows BMPピクセルにアクセスする場合、線は常にDWORDに揃えられていることに注意してください。

2
b_yang

Magic WandImageMagick ライブラリのAPIを試すことができます。

2
Albert Perrien

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;
}
2
philn

確かにそこにはライブラリがありますが(他の回答を参照)、Jiffyでは、率直に言って、自分自身を非常に簡単に解析できる、脳死した単純なファイル形式です。詳細はこちら:

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
Ben Zotto