2017年2月9日木曜日

ヒートマップフィルタ(HeatMapFilter)

 今回は疑似カラーマッピング技術であるヒートマップ風のフィルタを作成します。今回は作成に当たってHSV変換を行います。HSVとは色相(Hue)、彩度(Saturation・Chroma)、明度(Value・Lightness・Brightness)の三つの成分からなる色空間です。色相は色の種類を示し、0~360で表されます。彩度は色の鮮やかさを示し、0~100%で表されます。明度は色の明るさを示し、0~100%で表されます。これはRGB色空間の非線形変換であり、色の変換に用いられることもあります。
https://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93
RGBとHSVの相互変換のプログラム作成については次のサイトが参考になります。
http://hooktail.org/computer/index.php?RGB%A4%AB%A4%E9HSV%A4%D8%A4%CE%CA%D1%B4%B9%A4%C8%C9%FC%B8%B5
上記サイトでは彩度と明度が0~255で表されています。こちらもint型を用いるためにそのようにしたいと思います。(一部doubleキャストしていますが)
 ヒートマップフィルターにおいては、HSVのなかでHのみを変化させます。これにより色相の変化した画像となります。ただし、0から360まで変化させてしまうと色がほとんど元に戻ってしまうため、色相は0から240まで変化させます。

 まず、HSVとRGBの相互変換プログラムを作成します。Tutorial1Activityクラスと同じ場所にHSVTransクラスを作成します。その後、以下のコードを入力します。
    public int[] RGBtoHSV(int rgb){
        double red = (rgb >> 16) & 0xff;
        double green = (rgb >> 8) & 0xff;
        double blue = (rgb) & 0xff;
        red=red/255;
        green=green/255;
        blue=blue/255;
        double max;
        double min;
        int H;
        int S;
        int V;
        int result[]=new int[3];
        if(red > green){
            if(red > blue){
                max=red;
                if(green < blue){
                    min=green;
                }else{
                    min=blue;
                }
                H=(int) (60*(green-blue)/(max-min));
            }else{
                max=blue;
                min=green;
                H=(int) (60*(red-green)/(max-min)) +240 ;
            }
        }else{
            if(green > blue){
                max=green;
                if(red < blue){
                    min=red;
                }else{
                    min=blue;
                }
                H=(int) (60*(blue-red)/(max-min)) +120 ;
            }else{
                max=blue;
                min=red;
                H=(int) (60*(red-green)/(max-min)) +240 ;
            }
        }
        if(H < 0){
            H+=360;
        }
        H=H%360;
        S=(int)(((max-min)/max)*255);
        if(S > 255){
            S=255;
        }else if(S < 0){
            S=0;
        }
        V=(int)((max)*255);
        if(V > 255){
            V=255;
        }else if(V < 0){
            V=0;
        }
        result[0]=H;
        result[1]=S;
        result[2]=V;
        return result;
    }
    public int  HSVtoRGB(int hsv[]){
        //hsv H:0~360, S:0~255, V:0~255;
        int H=hsv[0];
        int S=hsv[1];
        int V=hsv[2];
        int red=0;
        int green=0;
        int blue=0;
        if(S==0){
            red=V;
            green=V;
            blue=V;
        }else{
            int I=(int)(H/60);
            double F=((double)H)/60 -I;
            int p=V*(255-S) / 255;
            int q=(int) (V*(255 - F*((double) S))/255);
            int t=(int) (V*(255-1*(1-F)*((double) S))/255);
            if(I==0){
                red=V;
                green=t;
                blue=p;
            }else
            if(I==1){
                red=q;
                green=V;
                blue=p;
            }else
            if(I==2){
                red=p;
                green=V;
                blue=t;
            }else
            if(I==3){
                red=p;
                green=q;
                blue=V;
            }else
            if(I==4){
                red=t;
                green=p;
                blue=V;
            }else
            if(I==5){
                red=V;
                green=p;
                blue=q;
            }
        }
        int result=255*16777216+red*65536+green*256+blue;
        return result;
    }

次にHeatMapFilterクラスを作成し、filterメソッドに以下のコードを入力します。
    public int[] filter(int[] imageArray, int width, int height) {
        int length = width*height;
        int[] oimgArray = new int[imageArray.length];
        int rgb;
        int red,green,blue;
        int y_val;
        int h;
        for(int i =0;i < length;i++){
            rgb = imageArray[i];
            red = (rgb >> 16) & 0xff;
            green = (rgb >> 8) & 0xff;
            blue = (rgb) & 0xff;
            y_val = ( 2 * red + 4 * green + blue ) / 7;//①
            h = 240- y_val*240/255;//②
            int hsv[]=new int[]{h,255,255};//③
            oimgArray[i]=new HSVTrans().HSVtoRGB(hsv);//④
        }
        return oimgArray;
    }

 ①では輝度グレイスケールに変換しています。そして、②ではその値をまず0~240の範囲に変換してから、240から引くことによって逆転させています。これは、元画像での白色が赤色に対応するようにするためです。
 ③ではHSVからRGBに変換するための配列を用意します。HSVの順番ですが、SとVは最大値の255に設定します。
 ④ではHSVの値をRGB値に変換します。

 最後に、 Tutorial1Activityクラスのint imageArray[]=ba2ia(ba);の下に以下の文を記入します。
imageArray=new HeatMapFilter().filter(imageArray, imagewidth, imageheight);

以下に実機での実行結果を示します。

0 件のコメント:

コメントを投稿