Skip to content
Snippets Groups Projects
Commit 34189c59 authored by Sebastian Hahta's avatar Sebastian Hahta
Browse files

Merge branch 'feature/python-ftlf' into 'master'

python ftl-file v3

See merge request nicolas.pope/ftl!200
parents c639ced2 9c5e9900
No related branches found
No related tags found
1 merge request!200python ftl-file v3
Pipeline #17353 passed
...@@ -12,8 +12,6 @@ from . misc import is_iframe ...@@ -12,8 +12,6 @@ from . misc import is_iframe
from . import ftltypes as ftl from . import ftltypes as ftl
from . import libde265 from . import libde265
_calib_fmt = "@ddddIIdddd"
try: try:
import cv2 as cv import cv2 as cv
...@@ -27,7 +25,7 @@ except ImportError: ...@@ -27,7 +25,7 @@ except ImportError:
''' YCrCb to RGB, based on OpenCV documentation definition. ''' YCrCb to RGB, based on OpenCV documentation definition.
Note: It seems this implementation is not perfectly equivalent to Note: It seems this implementation is not perfectly equivalent to
OpenCV's OpenCV's (results not exactly same, why?)
''' '''
rgb = np.zeros(img.shape, np.float) rgb = np.zeros(img.shape, np.float)
...@@ -43,11 +41,25 @@ except ImportError: ...@@ -43,11 +41,25 @@ except ImportError:
return rgb.round().astype(np.uint8) return rgb.round().astype(np.uint8)
def _ycbcr2rgb(img):
rgb = np.zeros(img.shape, np.float)
Y = img[:,:,0].astype(np.float)
Cr = img[:,:,2].astype(np.float)
Cb = img[:,:,1].astype(np.float)
delta = 128.0
rgb[:,:,0] = Y + 1.403 * (Cr - delta)
rgb[:,:,1] = Y - 0.714 * (Cr - delta) - 0.344 * (Cb - delta)
rgb[:,:,2] = Y + 1.773 * (Cb - delta)
return rgb.round().astype(np.uint8)
class FTLStreamWriter: class FTLStreamWriter:
def __init__(self, file): def __init__(self, file, version=2):
self._file = open(file, "wb") self._file = open(file, "wb")
self._file.write(bytes(ord(c) for c in "FTLF")) # magic self._file.write(bytes(ord(c) for c in "FTLF")) # magic
self._file.write(bytes([2])) # version self._file.write(bytes([version])) # version
self._file.write(bytes([0]*64)) # reserved self._file.write(bytes([0]*64)) # reserved
self._packer = msgpack.Packer(strict_types=False, use_bin_type=True) self._packer = msgpack.Packer(strict_types=False, use_bin_type=True)
...@@ -94,7 +106,7 @@ class FTLStreamWriter: ...@@ -94,7 +106,7 @@ class FTLStreamWriter:
if codec == ftl.codec_t.PNG: if codec == ftl.codec_t.PNG:
if ftl.is_float_channel(channel): if ftl.is_float_channel(channel):
# scaling always same (???) # scaling always same (???)
data = data.astype(np.float) / 1000.0 data = (data * 1000).astype(np.uint16)
params = [cv.IMWRITE_PNG_COMPRESSION, 9] params = [cv.IMWRITE_PNG_COMPRESSION, 9]
retval, data = cv.imencode(".png", data, params) retval, data = cv.imencode(".png", data, params)
...@@ -134,7 +146,8 @@ class FTLStreamWriter: ...@@ -134,7 +146,8 @@ class FTLStreamWriter:
raise NotImplementedError("todo") raise NotImplementedError("todo")
def add_calibration(self, timestamp, source, data): def add_calibration(self, timestamp, source, data):
struct.pack(_calib_fmt, *data) # todo: Use msgpack format instead (ftlf v3+)
struct.pack("@ddddIIdddd", *data)
raise NotImplementedError("todo") raise NotImplementedError("todo")
class FTLStreamReader: class FTLStreamReader:
...@@ -180,9 +193,19 @@ class FTLStreamReader: ...@@ -180,9 +193,19 @@ class FTLStreamReader:
def _update_calib(self, sp, p): def _update_calib(self, sp, p):
''' Update calibration. ''' ''' Update calibration. '''
calibration = struct.unpack(_calib_fmt, p.data[:(4*8+2*4+4*8)])
if p.codec == ftl.codec_t.MSGPACK:
# TODO: channel and capabilities should be saved as well
calib, channel, capabilities = msgpack.unpackb(p.data)
self._calibration[sp.streamID] = ftl.Camera._make(calib)
elif p.codec == ftl.codec_t.CALIBRATION:
calibration = struct.unpack("@ddddIIdddd", p.data[:(4*8+2*4+4*8)])
self._calibration[sp.streamID] = ftl.Camera._make(calibration) self._calibration[sp.streamID] = ftl.Camera._make(calibration)
else:
raise Exception("Unknown codec %i for calibration" % p.codec)
def _update_pose(self, sp, p): def _update_pose(self, sp, p):
''' Update pose ''' ''' Update pose '''
pose = np.asarray(struct.unpack("@16d", p.data[:(16*8)]), pose = np.asarray(struct.unpack("@16d", p.data[:(16*8)]),
...@@ -226,7 +249,10 @@ class FTLStreamReader: ...@@ -226,7 +249,10 @@ class FTLStreamReader:
raise NotImplementedError("non-color channel decoding not available") raise NotImplementedError("non-color channel decoding not available")
else: else:
if self._version < 3:
self._frame = _ycrcb2rgb(img) self._frame = _ycrcb2rgb(img)
else:
self._frame = _ycbcr2rgb(img)
def _decode_opencv(self, sp, p): def _decode_opencv(self, sp, p):
try: try:
...@@ -254,7 +280,7 @@ class FTLStreamReader: ...@@ -254,7 +280,7 @@ class FTLStreamReader:
Reads data for until the next timestamp. Returns False if there is no Reads data for until the next timestamp. Returns False if there is no
more data to read, otherwise returns True. more data to read, otherwise returns True.
todo: make decoding optional todo: make (frame) decoding optional
''' '''
self._frame = None self._frame = None
...@@ -268,16 +294,17 @@ class FTLStreamReader: ...@@ -268,16 +294,17 @@ class FTLStreamReader:
if self._p.block_total != 1 or self._p.block_number != 0: if self._p.block_total != 1 or self._p.block_number != 0:
raise Exception("Unsupported block format (todo)") raise Exception("Unsupported block format (todo)")
if self._p.codec == ftl.codec_t.JSON: # calibration/pose cached
self._process_json(self._sp, self._p) # todo: should be done by user instead?
elif self._p.codec == ftl.codec_t.CALIBRATION: if self._sp.channel == ftl.Channel.Calibration:
self._update_calib(self._sp, self._p) self._update_calib(self._sp, self._p)
elif self._p.codec == ftl.codec_t.POSE: elif self._sp.channel == ftl.Channel.Pose:
self._update_pose(self._sp, self._p) self._update_pose(self._sp, self._p)
elif self._p.codec == ftl.codec_t.HEVC: # decode if codec supported
if self._p.codec == ftl.codec_t.HEVC:
self._decode_hevc(self._sp, self._p) self._decode_hevc(self._sp, self._p)
elif self._p.codec == ftl.codec_t.PNG: elif self._p.codec == ftl.codec_t.PNG:
...@@ -287,7 +314,8 @@ class FTLStreamReader: ...@@ -287,7 +314,8 @@ class FTLStreamReader:
self._decode_opencv(self._sp, self._p) self._decode_opencv(self._sp, self._p)
else: else:
raise Exception("unkowno codec %i" % self._p.codec) # todo (unsupported codec)
pass
return True return True
...@@ -336,7 +364,7 @@ class FTLStreamReader: ...@@ -336,7 +364,7 @@ class FTLStreamReader:
raise ValueError("source id %i not found" % source) raise ValueError("source id %i not found" % source)
def get_Q(self, source): def get_Q(self, source):
''' Disparity to depth matrix in OpenCV format ''' ''' Disparity to depth matrix (OpenCV) '''
calib = self.get_calibration(source) calib = self.get_calibration(source)
Q = np.identity(4, dtype=np.float64) Q = np.identity(4, dtype=np.float64)
......
...@@ -65,7 +65,9 @@ class codec_t(IntEnum): ...@@ -65,7 +65,9 @@ class codec_t(IntEnum):
JSON = 100 JSON = 100
CALIBRATION = 101 CALIBRATION = 101
POSE = 102 POSE = 102
RAW = 103 MSGPACK = 103,
STRING = 104,
RAW = 105
definition_t = { definition_t = {
0 : (7680, 4320), 0 : (7680, 4320),
...@@ -85,4 +87,3 @@ def get_definition(shape): ...@@ -85,4 +87,3 @@ def get_definition(shape):
return k return k
return 7 # (None) return 7 # (None)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment