diff --git a/python/ftl/ftlstream.py b/python/ftl/ftlstream.py index 65514f0ba1109700b338cf30e91b2d046754cc9b..2af8e71644d39e4c6145708668602f8cffb084d1 100644 --- a/python/ftl/ftlstream.py +++ b/python/ftl/ftlstream.py @@ -246,21 +246,43 @@ class FTLStreamReader: warn("frame expected, no image received from decoder") if ftl.is_float_channel(self._sp.channel): - # TODO: only supports 8 bits per pixel format and 16 bits - # ()"old format") - # - # NVPipe: (2 * width), high bits in left, low in right - - high = img[:,(img.shape[1]//2):,0].astype(np.uint32) << 8 - low = img[:,:(img.shape[1]//2),0].astype(np.uint32) - img = (high|low).astype(np.float)/1000.0 + if (p.flags & ftl.PacketFlags.MappedDepth): + # New format + + # hardcoded constants maxdepth and P + maxdepth = 16 + P = (2.0 * 256.0) / 16384.0 + + # use only 8 bits of 10 + img = (img >> 2).astype(np.float) / 255 + + L = img[:,:,0] + Ha = img[:,:,1] + Hb = img[:,:,2] + + m = np.floor(4.0 * (L/P) - 0.5).astype(np.int) % 4 + L0 = L - ((L-(P / 8.0)) % P) + (P / 4.0) * m.astype(np.float) - (P/8.0) + + s = np.zeros(img.shape[:2], dtype=np.float) + np.copyto(s, (P/2.0) * Ha, where=m == 0) + np.copyto(s, (P/2.0) * Hb, where=m == 1) + np.copyto(s, (P/2.0) * (1.0 - Ha), where=m == 2) + np.copyto(s, (P/2.0) * (1.0 - Hb), where=m == 3) + + img = (L0+s) * maxdepth + else: + # NvPipe format + high = img[:,(img.shape[1]//2):,0].astype(np.uint32) << 8 + low = img[:,:(img.shape[1]//2),0].astype(np.uint32) + img = (high|low).astype(np.float)/1000.0 + ''' try: img[img < self._calibration[sp.streamID].min_depth] = 0.0 img[img > self._calibration[sp.streamID].max_depth] = 0.0 except KeyError: warn("no calibration for received frame") - + ''' self._frame = img else: diff --git a/python/ftl/ftltypes.py b/python/ftl/ftltypes.py index 69eb872489e92bb460ae3c57365b85993a79f387..6c22004140b4e71e6a0ffbf4bc900e09b8a0ad28 100644 --- a/python/ftl/ftltypes.py +++ b/python/ftl/ftltypes.py @@ -13,6 +13,10 @@ Packet = namedtuple("Packet", ["codec", "definition", "block_total", StreamPacket = namedtuple("StreamPacket", ["timestamp", "streamID", "channel_count", "channel"]) +class PacketFlags: + RGB = 0x00000001 + MappedDepth = 0x00000002 + # components/codecs/include/ftl/codecs/channels.hpp class Channel(IntEnum): None_ = -1 diff --git a/python/ftl/libde265.py b/python/ftl/libde265.py index c57404eaa00477e8c487d608caecea82a8e57bfa..20ef8ca38c9b29f5f3408385f13a98af72081c7f 100644 --- a/python/ftl/libde265.py +++ b/python/ftl/libde265.py @@ -1,24 +1,28 @@ -''' -Python wrapper for libde265. Only decoding is (partly) implemented. +'''! +Python wrapper for libde265. Only decoding is implemented. Requirements: * libde265 library (libde265.so.0) * numpy - * opencv or skimage + * opencv (recommended) or skimage ''' try: import cv2 as cv def _resize(img, size): - return cv.resize(img, dsize=tuple(reversed(size)), interpolation=cv.INTER_CUBIC) + dst = np.zeros(size, dtype=img.dtype) + cv.resize(img, tuple(reversed(size)), dst, interpolation=cv.INTER_LINEAR) + return dst except ImportError: + # seems to be much slower than OpenCV resize() + from skimage.transform import resize as resize_skimage def _resize(img, size): - # skimage resize() return dtype float64, convert back to uint8 + # skimage resize() return dtype float64, convert back to original type # order: 0 nn, 1 bilinear, 3 bicubic - return (resize_skimage(img, size, order=3, mode="constant", cval=0) * 255).astype(np.uint8) + return (resize_skimage(img, size, order=2, mode="constant", cval=0) * np.iinfo(img.dtype).max).astype(img.dtype) from warnings import warn @@ -39,6 +43,10 @@ if _threads is None: _threads = 1 +################################################################################ +# interface and definitions from libde256 api +################################################################################ + # error codes copied from header (de265.h) class _libde265error(IntEnum): @@ -155,6 +163,8 @@ libde265.de265_get_image_plane.restype = ctypes.POINTER(ctypes.c_char) libde265.de265_get_number_of_input_bytes_pending.argtypes = [ctypes.c_void_p] libde265.de265_get_number_of_input_bytes_pending.restype = ctypes.c_int +################################################################################ + class libde265Error(Exception): def __init__(self, code): super(libde265Error, self).__init__( @@ -168,7 +178,7 @@ class Decoder: self._more = ctypes.c_int() self._out_stride = ctypes.c_int() self._ctx = libde265.de265_new_decoder() - self._supress_warnings = False + self._disable_warnings = False err = libde265.de265_start_worker_threads(self._ctx, threads) @@ -182,28 +192,29 @@ class Decoder: size = (libde265.de265_get_image_height(de265_image, 0), libde265.de265_get_image_width(de265_image, 0)) - res = np.zeros((*size, 3), dtype=np.uint8) + res = np.zeros((*size, 3), dtype=np.uint16) # libde265: always 420 (???) - # chroma_format = libde265.de265_get_chroma_format(de265_image) - + chroma_format = libde265.de265_get_chroma_format(de265_image) + if chroma_format != de265_chroma.de265_chroma_420: + raise NotImplementedError("Unsupported chroma format %s" % str(chroma_format)) + for c in range(0, 3): size_channel = (libde265.de265_get_image_height(de265_image, c), libde265.de265_get_image_width(de265_image, c)) if size_channel[0] > size[0] or size_channel[1] > size[1]: - # Is this possible? - print(size, size_channel) raise Exception("Channel larger than first channel") bpp = libde265.de265_get_bits_per_pixel(de265_image, c) - if bpp != 8: - raise NotImplementedError("%i-bit format not implemented (TODO)" % bpp) + if bpp == 8: + dtype = np.uint8 + else: + dtype = np.uint16 img_ptr = libde265.de265_get_image_plane(de265_image, c, self._out_stride) - # libde: how is 10 bits per pixel returned - ch = np.frombuffer(img_ptr[:size_channel[0] * size_channel[1]], dtype=np.uint8) + ch = np.frombuffer(img_ptr[:size_channel[0] * self._out_stride.value], dtype=dtype) ch.shape = size_channel res[:,:,c] = _resize(ch, size) @@ -211,7 +222,7 @@ class Decoder: return res def _warning(self): - if self._supress_warnings: + if self._disable_warnings: return code = libde265.de265_get_warning(self._ctx)