はじめに
processingで画像処理をしていると、時々、RGB各8bitでは足りなくなる時があります。byteでなくてintで計算したいとか、floatで計算したいとか。フォーマットとしては、exrとかhdrがありますが、簡単に使い始められそうなライブラリがなく、二の足を踏んでしまいます。
そういうわけで、とりあえず、自分で読み書きできれば、十分という場合に、サンプルを書いたメモです。
概要
戦略としては、createImage( ,ARGB)でImage作って、その中に、色情報に見せかけた、float情報を書き込んでpngとして保存。loadImageでpngを読み込んで、色情報からfloat値を読み込むという手順。
ここで、colorとintは同じであリ、floatを含めて全て32bit変数であることを前提に書く。
32bit変数である、intとfloatを中身のbit情報を変えずに、見かけ状の型だけ変えたい。c言語だとポインタ使って楽勝だが、javaだとそうはいかず。
javaで動いているprocessingには、便利な命令があって、floatToIntBits/intBitsToFloatの二つを使えば、簡単に実装できました。
環境
processing 3.5.4
プログラムの概要
①noise命令で適当なfloat配列を生成
②グレースケール画像として表示確認
③PImageを作り、float配列をint配列と見なして、1ピクセルずつ書き込み、pngとして保存。
④そのpngをloadImageして、ピクセル値を読み込み、floatに変換して、間違いがないかチェック
備考
64bitのデータを扱いたいときは、doubleToLongBits/longBitsToDouble命令がある。しかし、1ピクセルに64bitは入らないので、32bitずつ書き込む工夫が必要である。
実行結果
実行すると、下記noise画像が表示されるが、保存したい元データはfloat配列であり、0~1の小数である。255倍して表示しただけ。
この、float値をint値(color値)と解釈して保存した画像が下記。ぐちゃぐちゃだが、なんとなく面影が残っている。
float配列の最初が0.6852823で、読み書き結果が同じだから大丈夫でしょう。
コード
size(256, 256);
float[][] f;
f = new float[256][256];
//generate random float array
noiseSeed(0);
for (int y=0; y<256; y++) {
for (int x=0; x<256; x++) {
f[x][y] = noise(x*0.01, y*0.01);
}
}
println(f[0][0]);
//display x255
for (int y=0; y<256; y++) {
for (int x=0; x<256; x++) {
stroke(f[x][y]*255);
point(x, y);
}
}
//save as png
PImage img = createImage(256, 256, ARGB);
img.loadPixels();
for (int y=0; y<256; y++) {
for (int x=0; x<256; x++) {
int i = Float.floatToIntBits(f[x][y]);
img.pixels[x+y*256] = i;
}
}
img.updatePixels();
img.save("float.png");
//load check
PImage img2 = loadImage("float.png");
img2.loadPixels();
color c = img2.pixels[0];
float f2 = Float.intBitsToFloat(c);
println(f2);