画像の合成の手順(プログラミング)

背景の上にキャラクター(背景のオレンジを透過)を合成

ペイント関係のソフトウェアであれば、今のご時世、簡単にできるかもしれない「画像の合成」。

PNG形式ファイルの透過設定を使えば、プログラミングでも関数やライブラリは用意されている。

しかし、BMP形式のファイルを扱う場合や、プログラミングの中で加工されたビットマップ画像となると、やはり合成はすぐにはできない。
透過部分を処理した画像を自分で用意する手間もあるし、決められた画像しか扱えない。
それでは汎用性に欠ける。

ということで、画像の合成方法を手順として書き記してメモが気にしておく。

C++で話を進めていくと、BitBlt()関数を使いこなしていかなければならない。

BOOL BitBlt(
  HDC hdcDest,  // handle to destination device context
  int nXDest,  // x-coordinate of destination rectangle's upper-left
  int nYDest,  // y-coordinate of destination rectangle's upper-left
  int nWidth,  // width of destination rectangle
  int nHeight,  // height of destination rectangle
  HDC hdcSrc,  // handle to source device context
  int nXSrc,  // x-coordinate of source rectangle's upper-left
  int nYSrc,  // y-coordinate of source rectangle's upper-left
  DWORD dwRop  // raster operation code
);

特に最後の dwRop をきちんと使っていかなければならない。

手順としては

(1)キャラクターのマスク画像(白黒)を作成
(2)中間画像(P):キャラクター画像+反転マスク画像
(3)背景画像の上にマスク画像を上書き(AND結合)
(4)背景画像の上に中間画像(P)を上書き(OR結合)

という流れ。

(1)キャラクターのマスク画像(白黒)を作成

まずは、キャラクター画像の透過部分を、自分で決めて塗り潰しておく。ここでは、オレンジ色。
(1)に関しては、ペイント関係のソフトウェアで自作してもいいし、プログラミングで自作してもいい。

マスク画像は、
 黒 = イメージ部分
 白 = 透過部分

として作成する。

右の図では、キャラクター部分を黒にする。

プログラミングだと、for() 文で全てのピクセルを調べて、オレンジ色だったら白にする、みたいな単純なコードでもいい。

(2)中間画像(P):キャラクター画像+反転マスク画像

マスク画像は大切なので、残しておく。
新しいビットマップを作成して、マスク画像を白黒反転させてコピー転送する。

(1)のマスク画像
→(白黒反転)
反転マスク画像(W)

BitBlt()関数の最後の引数  dwRop  =  NOTSRCCOPY
(反転した転送元のビットマップと転送先ビットマップにコピーします)

この指定方法で、一発変換で完成。
反転マスク画像を(W)とする。

次に、反転マスク画像(W)の上にキャラクターを上書きする。
ただし、AND結合。

BitBlt()関数の最後の引数  dwRop  =  SRCAND
(転送元のビットマップと転送先ビットマップのピクセルを論理 AND 演算子で結合します)

AND結合 →
(SRCAND指定)
中間画像(P)

ビット演算で 0x0000 & 0x**** 何をAND結合しても 0x0000 になる。背景を黒にするのは、この原理。
同様に、白の場合、0xffff & 0x**** = 0x**** になる。

中間画像(P)完成。  

(3)背景画像の上にマスク画像を上書き(AND結合)

AND結合 →
(SRCAND指定)

背景画像の上に、マスク画像(最初に作成した画像)を単純にAND結合で上書きする。
dwRop  =  SRCAND

(4)背景画像の上に中間画像(P)を上書き(OR結合)

OR結合 →
(SRCPAINT指定)

最後に、手順(2)(3)の画像を重ね合わせる。
ただし、今度は、OR結合。

BitBlt()関数の最後の引数  dwRop  =  SRCPAINT
(転送元のビットマップと転送先ビットマップのピクセルを論理 OR 演算子で結合します)

ビット演算で 0x0000 | 0x**** = 0x**** になる。黒の部分は、相手側の画像になる。

以上、(1)~(4)で合成は完成する。