2017年2月17日金曜日

割合レベル補正フィルタ(ToneRateMapFilter)

 今回はPhotoshopにおけるレベル補正に似た効果をもたらすフィルタを作成します。レベル補正とはコントラスト制御の一手法であり、ヒストグラムを見ながら画像全体の色調やカラーバランスおよび、シャドウ・ハイライトなどの調整を行えます。例えば、下の二つの図のうち上の図のような画像があるとします。この画像はヒストグラムが一つの山でできており、かつ中央付近にかたまっています。これを下の図の右のレベル補正図のように補正することで、メリハリのついた画像に変換することができます。
今回は、このような変換を自動で行うプログラムを作成します。考え方としては、第一に上限割合と下限割合のパラメータを設定し、ヒストグラムの中で左から下限割合までを黒にマッピングし、右から上限割合までを白にマッピングします。これにより、割合に応じて自動的にレベル補正が行われます。
 Tutorial1Activityクラスと同じ場所にToneRateMapFilterクラスを作成します。その後、filterメソッドに以下のコードを入力します。
public int[] filter(int[] imageArray, int width, int height,int max,int  min) {
  int tone[][]=ToneCalculator(imageArray);//①
  int length = width*height;
  int min_rate=(length*min)/100;//②
  int max_rate=(length*max)/100;
  int tonemap[][]=new int[3][256];
  tonemap[0]=tonemapping(tone[0],max_rate,min_rate);//③
  tonemap[1]=tonemapping(tone[1],max_rate,min_rate);
  tonemap[2]=tonemapping(tone[2],max_rate,min_rate);
  int[] oimgArray = new int[imageArray.length];
  int rgb;
  int red,green,blue;
  for(int i =0;i < length;i++){
   rgb = imageArray[i];
   red = (rgb >> 16) & 0xff;
   green = (rgb >> 8) & 0xff;
   blue = (rgb) & 0xff;
   oimgArray[i]=255*16777216+
     tonemap[0][red]*65536+tonemap[1][green]*256+tonemap[2][blue];
  }
  return oimgArray;
 }

 ①では、赤緑青それぞれの色についてヒストグラムを計算します。以下にToneCalculatorメソッドを記載します。
 public int[][] ToneCalculator(int[] imageArray){
  int tone[][]=new int[3][256];
  int length = imageArray.length;
  int rgb;
  int red,green,blue;
  for(int i =0;i < length;i++){
   rgb = imageArray[i];
   red = (rgb >> 16) & 0xff;
   green = (rgb >> 8) & 0xff;
   blue = (rgb) & 0xff;
   tone[0][red]+=1;
   tone[1][green]+=1;
   tone[2][blue]+=1;
  }
  return tone;
 }

 ②は引数で与えられた上限と下限について、全画素数に対する上限割合および下限割合を計算しています。例えば、画像サイズが約200万画素(フルHD)で、下限が5%ならば、ヒストグラムにおいて左から10万が下限割合になります。
 ③はルックアップテーブルの作成を行います。以下に必要なメソッドを記載します。
        public int[] tonemapping(int tone[], int max_rate,int min_rate){
  double min=(double)getmin(tone,min_rate);//④
  double max=(double)getmax(tone,max_rate);//⑤
  double distance=max-min;//⑥
  double rate=255/distance;
  int tonemap[]=new int[256];
  for(int i =0;i < 256;i++){
   if(i <= min){
    tonemap[i]=0;
   }else if(i >= max){
    tonemap[i]=255;
   }else{
    tonemap[i]=(int)((i-min)*rate);
   }
  }
  return tonemap;
 }
 public int getmin(int tone[] , int min_rate){
  int min=0;
  int count=0;
  for(int i =0;i < 256;i++){
   count+=tone[i];
   if(count > min_rate){
    min=i;
    break;
   }
  }
  return min;
 }
 public int getmax(int tone[] , int max_rate){
  int max=255;
  int count=0;
  for(int i =0;i < 256;i++){
   count+=tone[i];
   if(count >= max_rate){
    max=i;
    break;
   }
  }
  return max;
 }

 ④では、③で得られた下限割合をもちいて、ヒストグラムの0~255の中で下限割合を満たすような値を求めます。⑤では上限割合を満たす値を求めます。
 ⑥以降は④⑤で得られた上限および下限をもちいて、上下限マッピングフィルタと同様にルックアップテーブルの作成を行います。ただし、上下限マッピングフィルタと異なり、赤緑青それぞれで異なる上限下限の値を用います。
 最後に、 Tutorial1Activityクラスのint imageArray[]=ba2ia(ba);の下に以下の文を記入します。
imageArray=new ToneRateMapFilter().filter(imageArray, imagewidth, imageheight, 95,5);
第四引数が上限パラメータを、第五引数が下限パラメータを示します。それぞれの単位はパーセントです。

 以下に実機での実行結果を示します。今回は分布変化がわかりやすいようにサイの画像を用いています。ヒストグラムからわかるように、中央に山のあるヒストグラムから左右に引き伸ばした山が得られています。このように、上限と下限を設定することで、それに対応したルックアップテーブルを自動で作成することができます。





0 件のコメント:

コメントを投稿