C言語で画像をモノクロ・グレースケール化

画像をモノクロ・グレースケールに変換するための原理とC言語プログラムの実例の紹介を行います。

モノクロ・グレースケール化

こちらの記事で画素はRGBの3要素の輝度から成り立っていると説明しました。

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

RGB の輝度が全て同じ値の時、その画素はモノクロ(白、グレー or 黒)の色となります。モノクロ化・グレースケール化は、強制的に RGB の輝度値を全て同じ値にすることで実行することができます。

ただここで問題になるのが「何の値にするか」です。この値を求めるための変換式は実はかなり多くのものがあります。ここでは最も簡単な RGB の平均値を輝度値とする方法と、人間の視覚特性に基づいて変換する方法の2つを紹介します。

RGB の平均値を輝度値とする方法

これは非常に簡単で、RGB それぞれの輝度値を取得し、それぞれの和を3で割った値にすれば良いです。

(R + G + B) / 3

C言語プログラム例

#include "myJpeg.h"

int main(int argc, char *argv[]){

  BITMAPDATA_t bitmap;
  int m, n, c;
  int ave, sum;
  char outname[256];

  if(argc != 2){
    printf("ファイル名が指定されていません\n");
    return -1;
  }

  if(jpegFileReadDecode(&bitmap, argv[1]) == -1){
    printf("jpegFileReadDecode error\n");
    return -1;
  }

  /* ここから画像処理 */
  /* グレースケールに変換 */
  for(n = 0; n < bitmap.height; n++){
    for(m = 0; m < bitmap.width; m++){
      sum = 0;
      for(c = 0; c < bitmap.ch; c++){
        sum += bitmap.data[bitmap.ch * (m + n * bitmap.width) + c];
      }
      ave = sum / bitmap.ch;
      for(c = 0; c < bitmap.ch; c++){
        bitmap.data[bitmap.ch * (m + n * bitmap.width) + c] = ave;
      }
    }
  }
  /* ここまで画像処理 */

  sprintf(outname, "%s", "monochro.jpeg");

  if(jpegFileEncodeWrite(&bitmap, outname) == -1){
    printf("jpegFileEncodeWrite error\n");
    freeBitmapData(&bitmap);
    return -1;
  }

  freeBitmapData(&bitmap);

  return 0;
}

jpeg関連のファイルや関数については下記に記載していますのでこちらをご参照ください。

libJPEGのインストールとC言語での使用方法・使用例libJPEGのインストールとC言語での使用方法・使用例

プログラムの説明

下記の部分でRGBそれぞれの輝度の平均値を求めています。

      sum = 0;
      for(c = 0; c < bitmap.ch; c++){
        sum += bitmap.data[bitmap.ch * (m + c * bitmap.width) + c];
      }
      ave = sum / bitmap.ch;

そして、この平均値(ave)の値をRGBそれぞれの輝度値に上書きを行なっています。

      for(c = 0; c < bitmap.ch; c++){
        bitmap.data[bitmap.ch * (m + n * bitmap.width) + c] = ave;
      }

RGB全て同じ輝度になりますのでこの画素はモノクロの色になります。これを全画素に対して繰り返し実行することで画像全体がモノクロ化されます。

画像処理前後の画像

・画像処理前

・画像処理後

人間の視覚特性に基づいて変換する方法

人間の目は 赤、緑、青 それぞれが全て同じ明るさの度合いで見えているわけではなく、緑の方が明るく、青の方が暗く見えるそうです。ですので、この視覚特性を取り入れた方が、よりカラー時の画像に合ったモノクロ・グレースケール画像が作成できるというわけです。

つまり、緑である G を一番大きく輝度値に反映し、青である B を一番小さく輝度値に反映するために式に重み付けを行います。

0. 299 R + 0.587 G + 0.114 B

参考元:Wikipedia(YUV)

C言語プログラム例

#include "myJpeg.h"

int main(int argc, char *argv[]){

  BITMAPDATA_t bitmap;
  int m, n, c;
  int y;
  char outname[256];

  if(argc != 2){
    printf("ファイル名が指定されていません\n");
    return -1;
  }

  if(jpegFileReadDecode(&bitmap, argv[1]) == -1){
    printf("jpegFileReadDecode error\n");
    return -1;
  }

  /* ここから画像処理 */
  /* グレースケールに変換 */
  for(n = 0; n < bitmap.height; n++){
    for(m = 0; m < bitmap.width; m++){
      y = 0.299 * bitmap.data[bitmap.ch * (m + n * bitmap.width) + 0]
        + 0.587 * bitmap.data[bitmap.ch * (m + n * bitmap.width) + 1]
        + 0.114 * bitmap.data[bitmap.ch * (m + n * bitmap.width) + 2];
      for(c = 0; c < bitmap.ch; c++){
        bitmap.data[bitmap.ch * (m + n * bitmap.width) + c] = y;
      }
    }
  }
  /* ここまで画像処理 */

  sprintf(outname, "%s", "monochro.jpeg");

  if(jpegFileEncodeWrite(&bitmap, outname) == -1){
    printf("jpegFileEncodeWrite error\n");
    freeBitmapData(&bitmap);
    return -1;
  }

  freeBitmapData(&bitmap);

  return 0;
}

jpeg関連のファイルや関数については下記に記載していますのでこちらをご参照ください。

libJPEGのインストールとC言語での使用方法・使用例libJPEGのインストールとC言語での使用方法・使用例

プログラムの説明

下記の部分でRGBそれぞれの輝度値を用いてモノクロ化後の輝度値を求めています。

y = 0.299 * bitmap.data[bitmap.ch * (m + n * bitmap.width) + 0]
  + 0.587 * bitmap.data[bitmap.ch * (m + n * bitmap.width) + 1]
  + 0.114 * bitmap.data[bitmap.ch * (m + n * bitmap.width) + 2];

そして、この輝度値(y)をRGBそれぞれの輝度値に上書きを行なっています。

for(c = 0; c < bitmap.ch; c++){
  bitmap.data[bitmap.ch * (m + n * bitmap.width) + c] = y;
}

これを全画素に対して繰り返し実行することで画像全体がモノクロ化されます。

画像処理前後の画像

・画像処理前

・画像処理後

まとめ

このページでは画像のモノクロ化・グレースケール化の方法とC言語プログラムの例について解説しました。割と簡単な作りで画像の見た目をガラッと変えられるので画像処理初心者の方にもオススメの題材だと思います。ぜひ自分で作って画像処理プログラミングの楽しさを実感してみてください!

コメントを残す

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