はじめに
Bitmapファイル(*.bmp)は、画像データの先頭に画像の幅や高さ、ビット数などの情報を付加し、バイナリデータとしてファイルに保存されたファイルなので、画像データをプログラムから扱うのは、非常に便利なフォーマットです。
また、Bitmapファイルは、Jpegファイルのように画像ファイルに保存→読込をすることで、保存前の画像データとの誤差も生じないため、画像処理をする画像データを保存するには、Bitmapファイルフォーマットが良く用いられます。
最近では、C++ではOpenCV、C#では.NETのBitmapクラスなどがあるので、Bitmapファイルの中身を意識することなく、Bitmapファイルに保存/読込ができます。
工業用のカメラでは、1画素あたり10bit、12bitのグレースケールに対応したカメラがかなり普及してきていますが、OpenCVや.NETのライブラリでは、10bitや12bitの画像に対応していないことの方が多いのですが、ビットフィールと呼ばれる少々特殊な設定をすることで、Bitmapファイルでも対応することが可能となります。
そのため、Bitmapファイルの中身の構造を理解しておくことが重要となります。
Bitmapファイルの内部構造
Bitmapファイルは、決まった位置に特定の情報が配置されたメモリを、バイナリファイルとして保存することで、Bitmapファイル(*.bmp)となります。
この配置位置と、それぞれの意味について説明します。
Bitmapファイル全体の構造
まず、Bitmapファイルがどのようなブロックで構成されているか、全体像を把握しましょう。
BITMAPFILEHEADER | ビットマップファイルヘッダー ファイル全体の情報を格納 |
14バイト |
---|---|---|
BITMAPINFOHEADER | ビットマップインフォヘッダー 幅、高さ、ビット数などの画像データに関する情報を格納 |
40バイト |
カラーパレット(無い場合もあり) | 画像データをどの色でモニタ上に表示するか?の設定 | 4 x index数 |
画像データ | 画像データが、通常、画像の左下を原点として格納されている。 24bitカラー画像の場合は、B, G, R, B, G, R・・の順番 |
それでは、各ブロックの詳細を見ていきましょう。
1. ファイルヘッダー (BITMAPFILEHEADER): 14バイト固定
-
ファイルの先頭に必ず存在し、ファイルがBMPであることや、ピクセルデータまでのオフセットなどを示します。
オフセット(byte) サイズ(byte) フィールド名 説明 0 2 bfType
ファイルタイプ。必ず "BM" (0x4D42) 2 4 bfSize
ファイル全体のサイズ (バイト) 6 2 bfReserved1
予約領域 (通常 0) 8 2 bfReserved2
予約領域 (通常 0) 10 4 bfOffBits
ファイル先頭からピクセルデータの開始位置までのオフセット (バイト)
2. 情報ヘッダー (BITMAPINFOHEADER): 40バイト固定
-
画像の詳細情報(幅、高さ、色深度、圧縮形式など)を格納します。
オフセット(byte) サイズ(byte) フィールド名 説明 14 4 biSize
この情報ヘッダーのサイズ (バイト)。通常 40 (0x28)。 18 4 biWidth
画像の幅 (ピクセル) 22 4 biHeight
画像の高さ (ピクセル)。
正の値はボトムアップ形式 (左下原点)
負の値はトップダウン形式 (左上原点)
使用するプログラムによっては、負の値に対応していない場合もあります。26 2 biPlanes
プレーン数 (常に 1) 28 2 biBitCount
1ピクセルあたりのビット数 (色深度)。1, 4, 8, 16, 24, 32 など。 30 4 biCompression
圧縮形式 (下記参照) 34 4 biSizeImage
ピクセルデータ部分のサイズ (バイト)。
無圧縮(BI_RGB)の場合、0でも可 (パディング込みで計算可能)。38 4 biXPelsPerMeter
水平解像度 (ピクセル/メートル)。通常 0。 42 4 biYPelsPerMeter
垂直解像度 (ピクセル/メートル)。通常 0。 46 4 biClrUsed
カラーパレット内の色数。
0の場合、biBitCount
に基づいて最大色数が使われる (例: 8bitなら256色)。50 4 biClrImportant
重要な色の数。0の場合、全ての色が重要。
3. カラーパレット (Color Palette) または ビットマスク: オプション、可変長
-
biBitCount
が 1, 4, 8 の場合に存在します (インデックスカラー)。-
biClrUsed
で指定された数、またはbiBitCount
から計算される最大色数分のRGBQUAD
構造体の配列です。 -
RGBQUAD
構造体 (4バイト): 青(B), 緑(G), 赤(R), 予約(通常0) の順で各1バイト。
-
-
カラーパレット: BMPファイル、特に色数が少ない画像(1bit, 4bit, 8bit)を効率的に格納するために「カラーパレット」という仕組みを利用します。これは「インデックスカラー」方式とも呼ばれます。
カラーパレットが存在する条件:
- 情報ヘッダーの
biBitCount
(1ピクセルあたりのビット数) が 1, 4, 8 のいずれかであり、かつbiCompression
がBI_RGB
またはBI_RLE8
,BI_RLE4
の場合に、カラーパレットが必須となります。 -
biBitCount
が 16, 24, 32 の場合は、基本的にピクセルデータに直接色情報が含まれるため、カラーパレットは通常使用しません。
カラーパレットの構造:
-
カラーパレットは、情報ヘッダー (
BITMAPINFOHEADER
など) の直後、かつピクセルデータの前に配置されます。 -
パレットは、
RGBQUAD
という構造体の配列で構成されます。RGBQUAD
は1つの色を定義するための4バイトのデータです。typedef struct tagRGBQUAD { BYTE rgbBlue; // 青成分 (0-255) BYTE rgbGreen; // 緑成分 (0-255) BYTE rgbRed; // 赤成分 (0-255) BYTE rgbReserved; // 予約領域 (通常は 0) } RGBQUAD;
-
rgbBlue
,rgbGreen
,rgbRed
で色の三原色を各8ビット(0-255)で指定します。 -
rgbReserved
は通常0ですが、ファイル形式やアプリケーションによってはアルファ値(不透明度)として解釈される可能性もゼロではありません(ただしBMPの標準的な仕様ではありません)。
-
パレットのサイズ (色数):
- パレットに格納される
RGBQUAD
構造体の数(=パレットの色数)は、情報ヘッダーのbiClrUsed
フィールドによって決まります。-
biClrUsed
が 0 より大きい値の場合: その値がパレットの色数となります。例えばbiClrUsed
が 100 なら、100個のRGBQUAD
(計 400バイト) がパレットとして存在します。ただし、biBitCount
で表現可能な最大色数を超えることはできません (例: 4bit画像ならbiClrUsed
は16以下)。 -
biClrUsed
が 0 の場合:biBitCount
が示す最大の色数がパレットサイズとなります。-
biBitCount
= 1 : 2色 (2^1) のパレット (通常、白と黒) -
biBitCount
= 4 : 16色 (2^4) のパレット -
biBitCount
= 8 : 256色 (2^8) のパレット
この場合、パレットの合計バイト数は(2^biBitCount) * sizeof(RGBQUAD)
となります。
-
-
ピクセルデータとの関係:
-
biBitCount
が 1, 4, 8 の場合、ピクセルデータには実際のRGB値ではなく、**カラーパレットのインデックス(番号)**が格納されています。 - 例えば、8bit画像 (
biBitCount
=8) の場合、ピクセルデータは1バイト単位で読み込まれ、そのバイト値 (0~255) がそのままカラーパレットのインデックスとなります。値が10
であれば、カラーパレットの11番目 (0から数えるため) のRGBQUAD
で定義された色が、そのピクセルの色となります。 - 4bit画像 (
biBitCount
=4) の場合、1バイトに2ピクセル分の情報が含まれます。通常、上位4ビットが1ピクセル目のインデックス (0~15)、下位4ビットが2ピクセル目のインデックス (0~15) となります。 - 1bit画像 (
biBitCount
=1) の場合、1バイトに8ピクセル分の情報が含まれます。各ビットがインデックス (0または1) に対応します。
- 情報ヘッダーの
-
ビットマスク (
BI_BITFIELDS
指定時):- 情報ヘッダーの
biCompression
フィールドにBI_BITFIELDS
(値: 3) が指定されている場合、これは通常 16bpp または 32bpp のダイレクトカラーモードで使用されます。 - このモードでは、ピクセルデータ内のビットがどの色成分(赤、緑、青、場合によってはアルファ)に対応するかを定義するためのビットマスクが必要となります。
-
重要:
BI_BITFIELDS
が指定された場合、カラーパレットは存在しません。カラーパレットが配置されるべき場所(情報ヘッダーの直後)には、代わりに RGB のビットマスクが配置されます。 - 具体的には、情報ヘッダーの直後に、以下の3つの
DWORD
(符号なし4バイト整数、計12バイト) がこの順序で格納されます。-
Red Mask: ピクセルデータ内の赤成分に対応するビットを示すマスク (例: 16bit 5-6-5 なら
0xF800
)。 -
Green Mask: ピクセルデータ内の緑成分に対応するビットを示すマスク (例: 16bit 5-6-5 なら
0x07E0
)。 -
Blue Mask: ピクセルデータ内の青成分に対応するビットを示すマスク (例: 16bit 5-6-5 なら
0x001F
)。
-
Red Mask: ピクセルデータ内の赤成分に対応するビットを示すマスク (例: 16bit 5-6-5 なら
- これらのマスクがあるため、ソフトウェアはピクセルデータ(16bit または 32bit の値)から正確な RGB 値を抽出できます。
- 情報ヘッダーの
4. ピクセルデータ (Pixel Data):
- 実際の画像データが格納されます。
この開始位置はファイルヘッダーのbfOffBits
で示されます。 - 格納順序:
負の値に対応していないプログラムもあるので注意
-
パディング (Padding):
- 各行のデータサイズ(バイト数)は、必ず4バイトの倍数になるように、末尾に0x00などのパディングデータが付加されます。これはメモリアクセス効率のためです。
- 計算式:
stride = floor((biBitCount * biWidth + 31) / 32) * 4
- ピクセルデータ全体のサイズ (
biSizeImage
) は、無圧縮の場合stride * abs(biHeight)
で計算できます。
(例) 8bitモノクロ 802 x 600画素の画像の場合
メモリ上は 804 x 600画素分用意し、行の最後(右側)の2画素分の値は0にします。
-
色深度ごとのデータ形式:
- 1-bit: 1ピクセルを1ビットで表現。8ピクセルで1バイト。値はカラーパレットのインデックス0または1に対応。バイト内のビット順は通常、最上位ビット(MSB)が左端のピクセルに対応。
- 4-bit: 1ピクセルを4ビットで表現。2ピクセルで1バイト。通常、1バイトの上位4ビットが左側のピクセル、下位4ビットが右側のピクセルのインデックス(0-15)に対応。
- 8-bit: 1ピクセルを8ビット(1バイト)で表現。値はカラーパレットのインデックス(0-255)。
-
16-bit: 1ピクセルを16ビット(2バイト)で表現。
-
biCompression
=BI_RGB
: 通常 RGB 5-5-5 形式 (最上位ビットは予約)。赤・緑・青 各5ビット。 -
biCompression
=BI_BITFIELDS
: ヘッダー直後のビットマスクに従って RGB 値を格納。一般的なのは RGB 5-6-5 形式(赤5, 緑6, 青5ビット)。
-
- 24-bit: 1ピクセルを24ビット(3バイト)で表現。B, G, R の順で各8ビット。カラーパレットは使用しない (フルカラー)。
-
32-bit: 1ピクセルを32ビット(4バイト)で表現。
-
biCompression
=BI_RGB
: 通常 B, G, R, 予約(未使用, A) の順で各8ビット。予約バイトはC言語では0を指定する場合が多かったか、.NETではアルファ値(透過率)として使われ、不透明の場合255を指定する。 -
biCompression
=BI_BITFIELDS
: ヘッダー直後のビットマスクに従って RGB(A) 値を格納。
-
-
圧縮形式 (
biCompression
フィールドの値):-
0
(BI_RGB
): 無圧縮 (最も一般的) -
1
(BI_RLE8
): 8-bit Run-Length Encoding (8bppボトムアップ画像用) -
2
(BI_RLE4
): 4-bit Run-Length Encoding (4bppボトムアップ画像用) -
3
(BI_BITFIELDS
): ビットフィールド指定 (16bpp, 32bpp画像用)。
カラーマスクが情報ヘッダ直後 (カラーパレットの代わり) に配置される。トップダウン形式も可能。 -
4
(BI_JPEG
): JPEG圧縮されたデータを含む (埋め込みJPEG、稀) -
5
(BI_PNG
): PNG圧縮されたデータを含む (埋め込みPNG、稀)
-
モノクロ10~16bit画像の場合
ビットフィールドの設定を用います。
BITMAPFILEHEADER
のbfOffBits
を66 (= 14 + 40 + 4 x 3)
BITMAPINFOHEADER
のbiBitCount
を16
BITMAPINFOHEADER
のbiCompression
をBI_BITFIELDS
に設定します。
さらに、カラーパレットとしてRGBQUAD
を3つ分使用します。
ここでは、カラーパレットというよりも、1画素のデータのビット数(16bit)に対して、どのビットが有効なのか?を示すビットマスクとして用います。
RGBQUAD
の3つのうち、
bmiColors[0]がR(赤)
bmiColors[1]がG(緑)
bmiColors[2]がB(青)
の画像表示色のビットマスクとなります。
例えば、モノクロ10bitの場合、16bit中下位10bitが有効データとなります。
ビットで表現すると 0000001111111111 となります。
16進数で32bitの値として表現すると 0x0003FF となります。
これをRGBQUAD
で表すと、RGBQUAD
全体32bit中の上位ビットから順に
rgbReserved
, rgbRed
, rgbGreen
, rgbBlue
の順番で並んでいるので、最終的にカラーパレットは
// Rのビットマスク
bmiColors[0].rgbReserved = 0x00
bmiColors[0].rgbRed = 0x00
bmiColors[0].rgbGreen = 0x03
bmiColors[0].rgbBlue = 0xFF
// Gのビットマスク
bmiColors[1].rgbReserved = 0x00
bmiColors[1].rgbRed = 0x00
bmiColors[1].rgbGreen = 0x03
bmiColors[1].rgbBlue = 0xFF
// Bのビットマスク
bmiColors[2].rgbReserved = 0x00
bmiColors[2].rgbRed = 0x00
bmiColors[2].rgbGreen = 0x03
bmiColors[2].rgbBlue = 0xFF
となります。
ビットフィールドの設定は、あまり一般的に用いられてません。
そのためビットフィールドに対応していないプログラム、ライブラリが多くありますが、Windowsのフォトアプリでは、ビットフィールドの値が反映され、画像が表示されます。
モノクロの10~16bitで保存したBitmap画像ファイルはWindowsのエクスプローラでは32bitと表示されます。
おまけ。便利ツールの紹介
Bitmapファイルは、画像データにヘッダ情報が付いたただのバイナリファイルなので、Bitmapファイルの構造を確認するには、バイナリエディタがあると便利です。
私が良くお世話になっているのは、 TSXBIN というソフト
これ、かなりおススメです。
https://www.vector.co.jp/soft/dl/winnt/util/se513258.html