Skip to content

Commit

Permalink
Lytro plugin: read only metadata (#565)
Browse files Browse the repository at this point in the history
* Add options to only read metadata and no thumbnail

* Update tests for new options
  • Loading branch information
Maximilian Schambach committed Nov 16, 2020
1 parent a64b3ad commit 182129b
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 56 deletions.
141 changes: 85 additions & 56 deletions imageio/plugins/lytro.py
Expand Up @@ -93,7 +93,8 @@ class LytroIllumRawFormat(LytroFormat):
Parameters for reading
----------------------
None
meta_only : bool
Whether to only read the metadata.
"""

def _can_read(self, request):
Expand Down Expand Up @@ -138,9 +139,10 @@ def rearrange_bits(array):
# -- reader

class Reader(Format.Reader):
def _open(self):
def _open(self, meta_only=False):
self._file = self.request.get_file()
self._data = None
self._meta_only = meta_only

def _close(self):
# Close the reader.
Expand All @@ -157,15 +159,20 @@ def _get_data(self, index):
if index not in [0, "None"]:
raise IndexError("Lytro file contains only one dataset")

# Read all bytes
if self._data is None:
self._data = self._file.read()
if not self._meta_only:
# Read all bytes
if self._data is None:
self._data = self._file.read()

# Read bytes from string and convert to uint16
raw = np.frombuffer(self._data, dtype=np.uint8).astype(np.uint16)
# Read bytes from string and convert to uint16
raw = np.frombuffer(self._data, dtype=np.uint8).astype(np.uint16)

# Rearrange bits
img = LytroIllumRawFormat.rearrange_bits(raw)
# Rearrange bits
img = LytroIllumRawFormat.rearrange_bits(raw)

else:
# Return empty image
img = np.array([])

# Return image and meta data
return img, self._get_meta_data(index=0)
Expand Down Expand Up @@ -204,7 +211,10 @@ class LytroLfrFormat(LytroFormat):
Parameters for reading
----------------------
None
meta_only : bool
Whether to only read the metadata.
include_thumbnail : bool
Whether to include an image thumbnail in the metadata.
"""

def _can_read(self, request):
Expand All @@ -216,12 +226,14 @@ def _can_read(self, request):
# -- reader

class Reader(Format.Reader):
def _open(self):
def _open(self, meta_only=False, include_thumbnail=True):
self._file = self.request.get_file()
self._data = None
self._chunks = {}
self.metadata = {}
self._content = None
self._meta_only = meta_only
self._include_thumbnail = include_thumbnail

self._find_header()
self._find_chunks()
Expand All @@ -235,11 +247,11 @@ def _open(self):
and chunk_dict["imageRef"] in self._chunks
and chunk_dict["privateMetadataRef"] in self._chunks
):

# Read raw image data byte buffer
data_pos, size = self._chunks[chunk_dict["imageRef"]]
self._file.seek(data_pos, 0)
self.raw_image_data = self._file.read(size)
if not self._meta_only:
# Read raw image data byte buffer
data_pos, size = self._chunks[chunk_dict["imageRef"]]
self._file.seek(data_pos, 0)
self.raw_image_data = self._file.read(size)

# Read meta data
data_pos, size = self._chunks[chunk_dict["metadataRef"]]
Expand All @@ -257,24 +269,25 @@ def _open(self):
self.metadata["privateMetadata"] = self.serial_numbers

# Read image preview thumbnail
chunk_dict = self._content["thumbnails"][0]
if chunk_dict["imageRef"] in self._chunks:
# Read thumbnail image from thumbnail chunk
data_pos, size = self._chunks[chunk_dict["imageRef"]]
self._file.seek(data_pos, 0)
# Read binary data, read image as jpeg
thumbnail_data = self._file.read(size)
thumbnail_img = imread(thumbnail_data, format="jpeg")

thumbnail_height = chunk_dict["height"]
thumbnail_width = chunk_dict["width"]

