線形補間

今日はこのブログでは初になりますがソースコードを書いてみたいと思います。
ちょっと前置きを書きますが、そんなもの読みたくねぇよって方はいきなりソースコードに移ってください。

現在、大学院でディスプレイの研究をしています。
ディスプレイに表示されている色は数値で言うとデジタルで表され、多くのディスプレイは一色8bit(0〜255階調レベル)×3原色(赤、緑、青)の組合せで色を作っています。
最近では、一色10bit(0〜1023階調レベル)のものや原色数が3つより多い多原色ディスプレイなどもあって色の数は増えています。
この辺の話も大変面白いのでいつか取り上げたいと思いますが、今日は8bitで3原色のディスプレイを対象にしたいと思います。

ディスプレイの研究をしているということで、色を測定することが多くあります。
その中でもよくあるのがディスプレイの特性として0〜255階調の色を表示した時の各々の出力値の測定。
これは簡単に言ったら入出力特性とでもいうのでしょうかね。
真面目に256色を測定すればいい話なのですが、大変なので4階調ごと(0、4、8、…、255階調レベル)に測定したりします。
そして、そのあと測定していない階調(1、2、3、5、…、254階調レベル)を補間します。
補間の方法にはいろいろあって、一番簡単なのが線形補間です。
線形補間についてはwikipediaを見ていただいた方が分かりやすいと思うので、ここではソースだけを書きます。
ちなみに僕の場合、横軸が階調値、縦軸がXYZ三刺激値という出力値になるため9本のグラフになりますが、より一般化するためにソースコードでは1本のグラフでだけにします。


用意するデータ
出力値が一列に書かれたテキスト

8ステップ間隔の値を1ステップ間隔に線形補間する


import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.StringTokenizer;

public class SampleLinearInterpolate {

String inFile = "sampleTokusei.txt";//補間していない出力値が書かれたテキストの名前
double[] noInterpolated = new double[33];//テキストから読み取った値(補間前)

public static void main(String[] args) {
new SampleLinearInterpolate();
}
public SampleLinearInterpolate() {
read();//入力値をテキストから読み込みます
interpolate();//線形補間する
}

private void interpolate() {
int step = 8;//8階調ごとの出力値のデータを持っているため
double[] interpolated = new double[256];
System.out.println("X軸(階調レベル)"+"\t"+"Y軸(出力値)");
for(int i = 0; i < noInterpolated.length-2; i++){
double variation = (noInterpolated[i+1] - noInterpolated[i])/(double)step;//各区間ごとの変化量(傾き)
for(int j = 0; j < step; j++){
interpolated[i*step+j] = noInterpolated[i] + variation * (double)j;
System.out.println(i*step+j +"\t"+ interpolated[i*step+j]);
}
}
double variation = (noInterpolated[noInterpolated.length-1] - noInterpolated[noInterpolated.length-2]) / (step - 1);
for(int i = 0; i < step; i++){
interpolated[interpolated.length-step+i] = noInterpolated[noInterpolated.length-2] + variation * i;
}

for(int i = 0; i < interpolated.length; i++){
System.out.println(i +"\t"+ interpolated[i]);
}
}

private void read() {
try {
BufferedReader br = new BufferedReader(new FileReader(new File(inFile)));
int i = 0;
while(br.ready()){
StringTokenizer st = new StringTokenizer(br.readLine(), "\t\n,");
noInterpolated[i] = Double.parseDouble(st.nextToken());
i++;
}
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
}


実は今回は第三者(後輩)にノウハウを伝授する練習として一般化して書いてみました。
しかし、できるだけ本筋以外はシンプルに書きたいという願望もプログラミングスキルが足らないためか納得いくようには書けませんでした。
おそらく、デザインパターンを学ばれている中級以上の方々にとってはツッコミどころのたくさんあるソースだと思います。
ぜひぜひそういう点は突っ込んでいただきたいと思ってすのでよろしくお願いします。
個人的にもデザインパターンを体系的に学ぶ時期かなとは考えております。

そんな感じでソースを公開してみました。
ご自由にソースを利用していただいて構いませんが、利用したことによって生じた事故に責任はとれませんので自己責任でご利用ください。