0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

float配列をbyte[4]と見立ててpng保存する

Last updated at Posted at 2025-02-03

目的

32bit長のfloatの値を、8bit長に分割して、byte[4]として扱い、RGBAのPNGとして保存する手順です。

需要はあまりないと思いますが、自分の場合、こんな思考でした。
・HDRやEXRフォーマットは避けたい
・自分しか使わないので、解像度など決め打ち
・HeightMapで256階調では足りず、もっと細かくしたい
・表示がおかしくてもOSの標準機能で中身をみれたらなぁ
・float値のバイナリ書き出しだと、みれないしなぁ
・pngなら勝手に圧縮してくれる
・CTのようなボリュームデータも扱えそう。

float値のバイナリ書き出し

5年前、2021年3月30日の、自分の記事を見つけたので、(ショック!)参考にして、

コード「floatの精度を捨ててpngとして保存」

まず、ターゲットとするfloatのデータを決める。
32bitから8bitに丸め込まれるので、精度は落ちる。

PImage img;

float[][] f32 = new float[1024][1024];

size(1024, 1024);
noiseSeed(0);
img = createImage(1024, 1024, ARGB);
for (int y=0; y<1024; y++) {
  for (int x=0; x<1024; x++) {
    f32[x][y] = noise(x*0.02, y*0.02)*256;
    img.set(x, y, color(f32[x][y], 255));
  }
}
img.save("F.png");

image(img, 0, 0);

F.png

コード「floatをバイナリで保存して、読み込んで表示」

さっきのnoiseで生成したfloat配列をバイナリで保存し、
それをfloat配列に読み込み直して、imgに描画し、表示する。

ファイル容量は
1024102432/8 = 4,194,304 Byte

zip圧縮したら
3,686,253 Byte

89%に圧縮できた。

import java.io.*;

size(1024, 1024);
noiseSeed(0);

// Prep
float[][] f32 = new float[1024][1024];
for (int y=0; y<1024; y++) {
  for (int x=0; x<1024; x++) {
    f32[x][y] = noise(x*0.02, y*0.02)*256;
  }
}

// Write
try {
  OutputStream os = createOutput("F32_bin.dat");
  DataOutputStream dos = new DataOutputStream(os);
  for (int y=0; y<1024; y++) {
    for (int x=0; x<1024; x++) {
      dos.writeFloat(f32[x][y]);
    }
  }
  dos.flush();
  dos.close();
}
catch(IOException e) {
  e.printStackTrace();
}

// Load
float[][] tmp = new float[1024][1024];
try {
  InputStream is = createInput("F32_bin.dat");
  DataInputStream dis = new DataInputStream(is);
  for (int y=0; y<1024; y++) {
    for (int x=0; x<1024; x++) {
      tmp[x][y] = dis.readFloat();
    }
  }
  dis.close();
}
catch(IOException e) {
  e.printStackTrace();
}

// Display
PImage img = createImage(1024, 1024, ARGB);
for (int y=0; y<1024; y++) {
  for (int x=0; x<1024; x++) {
    img.set(x, y, color(tmp[x][y], 255));
  }
}
image(img, 0, 0);

コード「floatをintに変換してpng保存して、読み込んで表示」

color型がint型であることを利用し、かつ
Float.floatToIntBits
Float.intBitsToFloat
を駆使して、実装。
中間生成物であるpngファイルは、以下の様に見える。

ファイル容量は
3,688,761 Byte
zip圧縮とほぼ同等サイズになった。

import java.io.*;

size(1024, 1024);
noiseSeed(0);

// Prep
float[][] f32 = new float[1024][1024];
for (int y=0; y<1024; y++) {
  for (int x=0; x<1024; x++) {
    f32[x][y] = noise(x*0.02, y*0.02)*256;
  }
}

// Write
PImage img = createImage(1024, 1024, ARGB);
for (int y=0; y<1024; y++) {
  for (int x=0; x<1024; x++) {
    int i32 = Float.floatToIntBits(f32[x][y]);
    img.set(x, y, i32);
  }
}
img.save("F32.png");

// Load
float[][] tmp = new float[1024][1024];
PImage img2 = loadImage("F32.png");
for (int y=0; y<1024; y++) {
  for (int x=0; x<1024; x++) {
    int c = img2.get(x,y);
    tmp[x][y] = Float.intBitsToFloat(c);
  }
}

// Display
PImage img3 = createImage(1024, 1024, ARGB);
for (int y=0; y<1024; y++) {
  for (int x=0; x<1024; x++) {
    img3.set(x, y, color(tmp[x][y], 255));
  }
}
image(img3, 0, 0);

F32.png

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?