画像データの構造・画素・ビットマップデータについて解説

このページではC言語で画像処理を行うための前知識として、画像データの構造・画素・ビットマップデータについて説明します。

画素(ピクセル)とは

まず画像データの構造を知る前に、画素とは何かについて見てみましょう。Wikipediaで画素(ピクセル)について分かりやすく説明してくれています。

ピクセル(英: pixel)、または画素とは、コンピュータで画像を扱うときの、色情報 (色調や階調) を持つ最小単位、最小要素。しばしばピクセルと同一の言葉として使われるドットとは、後者が単なる物理的な点情報であることで区別される。例えばディスプレイにおいて320×240ピクセルの画像を100%表示すれば320×240ドットとなるが、200%表示ならば640×480ドットとなる。

引用元:Wikipedia

画像データの構造

画像データはこの画素の集まりになります。例えば画像を大きく拡大していくと沢山の点が集まって構成されていることが確認できると思います。この一つ一つの点が画素です。

またその一つ一つの点はそれぞれ色が違うことも確認できると思います。画素は一般的に三原色(赤緑青、RGB)それぞれに対する輝度(赤青緑それぞれをどれくらい強くするかの指標)をもっており、そのRGBそれぞれの輝度によって色が異なります

輝度は一般的に 1 バイトで表せる 0〜255 の間の値になります。色を綺麗に表示するようなソフトではもっと広い範囲の輝度を持つものもあります。

例えば(R:255・G:0・B:0)の画素は赤色の点となります。(R:255・G:255・B:255)であれば白色の点となります。この輝度の組み合わせにより 256 × 256 × 256 色の表現が可能です。

画素の並びを図で表すと下のようになります。画素は RGB の3つの輝度持っていますので、縦 x 横 x 色(RGB) の三次元データのようにして考えることができます。

スポンサーリンク

ビットマップデータ

上の図のように画素がそのまま並んで画像を形成しているデータをビットマップデータやラスターデータと呼びます。特に Windows を利用している方からするとビットマップデータと言うと、.bmp のデータを思い浮かべるかもしれませんが、.bmp は正確には「Windows ビットマップ」と言うデータ形式で、ここで言うビットマップデータとはちょっと違うものなので注意してください。

逆にビットマップデータでない画像形式とはどのようなものがあるでしょうか?有名なのが JPEG や TIFF などですね。これらは画像のファイルサイズを小さくするためにデータが符号化(エンコード)されており、上の図のように画素がそのまま並んだ状態ではありません

このような状態だとどのような画像であるかが人間には分からないため、画像を表示するプレビューソフトなどでは、JPEG や TIFF が入力されるとそのデータをデコードしてビットマップデータ形式に変換したものを画面に表示しているのです。

JPEGをビットマップデータに変換して表示する様子

画像処理プログラミングを行う時も同じで、JPEG などのエンコードされたデータだと、どう処理をすればどういう画像になるかが直感的に分からないためプログラミングが非常に難しいです。そのため一旦デコードしてビットマップデータに変換し、変換後のビットマップデータに対して画像処理を行う手順を踏んでプログラミングを行います。この先でも説明していますが、ビットマップデータであれば画素がメモリ空間上にそのまま並んでいるため非常に扱いやすいです。

このページではここから先は画像データを全てビットマップ形式のデータとして説明を行ないます。

画像データのメモリ配置

続いて画像データがどのようにメモリ上に配置されるかの一例を見てみましょう。C言語プログラムで下記の処理を実行すればメモリ上に M x N 画素分のメモリ領域が確保され、その領域の先頭アドレスを ptr ポインタが指すようになります。

ptr = (unsigned char*)malloc(sizeof(unsigned char) * M * N * 3);

M は横方向のピクセル数、N は縦方向のピクセル数でありこの2つを掛け合わせることで画素数分のサイズとなります。さらにその画素数に対して R と G と B の3つの色分の輝度を格納できるように3を掛けています。unsigned char のサイズは1バイトですので、M * N * 3 バイト分のメモリが確保されることになります。

この malloc を行った時のメモリ空間を図示すると下のようになります(実際には上記の malloc により確保されるのは一次元のデータになります。が、二次元の図でイメージした方がわかりやすいため、二次元のように縦横に並べて図を書いています)。

一つの箱のサイズは1バイトで、一つ一つの箱に輝度が格納されるイメージです。RGB の3個で一つの画素を表し、一つ目がRの輝度、二つ目がGの輝度、三つ目がBの輝度を表しています。

画像上の座標も考えると下図のような感じになります。横幅をM、高さをNとして考えています。

画素へのアクセス

サイズが M × N の画像において、(m, n)画素へのアクセスについて下の図で説明していきます。

各画素が3バイトなので、一つ右横の画素へアクセスする場合にはポインタのアドレスを3バイト分プラスしたアドレスにアクセスします。m 画素分右横へアクセスするためには3の m 倍分ずらせば良いので 3 × m バイトプラスすることになります。

一つ下の画像へのアクセスについては少し難しくなりますが、図を見れば理解しやすいと思います。メモリ配置は2次元で書くとわかりやすいので2次元のように書いていますが、実際は1次元です。つまり下の図のメモリ空間の右端は左端の1つ下のマスに繋がっているのです。なので、1つ下の画素にアクセスしようと思うと、下の図のように横方向に1周回った位置にある画素にアクセスすることになります。

画像の幅が M で一つの画素が3バイトなので、一つ下の画像へは 3 × M バイト分プラスすれば一つ下の画素へアクセスできます。n画素分下にずらすことを考えると、3 x M バイトの n 倍分ずらせば良いので 3 × M × n バイト分プラスすることになります

したがって、(m, n)画素には下記のアドレスによってアクセスすることが可能です。

画像の先頭アドレス +(3 × m)+(3 × M × n)

スポンサーリンク

画素値取得

さらに、各画素は R と G と B の輝度値(それぞれ1バイト分)を持っているため3バイトの情報となっており、画素のアドレスの最初の1バイトには R の輝度値が、次の1バイトにはGの輝度値が、最後の1バイトには B の輝度値が格納されています。

したがって(m, n)画素のR・G・Bの輝度値はそれぞれ下記のアドレスに格納されており、ここを参照することで画素値を取得することが可能です。

R:画像の先頭アドレス +(3 × m)+(3 × M × n)

G:画像の先頭アドレス +(3 × m)+(3 × M × n)+ 1

B:画像の先頭アドレス +(3 × m)+(3 × M × n)+ 2

実際に画素値を取得するプログラムは下のページで紹介していますので是非参考にしてください。

C言語での画像の画素値取得

モノクロ・アルファチャンネル

ここまで画素は RGB の3つの情報から構成されることを前提に話してきましたが、実は画像の持つ情報は3つとは限りません。

例えばモノクロ(グレースケール)の画像だと画素は1つの情報から構成されますし、アルファチャンネルを持つ画像であれば4つの情報(R・G・B・α)から構成されます。例えばアルファチャンネル付きの画像であれば、メモリ空間上には下のように展開されます。

アルファチャンネルの解説やアルファチャンネルをを扱ったプログラムは下のページで紹介していますので興味があれば読んでみてください。

C言語でアルファチャンネル付きPNGを画像処理

まとめ

このページでは画像データの構造や画素・ビットマップデータについて解説しました。特に画像処理を行う場合は、メモリ上にどのように各画素のデータが存在するかをイメージできることが重要です。この辺りは実際に画像処理プログラミングを行なって失敗を重ねていくうちに身につくものですので、ガンガン画像処理プログラミングに挑戦してみてください!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です