Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
ftl
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Nicolas Pope
ftl
Commits
bbc60185
Commit
bbc60185
authored
5 years ago
by
Sebastian
Browse files
Options
Downloads
Patches
Plain Diff
simpler interface
parent
86a69d11
No related branches found
No related tags found
1 merge request
!155
Feature/python
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
python/ftl/ftlstream.py
+81
-101
81 additions, 101 deletions
python/ftl/ftlstream.py
python/ftl/ftltypes.py
+1
-1
1 addition, 1 deletion
python/ftl/ftltypes.py
python/ftl/libde265.py
+14
-3
14 additions, 3 deletions
python/ftl/libde265.py
with
96 additions
and
105 deletions
python/ftl/ftlstream.py
+
81
−
101
View file @
bbc60185
...
...
@@ -12,6 +12,8 @@ from . misc import is_iframe
from
.
import
ftltypes
as
ftl
from
.
import
libde265
_calib_fmt
=
"
@ddddIIdddd
"
try
:
import
cv2
as
cv
...
...
@@ -19,6 +21,8 @@ try:
return
cv
.
cvtColor
(
img
,
cv
.
COLOR_YCrCb2RGB
)
except
ImportError
:
warn
(
"
OpenCV not available. OpenCV required for full functionality.
"
)
def
_ycrcb2rgb
(
img
):
'''
YCrCb to RGB, based on OpenCV documentation definition.
...
...
@@ -42,9 +46,10 @@ except ImportError:
class
FTLStreamWriter
:
def
__init__
(
self
,
file
):
self
.
_file
=
open
(
file
,
"
wb
"
)
self
.
_file
.
write
(
bytes
(
ord
(
c
)
for
c
in
"
FTLF
"
))
self
.
_file
.
write
(
bytes
([
2
]))
self
.
_file
.
write
(
bytes
([
0
]
*
64
))
self
.
_file
.
write
(
bytes
(
ord
(
c
)
for
c
in
"
FTLF
"
))
# magic
self
.
_file
.
write
(
bytes
([
2
]))
# version
self
.
_file
.
write
(
bytes
([
0
]
*
64
))
# reserved
self
.
_packer
=
msgpack
.
Packer
(
strict_types
=
False
,
use_bin_type
=
True
)
def
__del__
(
self
):
...
...
@@ -53,36 +58,20 @@ class FTLStreamWriter:
def
close
(
self
):
self
.
_file
.
close
()
def
add_source
(
self
,
parameters
,
pose
):
pass
def
add_raw
(
self
,
sp
,
p
):
if
len
(
sp
)
!=
len
(
ftl
.
StreamPacket
.
_fields
)
or
len
(
p
)
!=
len
(
ftl
.
Packet
.
_fields
):
raise
ValueError
(
"
invalid input
"
)
self
.
_file
.
write
(
self
.
_packer
.
pack
((
sp
,
p
)))
self
.
_file
.
flush
()
def
add_frame
(
self
,
timestamp
,
src
,
channel
,
codec
,
data
,
encode
=
True
):
pass
class
FTLStreamBufferedWriter
(
FTLStreamWriter
):
def
__init__
(
self
,
file
,
fps
=
25.0
):
super
(
FTLStreamWriter
,
file
)
self
.
_ts
=
0
self
.
_frame_t
=
int
(
1.0
/
fps
)
self
.
_n_sources
=
0
self
.
_frames
=
[]
def
add_source
(
self
,
count
=
1
):
self
.
_n_sources
+=
count
return
self
.
_n_sources
def
add_calibration
(
self
,
source
):
if
not
0
<
source
<
self
.
_n_sources
:
raise
ValueError
(
"
invalid source id
"
)
def
add_frame
(
self
,
source
,
channel
,
data
,
codec
,
definition
=
None
,
flags
=
0
,
encode
=
True
):
if
not
0
<
source
<
self
.
_n_sources
:
def
add_frame
(
self
,
timestamp
,
source
,
channel
,
channel_count
,
codec
,
data
,
definition
=
None
,
flags
=
0
,
encode
=
True
):
'''
Write frame to file. If encode is False (data already encoded),
definition needs to be specified.
'''
if
source
<
0
:
raise
ValueError
(
"
invalid source id
"
)
if
channel
not
in
ftl
.
Channel
:
...
...
@@ -92,7 +81,7 @@ class FTLStreamBufferedWriter(FTLStreamWriter):
raise
ValueError
(
"
invalid codec
"
)
if
encode
:
if
definition
is
not
None
:
if
definition
is
None
:
definition
=
ftl
.
get_definition
(
data
.
shape
)
if
definition
is
None
:
...
...
@@ -131,38 +120,48 @@ class FTLStreamBufferedWriter(FTLStreamWriter):
if
not
isinstance
(
data
,
bytes
):
raise
ValueError
(
"
expected bytes
"
)
ftl
.
Packet
(
int
(
codec
),
int
(
definition
),
1
,
0
,
int
(
flags
),
data
)
sp
=
ftl
.
StreamPacket
(
int
(
timestamp
),
int
(
source
),
int
(
channel_count
),
int
(
channel
))
p
=
ftl
.
Packet
(
int
(
codec
),
int
(
definition
),
1
,
0
,
int
(
flags
),
data
)
def
push_frames
(
self
):
for
frame
in
self
.
_frames
:
self
.
add_raw
(
sp
,
p
)
self
.
_ts
+=
self
.
_frame_t
self
.
add_raw
(
sp
,
p
)
def
add_pose
(
self
,
timestamp
,
source
,
data
):
if
data
.
shape
!=
(
4
,
4
):
raise
ValueError
(
"
invalid pose
"
)
data
.
astype
(
np
.
float64
).
tobytes
(
order
=
'
F
'
)
raise
NotImplementedError
(
"
todo
"
)
def
add_calibration
(
self
,
timestamp
,
source
,
data
):
struct
.
pack
(
_calib_fmt
,
*
data
)
raise
NotImplementedError
(
"
todo
"
)
class
FTLStreamReader
:
'''
FTL file reader
'''
'''
FTL file reader
.
'''
def
__init__
(
self
,
file
):
self
.
_file
=
open
(
file
,
"
br
"
)
self
.
_decoders
=
{}
self
.
_version
=
0
self
.
_decoders_hevc
=
{}
self
.
_seen_iframe
=
set
()
self
.
_frameset
=
{}
self
.
_frameset_new
=
{}
self
.
_frame
=
None
# calibration and pose are cached
self
.
_calibration
=
{}
self
.
_pose
=
{}
self
.
_ts
=
-
sys
.
maxsize
-
1
try
:
magic
=
self
.
_file
.
read
(
5
)
version
=
int
(
magic
[
4
])
self
.
_
version
=
int
(
magic
[
4
])
if
magic
[:
4
]
!=
bytes
(
ord
(
c
)
for
c
in
"
FTLF
"
):
raise
Exception
(
"
wrong magic
"
)
if
==
2
:
if
self
.
_version
>=
2
:
# first 64 bytes reserved
self
.
_file
.
read
(
8
*
8
)
self
.
_unpacker
=
msgpack
.
Unpacker
(
self
.
_file
,
raw
=
True
,
use_list
=
False
)
...
...
@@ -180,23 +179,15 @@ class FTLStreamReader:
return
ftl
.
StreamPacket
.
_make
(
v1
),
ftl
.
Packet
.
_make
(
v2
)
def
_update_calib
(
self
,
sp
,
p
):
'''
Update calibration.
todo: fix endianess
'''
calibration
=
struct
.
unpack
(
"
@ddddIIdddd
"
,
p
.
data
[:(
4
*
8
+
2
*
4
+
4
*
8
)])
'''
Update calibration.
'''
calibration
=
struct
.
unpack
(
_calib_fmt
,
p
.
data
[:(
4
*
8
+
2
*
4
+
4
*
8
)])
self
.
_calibration
[
sp
.
streamID
]
=
ftl
.
Camera
.
_make
(
calibration
)
def
_update_pose
(
self
,
sp
,
p
):
'''
Update pose
todo: fix endianess
'''
'''
Update pose
'''
pose
=
np
.
asarray
(
struct
.
unpack
(
"
@16d
"
,
p
.
data
[:(
16
*
8
)]),
dtype
=
np
.
float64
)
pose
=
pose
.
reshape
((
4
,
4
),
order
=
'
F
'
)
# Eigen
self
.
_pose
[
sp
.
streamID
]
=
pose
def
_process_json
(
self
,
sp
,
p
):
...
...
@@ -207,10 +198,10 @@ class FTLStreamReader:
k
=
(
sp
.
streamID
,
sp
.
channel
)
if
k
not
in
self
.
_decoders
:
self
.
_decoders
[
k
]
=
libde265
.
Decoder
(
ftl
.
definition_t
[
p
.
definition
])
if
k
not
in
self
.
_decoders
_hevc
:
self
.
_decoders
_hevc
[
k
]
=
libde265
.
Decoder
(
ftl
.
definition_t
[
p
.
definition
])
decoder
=
self
.
_decoders
[
k
]
decoder
=
self
.
_decoders
_hevc
[
k
]
if
k
not
in
self
.
_seen_iframe
:
if
not
is_iframe
(
p
.
data
):
...
...
@@ -231,37 +222,39 @@ class FTLStreamReader:
# if this happens, does get_next_picture() in loop help?
warn
(
"
frame expected, no image from decoded
"
)
self
.
_frame
=
_ycrcb2rgb
(
img
)
self
.
_frameset_new
[
k
]
=
self
.
_frame
if
ftl
.
is_float_channel
(
self
.
_sp
.
channel
):
raise
NotImplementedError
(
"
non-color channel decoding not available
"
)
else
:
self
.
_frame
=
_ycrcb2rgb
(
img
)
def
_decode_
png
(
self
,
sp
,
p
):
def
_decode_
opencv
(
self
,
sp
,
p
):
try
:
cv
except
NameError
:
raise
Exception
(
"
OpenCV required for
PNG
decoding
"
)
raise
Exception
(
"
OpenCV required for
OpenCV (png/jpeg)
decoding
"
)
self
.
_frame
=
cv
.
imdecode
(
np
.
frombuffer
(
p
.
data
,
dtype
=
np
.
uint8
),
cv
.
IMREAD_ANYDEPTH
)
self
.
_frame
=
self
.
_frame
.
astype
(
np
.
float
)
/
1000.0
self
.
_frameset_new
[(
sp
.
streamID
,
sp
.
channel
)]
=
self
.
_frame
cv
.
IMREAD_UNCHANGED
)
def
_flush_decoders
(
self
):
for
decoder
in
self
.
_decoders
.
values
():
decoder
.
flush_data
()
if
ftl
.
is_float_channel
(
self
.
_sp
.
channel
):
self
.
_frame
=
self
.
_frame
.
astype
(
np
.
float
)
/
1000.0
def
seek
(
self
,
ts
):
'''
Read until timestamp reached
'''
if
self
.
_ts
>=
ts
:
if
self
.
get_timestamp
()
>=
ts
:
raise
Exception
(
"
trying to seek to earlier timestamp
"
)
while
self
.
read
():
if
self
.
_ts
>=
ts
:
if
self
.
get_timestamp
()
>=
ts
:
break
def
read
(
self
):
'''
Reads data for until the next timestamp. Returns False if there is no
more data to read, otherwise returns True.
todo: make decoding optional
'''
self
.
_frame
=
None
...
...
@@ -270,19 +263,8 @@ class FTLStreamReader:
self
.
_packets_read
+=
1
except
msgpack
.
OutOfData
:
self
.
_frameset
=
self
.
_frameset_new
self
.
_frameset_new
=
{}
return
False
if
self
.
_sp
.
timestamp
<
self
.
_ts
:
# old data, do not update
return
True
if
self
.
_sp
.
timestamp
>
self
.
_ts
:
self
.
_ts
=
self
.
_sp
.
timestamp
self
.
_frameset
=
self
.
_frameset_new
self
.
_frameset_new
=
{}
if
self
.
_p
.
block_total
!=
1
or
self
.
_p
.
block_number
!=
0
:
raise
Exception
(
"
Unsupported block format (todo)
"
)
...
...
@@ -299,7 +281,10 @@ class FTLStreamReader:
self
.
_decode_hevc
(
self
.
_sp
,
self
.
_p
)
elif
self
.
_p
.
codec
==
ftl
.
codec_t
.
PNG
:
self
.
_decode_png
(
self
.
_sp
,
self
.
_p
)
self
.
_decode_opencv
(
self
.
_sp
,
self
.
_p
)
elif
self
.
_p
.
codec
==
ftl
.
codec_t
.
JPG
:
self
.
_decode_opencv
(
self
.
_sp
,
self
.
_p
)
else
:
raise
Exception
(
"
unkowno codec %i
"
%
self
.
_p
.
codec
)
...
...
@@ -310,10 +295,22 @@ class FTLStreamReader:
return
self
.
_packets_read
def
get_raw
(
self
):
'''
Returns previously received StreamPacket and Packet
'''
return
self
.
_sp
,
self
.
_p
def
get_channel_type
(
self
):
return
ftl
.
Channel
(
self
.
_sp
.
channel
)
def
get_source_id
(
self
):
return
self
.
_sp
.
streamID
def
get_timestamp
(
self
):
return
self
.
_ts
return
self
.
_sp
.
timestamp
def
get_frame
(
self
):
'''
Return decoded frame from previous packet. Returns None if previous
packet did not contain a (valid) frame.
'''
return
self
.
_frame
def
get_pose
(
self
,
source
):
try
:
...
...
@@ -337,26 +334,7 @@ class FTLStreamReader:
return
self
.
_calibration
[
source
]
except
KeyError
:
raise
ValueError
(
"
source id %i not found
"
%
source
)
def
get_frame
(
self
):
'''
Return decoded frame from previous packet. Returns None if previous
packet did not contain a (valid) frame.
'''
return
self
.
_frame
def
get_frameset
(
self
):
return
self
.
_frameset
def
get_frameset_frame
(
self
,
source
,
channel
):
k
=
(
source
,
channel
)
if
k
in
self
.
_frameset
:
return
self
.
_frameset
[
k
]
else
:
# raise an exception instead?
return
None
def
get_frameset_sources
(
self
):
return
list
(
set
(
src
for
src
,
_
in
self
.
_frameset
.
keys
()))
def
get_Q
(
self
,
source
):
'''
Disparity to depth matrix in OpenCV format
'''
...
...
@@ -374,3 +352,5 @@ class FTLStreamReader:
'''
Get list of sources
'''
return
list
(
self
.
_calibration
.
keys
())
def
get_version
(
self
):
return
self
.
_version
This diff is collapsed.
Click to expand it.
python/ftl/ftltypes.py
+
1
−
1
View file @
bbc60185
...
...
@@ -11,7 +11,7 @@ Packet = namedtuple("Packet", ["codec", "definition", "block_total",
"
block_number
"
,
"
flags
"
,
"
data
"
])
StreamPacket
=
namedtuple
(
"
StreamPacket
"
,
[
"
timestamp
"
,
"
streamID
"
,
"
chanel_count
"
,
"
channel
"
])
"
chan
n
el_count
"
,
"
channel
"
])
# components/codecs/include/ftl/codecs/channels.hpp
class
Channel
(
IntEnum
):
...
...
This diff is collapsed.
Click to expand it.
python/ftl/libde265.py
+
14
−
3
View file @
bbc60185
...
...
@@ -88,6 +88,12 @@ class _libde265error(IntEnum):
DE265_WARNING_SPS_MISSING_CANNOT_DECODE_SEI
=
1025
DE265_WARNING_COLLOCATED_MOTION_VECTOR_OUTSIDE_IMAGE_AREA
=
1026
class
de265_chroma
(
IntEnum
):
de265_chroma_mono
=
0
de265_chroma_420
=
1
de265_chroma_422
=
2
de265_chroma_444
=
3
libde265
=
ctypes
.
cdll
.
LoadLibrary
(
"
libde265.so.0
"
)
libde265
.
de265_get_error_text
.
argtypes
=
[
ctypes
.
c_void_p
]
...
...
@@ -131,6 +137,9 @@ libde265.de265_peek_next_picture.restype = ctypes.c_void_p
libde265
.
de265_release_next_picture
.
argtypes
=
[
ctypes
.
c_void_p
]
libde265
.
de265_release_next_picture
.
restype
=
None
libde265
.
de265_get_chroma_format
.
argtypes
=
[
ctypes
.
c_void_p
]
libde265
.
de265_get_chroma_format
.
restype
=
ctypes
.
c_int
libde265
.
de265_get_image_width
.
argtypes
=
[
ctypes
.
c_void_p
,
ctypes
.
c_int
]
libde265
.
de265_get_image_width
.
restype
=
ctypes
.
c_int
...
...
@@ -172,16 +181,18 @@ class Decoder:
def
_copy_image
(
self
,
de265_image
):
res
=
np
.
zeros
((
self
.
_size
[
0
],
self
.
_size
[
1
],
3
),
dtype
=
np
.
uint8
)
# libde265: always 420 (???)
# chroma_format = libde265.de265_get_chroma_format(de265_image)
for
c
in
range
(
0
,
3
):
size
=
(
libde265
.
de265_get_image_height
(
de265_image
,
c
),
libde265
.
de265_get_image_width
(
de265_image
,
c
))
bpp
=
libde265
.
de265_get_bits_per_pixel
(
de265_image
,
c
)
if
bpp
!=
8
:
raise
NotImplementedError
(
"
unsupported bits per pixel %i
"
%
bpp
)
img_ptr
=
libde265
.
de265_get_image_plane
(
de265_image
,
c
,
self
.
_out_stride
)
# for frombuffer() no copy assumed
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment