LoginSignup
1
0

float32のrgbaデータをuint8に変換する

Last updated at Posted at 2024-03-02

前提

ZED SDK で点群(PointCloud) データを取得する。
そのときに、XYZRGBAのデータを取得することができる。

xyz_rgba はnumpy のdtype=np.float32 のデータ形式になる。

xyz_rgba = point_cloud.get_data()

xyz_rgba[:, :, 3] は(r, g, b, a) の各uint8 をfloat32のデータ形式として解釈した値が格納されている。

こまったこと

  • float32のデータ形式 から(r, g, b, a) の各uint8 に変換する方法の記載がなかった。

IEEE 754 での単精度浮動小数点数の形式: binary32

Screenshot from 2024-03-02 09-58-15.png
wikiからのスクリーンショット

解決手法:

numpy.frombuffer() を使う

import numpy as np

colorarray = np.random.randint(0, 255, (12), dtype=np.uint8)
byte_data = colorarray.tobytes()
retrieved_color_array = np.frombuffer(byte_data, dtype=np.uint8)

# 変換・逆変換後の値が一致することを確認
assert np.array_equal(retrieved_color_array, colorarray)

print(f"{colorarray=}")
print(f"{byte_data=}")
print(f"{retrieved_color_array=}")

# float32にとして解釈
float32_array = np.frombuffer(byte_data, dtype=np.float32)
print(f"{float32_array=}")

# float32の配列を再度バイト列に変換
byte_data2 = float32_array.tobytes()
# そのバイト列をuint8で再解釈
retrieved_color_array2 = np.frombuffer(byte_data2, dtype=np.uint8)
print(f"{retrieved_color_array2=}")
# 元のuint8と一致することの確認
assert np.array_equal(retrieved_color_array2, colorarray)


実行結果

colorarray=array([ 83,  15, 209, 142,  29, 242,  41, 229,  34, 209, 185, 172],
      dtype=uint8)
byte_data=b'S\x0f\xd1\x8e\x1d\xf2)\xe5"\xd1\xb9\xac'
retrieved_color_array=array([ 83,  15, 209, 142,  29, 242,  41, 229,  34, 209, 185, 172],
      dtype=uint8)
float32_array=array([-5.1537235e-30, -5.0159134e+22, -5.2812347e-12], dtype=float32)
retrieved_color_array2=array([ 83,  15, 209, 142,  29, 242,  41, 229,  34, 209, 185, 172],
      dtype=uint8)

追記:成功しなかった方法

  • 以下の関数を利用してfloat32をTuple[int, int, int, int] に変換しようとする試み。
  • 失敗した理由:
    − pythonの言語仕様自体には(つまりnumpyなしでは)、float32という型は存在しない。
  • numpy配列の一部を単独のスカラー値として扱った時点で、float32からfloat64に暗黙の変換がされる。
  • そのため、struct.pack('f', float_value)をした時点で、packされる値は、元のfloat32とは違ってしまっている。
  • 結論: numpyを使いましょう。
# 成功しなかった方法
def float32_to_bytes(float_value: float) -> bytes:
    bytes_data = struct.pack('f', float_value)  # 'f'はfloat32を表すフォーマットです
    return bytes_data


def fourbytes2arraychar(fourbytes: bytes) -> Tuple[int, int, int, int]:
    int32_val = int.from_bytes(fourbytes, byteorder="little")
    return (int32_val & MASK0,
            (int32_val & MASK1) >> 8,
            (int32_val & MASK2) >> 16,
            (int32_val & MASK3) >> 24)
1
0
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
1
0