ialdev-io 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iad/io/__init__.py +17 -0
- iad/io/basic_formats.py +98 -0
- iad/io/bit_streams.py +98 -0
- iad/io/ciif.py +852 -0
- iad/io/format.py +678 -0
- iad/io/imread.py +296 -0
- iad/io/imwrite.py +55 -0
- iad/io/inu/__init__.py +0 -0
- iad/io/inu/env._py +55 -0
- iad/io/inu/utils/__init__.py +0 -0
- iad/io/inu/utils/imread.py +296 -0
- iad/io/pfm.py +79 -0
- iad/io/ply.py +260 -0
- iad/io/special.py +93 -0
- iad/io/tb.py +43 -0
- iad/io/tiff_tags.py +322 -0
- iad/io/video.py +189 -0
- iad/io/zfp.py +33 -0
- ialdev_io-0.1.0.dist-info/METADATA +24 -0
- ialdev_io-0.1.0.dist-info/RECORD +21 -0
- ialdev_io-0.1.0.dist-info/WHEEL +4 -0
iad/io/__init__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from .imread import imread
|
|
2
|
+
from .imwrite import imsave
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def read_meta(path):
|
|
6
|
+
"""Read file at path and return dict (e.g. YAML/JSON). Used by extract_attr when meta is a path."""
|
|
7
|
+
path = __import__('pathlib').Path(path)
|
|
8
|
+
suffix = path.suffix.lower()
|
|
9
|
+
if suffix in ('.yaml', '.yml'):
|
|
10
|
+
import yaml
|
|
11
|
+
return yaml.safe_load(path.read_text(encoding='utf-8')) or {}
|
|
12
|
+
if suffix in ('.json', '.js', '.jso', '.jsn'):
|
|
13
|
+
import json
|
|
14
|
+
return json.loads(path.read_text(encoding='utf-8'))
|
|
15
|
+
# fallback: try yaml
|
|
16
|
+
import yaml
|
|
17
|
+
return yaml.safe_load(path.read_text(encoding='utf-8')) or {}
|
iad/io/basic_formats.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from itertools import chain
|
|
4
|
+
from typing import Callable, Any
|
|
5
|
+
|
|
6
|
+
from .format import FileFormat, PathT, read_outputs, Content as CT, sfx_of
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MiddleburyCalib(FileFormat, patterns="calib.txt", content=CT.CONFIG):
|
|
10
|
+
@classmethod
|
|
11
|
+
def read(cls, filename: PathT, *, content=CT.CONFIG, **kws):
|
|
12
|
+
from .special import middlebury_calib
|
|
13
|
+
assert not kws and cls.valid_content(content)
|
|
14
|
+
return middlebury_calib(filename)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
_cfg_sfx = [['.yaml', '.yml'], ['.json', '.jso', '.js', '.jsn'], ['.toml', '.tml', '.ini']]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ConfigFormat(FileFormat, desc="Nested Textual Configuration",
|
|
21
|
+
content=CT.META | CT.CONFIG, patterns=[*chain(*_cfg_sfx)]):
|
|
22
|
+
from iad.core.param import TBox
|
|
23
|
+
_aliases = {sfx: grp[0].strip('.') for grp in _cfg_sfx for sfx in grp}
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def read(cls, filename: PathT, *, content=CT.UNDEF, **kws):
|
|
27
|
+
assert cls.valid_content(content)
|
|
28
|
+
name = f'from_{cls._aliases[sfx_of(filename)]}'
|
|
29
|
+
return getattr(cls.TBox, name)(filename=filename, **kws)
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def write(cls, filename: PathT, data: dict, **kws) -> Callable[[PathT], Any]:
|
|
33
|
+
"""Acquire read function by the format"""
|
|
34
|
+
name = f'to_{cls._aliases[sfx_of(filename)]}'
|
|
35
|
+
return getattr(cls.TBox(data), name)(filename=filename, **kws)
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def supports_write(cls, *, data=None, meta=None):
|
|
39
|
+
return meta is None and (
|
|
40
|
+
data is None or issubclass(data, dict))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class TifFormat(FileFormat, desc="Tiff with metadata in ImageDescription Tag",
|
|
44
|
+
patterns=['.tiff', '.tif'],
|
|
45
|
+
content=CT.META | CT.IMAGE):
|
|
46
|
+
_meta_tag = "ImageDescription"
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
@read_outputs
|
|
50
|
+
def read(cls, filename: PathT, *, content=CT.DATA, **kws):
|
|
51
|
+
"""No need for file_form"""
|
|
52
|
+
from tifffile import imread, tiffcomment
|
|
53
|
+
out = []
|
|
54
|
+
if content & CT.DATA:
|
|
55
|
+
out.append(imread(filename))
|
|
56
|
+
if content & CT.META:
|
|
57
|
+
import yaml
|
|
58
|
+
comment = tiffcomment(filename, tagcode=cls._meta_tag)
|
|
59
|
+
meta = yaml.load(comment, Loader=yaml.SafeLoader)
|
|
60
|
+
out.append(meta if isinstance(meta, dict) else None)
|
|
61
|
+
return tuple(out)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class ImageFormat(FileFormat, desc="General image format",
|
|
65
|
+
patterns=['.png', '.bmp', '.jpg'],
|
|
66
|
+
content=CT.IMAGE):
|
|
67
|
+
@classmethod
|
|
68
|
+
def read(cls, filename: PathT):
|
|
69
|
+
from .imread import imread
|
|
70
|
+
return imread(filename)
|
|
71
|
+
|
|
72
|
+
@classmethod
|
|
73
|
+
def write(cls, filename: PathT, data, *, meta=None, **kws):
|
|
74
|
+
from .imread import imsave
|
|
75
|
+
assert meta is None
|
|
76
|
+
imsave(filename, data, **kws)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class InuStereoFormat(FileFormat, desc="Inuitive Stereo Images with Cameras metadata",
|
|
80
|
+
patterns=[
|
|
81
|
+
r"StereoImage_\d+\.tif",
|
|
82
|
+
r"Output_Video_(Left|Right)_\d+\.(bmp|png|tif|jpg)",
|
|
83
|
+
r"Video_\d+\.(bmp|png|tif|jpg)"],
|
|
84
|
+
content=CT.IMAGE | CT.META):
|
|
85
|
+
"""Inuitive tif based format for 2 stereo images with custom tags."""
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
def read(cls, filename: PathT, content=CT.DATA, *kws):
|
|
89
|
+
"""No need for file_form"""
|
|
90
|
+
assert not kws
|
|
91
|
+
out = []
|
|
92
|
+
if content & CT.META:
|
|
93
|
+
from iad.io.inu.utils.imread import imread_stereo
|
|
94
|
+
out.append(imread_stereo(str(filename), cam_info=False))
|
|
95
|
+
if content & CT.DATA:
|
|
96
|
+
from iad.io.inu.utils.imread import tiff_inu_cam
|
|
97
|
+
out.append(tiff_inu_cam(str(filename)))
|
|
98
|
+
return tuple(out) if len(out) > 1 else out if len(out) == 1 else 0
|
iad/io/bit_streams.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
""" Bit streams operations"""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def save_bit_streams(full_file_name, streams, order=None):
|
|
5
|
+
""" Save bit stream
|
|
6
|
+
|
|
7
|
+
:param full_file_name: the full path of the .tiff file to be saved
|
|
8
|
+
:param streams: dict of dicts of streams. See my_streams in '__main__' for example
|
|
9
|
+
:param order: list of streams' names to record in specific order,
|
|
10
|
+
or list of fio {name:offset} to record in pre-defined offsets
|
|
11
|
+
:return: ---
|
|
12
|
+
"""
|
|
13
|
+
import tifffile, json
|
|
14
|
+
from iad.core.binary import join_bits
|
|
15
|
+
streams = streams.copy()
|
|
16
|
+
|
|
17
|
+
def extract_bits_data(names):
|
|
18
|
+
return zip(*[(streams[name]['bits'], streams[name]['data']) for name in names])
|
|
19
|
+
|
|
20
|
+
bits, data_streams = extract_bits_data(streams)
|
|
21
|
+
check_clip = False
|
|
22
|
+
ord_streams = None
|
|
23
|
+
|
|
24
|
+
if order is not None:
|
|
25
|
+
if type(order) == dict:
|
|
26
|
+
offsets = [order[name] for name in streams]
|
|
27
|
+
for name in streams: # ADD offsets TO streams to be used in unpacking
|
|
28
|
+
streams[name]['offset'] = order[name]
|
|
29
|
+
bits = list(zip(bits, offsets))
|
|
30
|
+
else:
|
|
31
|
+
assert hasattr(order, '__iter__')
|
|
32
|
+
bits, data_streams = extract_bits_data(order)
|
|
33
|
+
ord_streams = {name: streams[name] for name in order}
|
|
34
|
+
|
|
35
|
+
tiff_im = join_bits(bits, data_streams, check_clip)
|
|
36
|
+
|
|
37
|
+
for name in streams.keys():
|
|
38
|
+
del streams[name]['data']
|
|
39
|
+
metadata = json.dumps(streams if ord_streams is None else ord_streams) # REMOVE 'data' FROM streams AND PACK INTO JSON
|
|
40
|
+
|
|
41
|
+
tifffile.imsave(full_file_name, tiff_im, description=metadata)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def load_bit_streams(full_file_name):
|
|
45
|
+
""" Load bit streams from tiff file with YML metadata
|
|
46
|
+
|
|
47
|
+
:param full_file_name: the full path of the .tiff file to be loaded.
|
|
48
|
+
the file is assumed to contain YML metadata recorded by save_bit_streams()
|
|
49
|
+
:return: split data streams
|
|
50
|
+
"""
|
|
51
|
+
from iad.core.binary import split_bits
|
|
52
|
+
from imread import imread
|
|
53
|
+
tiff_im, streams = imread(full_file_name, get_meta=True)
|
|
54
|
+
|
|
55
|
+
bits = [streams[name]['bits'] for name in streams.keys()]
|
|
56
|
+
|
|
57
|
+
if 'offset' in list(streams.values())[0].keys(): # list(streams.values())[0]['offset'] != None:
|
|
58
|
+
offsets = [streams[name]['offset'] for name in streams.keys()]
|
|
59
|
+
bits = list(zip(bits, offsets))
|
|
60
|
+
|
|
61
|
+
data = split_bits(tiff_im, bits)
|
|
62
|
+
|
|
63
|
+
for i, name in enumerate(streams):
|
|
64
|
+
streams[name]['data'] = data[i]
|
|
65
|
+
|
|
66
|
+
return streams
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if __name__ == '__main__':
|
|
70
|
+
|
|
71
|
+
sz_x = 10 #640
|
|
72
|
+
sz_y = 10 #480
|
|
73
|
+
import numpy as np
|
|
74
|
+
conf_inf_bits = 4
|
|
75
|
+
conf_inf = np.random.randint(2 ** conf_inf_bits, size=(sz_x, sz_y)).astype('uint8')
|
|
76
|
+
|
|
77
|
+
disp_inf_bits = 1
|
|
78
|
+
disp_inf = np.ones((sz_x, sz_y), dtype='uint8')
|
|
79
|
+
|
|
80
|
+
my_streams = {
|
|
81
|
+
'conf_inf': {
|
|
82
|
+
'data': conf_inf,
|
|
83
|
+
'bits': conf_inf_bits,
|
|
84
|
+
'info': 'information score estimated from confidence'
|
|
85
|
+
},
|
|
86
|
+
'disp_inf': {
|
|
87
|
+
'data': disp_inf,
|
|
88
|
+
'bits': disp_inf_bits,
|
|
89
|
+
'info': 'important estimated from disparity'
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# Have to support order = None, order as list, and order as dictionary
|
|
94
|
+
order_my = ['disp_inf', 'conf_inf']
|
|
95
|
+
order_dict_my = {'disp_inf': 1, 'conf_inf': 3} # name: offset.
|
|
96
|
+
|
|
97
|
+
save_bit_streams('some_file.tif', my_streams, None) #order_my)
|
|
98
|
+
res_streams = load_bit_streams('some_file.tif')
|