# Add thumbnail to metadata
self.metadata["thumbnail"] = {
"image": thumbnail_img,
"height": thumbnail_height,
"width": thumbnail_width,
}
if self._include_thumbnail:
chunk_dict = self._content["thumbnails"][0]
if chunk_dict["imageRef"] in self._chunks:
# Read thumbnail image from thumbnail chunk
data_pos, size = self._chunks[chunk_dict["imageRef"]]
self._file.seek(data_pos, 0)
# Read binary data, read image as jpeg
thumbnail_data = self._file.read(size)
thumbnail_img = imread(thumbnail_data, format="jpeg")

thumbnail_height = chunk_dict["height"]
thumbnail_width = chunk_dict["width"]

# Add thumbnail to metadata
self.metadata["thumbnail"] = {
"image": thumbnail_img,
"height": thumbnail_height,
"width": thumbnail_width,
}

except KeyError:
raise RuntimeError("The specified file is not a valid LFR file.")
Expand Down Expand Up @@ -375,9 +388,12 @@ def _get_data(self, index):
if index not in [0, None]:
raise IndexError("Lytro lfr file contains only one dataset")

# Read bytes from string and convert to uint16
raw = np.frombuffer(self.raw_image_data, dtype=np.uint8).astype(np.uint16)
im = LytroIllumRawFormat.rearrange_bits(raw)
if not self._meta_only:
# Read bytes from string and convert to uint16
raw = np.frombuffer(self.raw_image_data, dtype=np.uint8).astype(np.uint16)
im = LytroIllumRawFormat.rearrange_bits(raw)
else:
im = np.array([])

# Return array and dummy meta data
return im, self.metadata
Expand All @@ -401,7 +417,8 @@ class LytroF01RawFormat(LytroFormat):
Parameters for reading
----------------------
None
meta_only : bool
Whether to only read the metadata.
"""

Expand Down Expand Up @@ -437,9 +454,10 @@ def rearrange_bits(array):
# -- reader

class Reader(Format.Reader):
def _open(self):
def _open(self, meta_only=False):
self._file = self.request.get_file()
self._data = None
self._meta_only = meta_only

def _close(self):
# Close the reader.
Expand All @@ -456,15 +474,19 @@ def _get_data(self, index):
if index not in [0, "None"]:
raise IndexError("Lytro file contains only one dataset")

# Read all bytes
if self._data is None:
self._data = self._file.read()
if not self._meta_only:
# Read all bytes
if self._data is None:
self._data = self._file.read()

# Read bytes from string and convert to uint16
raw = np.frombuffer(self._data, dtype=np.uint8).astype(np.uint16)

# Read bytes from string and convert to uint16
raw = np.frombuffer(self._data, dtype=np.uint8).astype(np.uint16)
# Rearrange bits
img = LytroF01RawFormat.rearrange_bits(raw)

# Rearrange bits
img = LytroF01RawFormat.rearrange_bits(raw)
else:
img = np.array([])

# Return image and meta data
return img, self._get_meta_data(index=0)
Expand Down Expand Up @@ -503,7 +525,10 @@ class LytroLfpFormat(LytroFormat):
Parameters for reading
----------------------
None
meta_only : bool
Whether to only read the metadata.
include_thumbnail : bool
Whether to include an image thumbnail in the metadata.
"""

def _can_read(self, request):
Expand All @@ -515,12 +540,13 @@ def _can_read(self, request):
# -- reader

class Reader(Format.Reader):
def _open(self):
def _open(self, meta_only=False):
self._file = self.request.get_file()
self._data = None
self._chunks = {}
self.metadata = {}
self._content = None
self._meta_only = meta_only

self._find_header()
self._find_meta()
Expand All @@ -534,11 +560,11 @@ def _open(self):
and chunk_dict["imageRef"] in self._chunks
and chunk_dict["privateMetadataRef"] in self._chunks
):

