前提
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
解決手法:
numpy.frombuffer() を使う
.py
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)
実行結果
.py
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を使いましょう。
.py
# 成功しなかった方法
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)