モノクロ(単一色)階調表現への変換

 モノクロの絵や写真には独特の雰囲気があるので、特殊効果として良く使われますね。ゲームやマルチメディア作品でも回想シーンや叙情的イベントなどで使われ、効果的に使うと極めて印象深いシーンを作る事が出来るようです。
 今回は、普通のカラー映像からモノクロ映像を作ってみましょう。

色の表現方法と単色化

 24ビットDIBでは、色のRGB(赤・緑・青)成分をそれぞれ256(8ビット)段階で表現しています。この場合、RGBの各成分を同じ値にすると「鮮やかさ」が失われて灰色になるので、白黒に変換する時にはすべてのピクセルでRGBの値を同じにする事になるわけです。これは絵の「鮮やかさ」(各色の強さ)を無視して「明るさ」のみを表現する、という見方も出来るでしょう。逆に言えば、そのピクセルの明るさから見てRGBの各成分がどれだけばらついているかを調べれば、ピクセルの「鮮やかさ」が求められるという事にもなりそうです。さらに、RGBすべてを同じ値にするのではなくBだけを指定すれば「青黒」、Rだけなら「赤黒」になります。
 では、各ピクセルの「明るさ」はどうやって求めるのでしょうか?一番単純に考えればRGBの平均をとる、という事になるでしょう。でも考えてみれば、平均としては同じでもRGBが(0,255,0)の時より(0,0,255)の時の方が暗いですよね?これは、緑と青では色自体が明るさに与える影響が違うからです。そこで、実際にRGBの成分から明るさを求めるには、以下のような式を使う事が多いようです。

明るさ=R×0.30+G×0.59+B×0.11

 後は、この明るさの値をRGBすべてに指定すれば「白黒」、Rのみに指定してGBを0にすれば「青黒」になりますね。また、RGに明るさを指定してBを255にすると「白青」にもなるので試してみましょう。

・プログラム

 今回は、DIBの読み込みプログラムを基に読み込んだDIBを白黒・白青に変換する処理を加えてみます。24ビットDIBでは、ビットマップバッファの先頭lpBMPから1ピクセル3バイトでRGB各成分が記録されているので、単色に変換する部分は、以下のような感じになるでしょう。

  void grayScale(int mode) { // 単色スケールに変換

      int i;
      BYTE r,g,b,c;

      for (i=0;i<xSize*ySize;i++) { // 各ピクセルを単色化

          b=lpBMP[i*3]; // ピクセルのRGB成分を取得
          g=lpBMP[i*3+1];
          r=lpBMP[i*3+2];

          c=(BYTE)(r*0.3+g*0.59+b*0.11); // 明るさを計算

          if (mode==1) { // 白黒

              lpBMP[i*3]=c;
              lpBMP[i*3+1]=c;
              lpBMP[i*3+2]=c;

           } else if(mode==2) { // 白青

              lpBMP[i*3]=255;
              lpBMP[i*3+1]=c;
              lpBMP[i*3+2]=c;

           }

      }

      InvalidateRgn(hwnd,NULL,FALSE);
      UpdateWindow (hwnd);             // 再描画

  }

プログラムソース表示

 プログラムを起動したら、フルカラーのビットマップファイルをドラッグ&ドロップするか、読み込みボタンで選択して読み込んでください。その後、白黒・白青ボタンで単色スケール化できます。ただし、このプログラムで単色化できるのは、24ビットかつ横方向が4ピクセル単位のDIBのみです。


戻る