画像 - Hirotake Itoh's memo by PukiWiki

とにかく奥が深い。何かやろうとするたびに、膨大なbackgroundに押し潰されそうになる。

## EXIF *

デジカメなんかがjpegに各種情報を埋め込むための仕様なのだそうだ。どの受光素子が「画像の左上」か、なんて(カメラを縦向きで撮ったかどうか)なんかも記録してくれるので便利。でもどうやらメーカーごとに「方言」があるみたいなのが困る。

Exif形式の画像ファイル解説

## jpeg *

風景、人物写真などに適したフォーマットで、非常に広く普及している。

### IJG *

IJGという所が総本山っぽい雰囲気である。スタンダードっぽいライブラリを提供しておった。関連webページは以下。

Independent JPEG Group's JPEG software release 6b with x86 SIMD extension for IJG JPEG library version 1.02
オープンソースを使った JPEG 操作
Windows Programming Tips

## フォーマット *

画像の持つ情報量は多いので、ファイルの形式としては何らかの圧縮を施すのが通例であり、その方法の違いなどにより様々なファイル形式が存在する。一般に、写真画像ならjpegが適し、白の背景に黒の三角形を描きました、みたいなエッジのきいた人工的な図形ならPNGの方が適する場合が多い。

ウェブで用いられる画像形式について。
画像圧縮アルゴリズム (5) LZ法
離散コサイン変換

## 色とデータ量 *

一般的なPC上で、色は赤・緑・青(RGB)の各々の強度(加色混合)で表現される。各色の強度をどれだけ細かく制御するかで、表現できる色の数が決まる。

最近のPC上では約1677万色を区別して発色することが容易に可能で、これは大体人間の識別できる色数の限界といわれているらしい。この意味において、発色「数」に関してはPCまわりの技術は充分な水準に達しているといえる(無論、色空間の変換やらモニタの較正やら、他に考慮すべき事項もまだ沢山あるが、とりあえず「数」だけは充分)。

1677万とは 256*256*256=(2^8)^3 である。RGBに各々256種類(8bit)の情報を割り振ることによって実現される。つまり、ひとつの点の色を表現するのに 8bit + 8bit + 8bit = 24bit のデータ量が必要なわけである。このことから「1677万色の発色 」を24bitカラーと称することもある。True Colorと呼ばれているものも同様の意味を持つ。32bit PC上のデータ処理の観点からは、嘘データを8bitつめこんで、32bit/点 として扱う方が効率がよいらしい(アライメントの事情だかなんだか。よくわからん)。故に、32bitカラーと呼ばれているものも、色の数としては24bitカラーと変わらない。

これに対し、6万5千色を扱うHigh Colorあるいは16bitカラー(2^16=65536)と呼ばれるものもある。これはRとBを5bit、Gを6bitで表現している。業務用機器では、RGB各々10bitで表現している(2^(10+10+10)=1073741824 種類の発色ができる)ものもあるらしい。

以下参考文献。

PC ViewよりRGB
色色雑学 すごい！

### グレースケール *

モノクロ画像だと色の情報は失われるが、データ量も小さいため、RGBをモノクロに変換したいこともままある。しかしこの変換も一筋縄ではいかず、色々と方式があって混乱したが、幾つかのすばらしい解説のおかげで理解がちょっぴり深まった。

osakana.factory - グレースケールのひみつ
ISP imaging-developers - 色変換式集
YUVフォーマット及び YUV<->RGB変換

## BMP *

ビットマップ。文字通り、座標の各点(ビット)の色をSerialに記録(マップ)したもので、概念はとてもわかりやすい一方でデータ量はかなり多くなってしまう。

単純であるがため、歴史のある形式である。その結果、細かく仕様の異なるものが混在しているようで、全貌の把握にはなかなか骨が折れる。

WisdomSoftの標準 Windows APIよりDIB ファイルヘッダなどなど
ビットマップファイルの構造
BMPファイルを32ビットDIBとして読み込む
第３回　BitmapをVC++で扱うヒント

### 幅とデータ量の検証 *

#### preface *

ビットマップを(数学でいうところの)行列として捉える。このとき行数は画像の高さ、列数は画像の幅を表す(単位はpixel)。上下の区別をとりあえず無視すると、ビットマップの画像データの並び方は次のように表現できる。

(第1行のデータ)(第2行のデータ)(第3行のデータ)...