# Read raw image data byte buffer
data_pos, size = self._chunks[chunk_dict["imageRef"]]
self._file.seek(data_pos, 0)
self.raw_image_data = self._file.read(size)
if not self._meta_only:
# Read raw image data byte buffer
data_pos, size = self._chunks[chunk_dict["imageRef"]]
self._file.seek(data_pos, 0)
self.raw_image_data = self._file.read(size)

# Read meta data
data_pos, size = self._chunks[chunk_dict["metadataRef"]]
Expand Down Expand Up @@ -657,9 +683,12 @@ def _get_data(self, index):
if index not in [0, None]:
raise IndexError("Lytro lfp file contains only one dataset")

# Read bytes from string and convert to uint16
raw = np.frombuffer(self.raw_image_data, dtype=np.uint8).astype(np.uint16)
im = LytroF01RawFormat.rearrange_bits(raw)
if not self._meta_only:
# Read bytes from string and convert to uint16
raw = np.frombuffer(self.raw_image_data, dtype=np.uint8).astype(np.uint16)
im = LytroF01RawFormat.rearrange_bits(raw)
else:
im = np.array([])

# Return array and dummy meta data
return im, self.metadata
Expand Down
30 changes: 30 additions & 0 deletions tests/test_lytro.py
Expand Up @@ -419,6 +419,20 @@ def test_lytro_lfr_reading():
assert img._meta["metadata"] == metadata_gt
assert img._meta["privateMetadata"] == private_metadata_gt

# Read metadata only (with thumbnail)
img = imageio.imread(lfr_file, format="lytro-lfr", meta_only=True)
assert np.array_equal(img, [])
assert img._meta["metadata"] == metadata_gt
assert img._meta["privateMetadata"] == private_metadata_gt
assert np.array_equal(img._meta["thumbnail"]["image"], thumb_gt)

# Read metadata only (without thumbnail)
img = imageio.imread(lfr_file, format="lytro-lfr", meta_only=True, include_thumbnail=False)
assert np.array_equal(img, [])
assert img._meta["metadata"] == metadata_gt
assert img._meta["privateMetadata"] == private_metadata_gt
assert "thumbnail" not in img._meta.keys()

# Test fail
test_reader = imageio.read(lfr_file, "lytro-lfr")
raises(IndexError, test_reader.get_data, -1)
Expand Down Expand Up @@ -563,6 +577,12 @@ def test_lytro_lfp_reading():
assert img._meta["metadata"] == metadata_gt
assert img._meta["privateMetadata"] == private_metadata_gt

# Read metadata only
img = imageio.imread(lfp_file, format="lytro-lfp", meta_only=True)
assert np.array_equal(img, [])
assert img._meta["metadata"] == metadata_gt
assert img._meta["privateMetadata"] == private_metadata_gt

# Test fail
test_reader = imageio.read(lfp_file, "lytro-lfp")
raises(IndexError, test_reader.get_data, -1)
Expand Down Expand Up @@ -596,6 +616,11 @@ def test_lytro_raw_illum_reading():
# Test extracted metadata against extracted metadata from .txt file
assert img._meta == meta_gt

# Read metadata only
img = imageio.imread(raw_file, format="lytro-illum-raw", meta_only=True)
assert np.array_equal(img, [])
assert img._meta == meta_gt

# Test fail
test_reader = imageio.read(raw_file, "lytro-illum-raw")
raises(IndexError, test_reader.get_data, -1)
Expand Down Expand Up @@ -629,6 +654,11 @@ def test_lytro_raw_f0_reading():
# Test extracted metadata against extracted metadata from .txt file
assert img._meta == meta_gt

# Read metadata only
img = imageio.imread(raw_file, format="lytro-f01-raw", meta_only=True)
assert np.array_equal(img, [])
assert img._meta == meta_gt

# Test fail
test_reader = imageio.read(raw_file, "lytro-f01-raw")
raises(IndexError, test_reader.get_data, -1)
Expand Down

0 comments on commit 182129b

Please sign in to comment.