つまり、横方向の1ラインをまずはドドっと格納し、そして次のラインをドドっと・・・という具合である。この時、ビットマップ形式のシキタリでは、1行(1ライン)あたりのbyte数は4の倍数でなくてはならないそうだ。画像の幅なんてのは千差万別なので、不幸にして生データ(pixel数ではない)が4の倍数にならないなんてことはザラにあるわけだが、その時は行の末尾に嘘データ(ゼロ)を詰めて無理矢理に一番近い4の倍数にしてしまうらしい。実感を得るために検証してみた。(ただの自己満足です)

#### 準備と予想 *

最も使用頻度の大きいであろう24bitカラーのビットマップを、幅を1pixelずつ変えて保存し、各々のファイルサイズを比較するという作戦である。

素材としてC:\WINNT(windows2000)にある「フィッシング.bmp」を使う。Photoshopでサイズを128pixel(横) x 64pixel(縦)にし、さらに24bitカラーとした。

この時1行あたりのデータ量は、1pixelあたり3byte(24bit)であるから

128 x 3byte = 384byte

であり、4で割切れる(ので嘘データ不要)。この時のファイルサイズを起点とする。さて幅を1pixel増やすと1行あたり

129 x 3byte = 387byte

であって4で割切れない。割切れるように嘘データを詰めて1行あたり388byteとなるならば、全体として

(388 - 384)byte x 64 = 256byte

のファイルサイズの増加となるはずである。同様にして、

130 x 3byte = 390byte ==> (392 - 384)byte x 64 = 512byte ==> 512byteの増加
131 x 3byte = 393byte ==> (396 - 384)byte x 64 = 768byte ==> 768byteの増加
132 x 3byte = 396byte ==> (396 - 384)byte x 64 = 768byte ==> 768byteの増加
127 x 3byte = 381byte ==> (384 - 384)byte x 64 = 0byte ==> 0byteの増加

となるはずである。127と128、131と132のファイルサイズが変わらないあたりで4の倍数の実感が沸くはずである。

#### 結果 *

予想通りとなった。知ってる人からするとバカらしい検証だろうが、うまくいったので満足。

## PNG *

Portable Network Graphics のことで、GIFの後継として開発されたそうだ。

### ライブラリ *

プログラムからPNGを扱うためにはzlibとlibpngが必要となる。ソースもバイナリも手に入るが、ソースを持ってきてもVisual Studio用のプロジェクトが付属するのでビルドは楽である。プロジェクトを開いて ビルド => アクティブな構成の設定 から好きなものを選ぶだけでよい。

bmp2png & png2bmp
PNG利用術
PNGを読み込む（VC++でlibpngを使用する）
libpngについて
MNG/PNGを使ってみる

### PNGファイルフォーマット *

倉庫という名の作品展
Portable Network Graphics (PNG) Specification (Second Edition)

## GDI+ *

Windowsにおいて、標準の画像フォーマットは所謂「ビットマップ」であるが、それ以外のjpegといったフォーマットの方が巷で専ら使用されている。GDI+は、そういった様々のフォーマットの画像(BMP, GIF, JPEG, PNG, TIFF, EMF)を扱うためのライブラリ。

GDI+に関するメモ
GDI+の導入
第３３５章 ＧＤＩ＋の基礎　その１(猫でもわかるプログラミングより)
第３３６章 ＧＤＩ＋の基礎　その２(猫でもわかるプログラミングより)
GDI+ Programming Note
GDI+ と VC++ と日本語

platformSDKが必要みたいだ。

Windows Server 2003 PSDK Full Download with Local Install(Windows 2000でもこちらから導入するらしい)
Visual C++ Toolkit ＋ Platform SDK のインストールとテスト

こんな感じのコードでjpegがピクチャコントロールに表示できた。初期化などはすでに終わっているものとする。

const HWND hWndPict = GetDlgItem(hWnd, IDC_PICT);
RECT Rect;
GetClientRect(hWndPict, &Rect);
const int width = Rect.right - Rect.left;
const int height = Rect.bottom - Rect.top;
setlocale(LC_ALL,"");
HDC hdc = GetDC(hWndPict);
Graphics MyGraphics(hdc);
Image myImage(filename); // WCHAR* filename
MyGraphics.DrawImage(&myImage, 0, 0, width, height);
ReleaseDC(hWndPict, hdc);

10c1

添付ファイル: 132dlg.png 2230件
[詳細]
131dlg.png 2272件
[詳細]
130dlg.png 2229件
[詳細]
129dlg.png 2216件
[詳細]
128dlg.png 2273件
[詳細]
127dlg.png 2227件
[詳細]
save_dialog.png 2334件
[詳細]

Last-modified: Sun, 30 Apr 2006 20:23:31 JST