Skip to content

Commit

Permalink
fix(e2e_format.py): change the name of E2EFile to E2EFormat to avoid …
Browse files Browse the repository at this point in the history
…confustion with E2EFileStructure in e2e_reader.py
  • Loading branch information
Oli4 committed Mar 15, 2023
1 parent 4e41acd commit 01be6a0
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 23 deletions.
12 changes: 6 additions & 6 deletions docs/formats/he_e2e_structures/he_e2e_structure_doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ In contrast to the VOL and XML exports the E2E data may contain several OCT volu
# File Structure
The first bytes in an E2E file contain a version structure followed by a header structure. The header gives you access to the rest of the file by identifying the position of the last chunk of data. Each chunk has exactly 512 elements which we call folders.

{{ get_structure_doc("E2EFile") }}
{{ get_structure_doc("E2EFormat") }}

### Chunk
Every chunk has a header similar to the file header. A chunk then holds the headers of all contained folders sequentially, followed by data containers, that are referenced by the folder headers. A chunk can contain folders with data of different patients, studies, series, slices and types. Each folder contains data for a single (patient, study, series, slice, type) combination which is given in the folder header as well as the data container header. For the last chunk to have 512 folders, empty folders of `type=0` are appended.
Expand All @@ -30,23 +30,23 @@ In the following sections we describe the data items we found in each level of t

### Slice Data

{{ get_hierarchy_doc("E2ESlice") }}
{{ get_hierarchy_doc("E2ESliceStructure") }}

### Series Data

{{ get_hierarchy_doc("E2ESeries") }}
{{ get_hierarchy_doc("E2ESeriesStructure") }}

### Study Data

{{ get_hierarchy_doc("E2EStudy") }}
{{ get_hierarchy_doc("E2EStudyStructure") }}

### Patient Data

{{ get_hierarchy_doc("E2EPatient") }}
{{ get_hierarchy_doc("E2EPatientStructure") }}

### General Data

{{ get_hierarchy_doc("E2EFile") }}
{{ get_hierarchy_doc("E2EFileStructure") }}


## Further observations
Expand Down
6 changes: 3 additions & 3 deletions src/eyepy/io/he/e2e_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ class Version(DataclassMixin):


@dataclasses.dataclass
class E2EFile(DataclassMixin):
class E2EFormat(DataclassMixin):
"""E2E file format
Size: variable
Expand All @@ -759,10 +759,10 @@ class E2EFile(DataclassMixin):
doc="The number and size of the chunks depends on the data")


e2e_format = DataclassStruct(E2EFile)
e2e_format = DataclassStruct(E2EFormat)

__e2efile_structures__ = [
E2EFile,
E2EFormat,
Version,
Chunk,
Header,
Expand Down
48 changes: 34 additions & 14 deletions src/eyepy/io/he/e2e_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import logging
from pathlib import Path
from textwrap import indent
import traceback
from typing import Any, Dict, List, Optional, Tuple, Union

import construct as cs
Expand Down Expand Up @@ -419,12 +420,7 @@ def get_volume(self) -> EyeVolume:
## Check if scan is a volume scan
volume_meta = self.get_meta()

size_x = volume_meta["bscan_meta"][0]["size_x"]
size_y = volume_meta["bscan_meta"][0]["size_y"]
scan_pattern = volume_meta["bscan_meta"][0]["scan_pattern"]
n_bscans = volume_meta["bscan_meta"][0]["n_bscans"] if len(
self.get_bscan_meta()
) != 1 else 1 # n_bscans is 0 instead of 1 for single B-scan Volumes in the e2e file.

## Check if scan pattern is supported by EyeVolume
if scan_pattern == 2:
Expand All @@ -434,13 +430,7 @@ def get_volume(self) -> EyeVolume:
msg = f"The EyeVolume object does not support scan pattern 5 (Radial scan - star pattern)."
raise ValueError(msg)

data = np.zeros((n_bscans, size_y, size_x))
for ind, sl in self.slices.items():
bscan = sl.get_image()
i = ind // 2 if len(
self.get_bscan_meta()
) != 1 else 0 # Slice id for single B-scan Volumes is 2 and not 0 in the e2e file.
data[i] = bscan
data = self.get_bscans()

volume_meta = self.get_meta()
localizer = self.get_localizer()
Expand All @@ -459,6 +449,23 @@ def get_volume(self) -> EyeVolume:

return volume

def get_bscans(self) -> np.ndarray:
volume_meta = self.get_meta()
size_x = volume_meta["bscan_meta"][0]["size_x"]
size_y = volume_meta["bscan_meta"][0]["size_y"]
n_bscans = volume_meta["bscan_meta"][0]["n_bscans"] if len(
self.get_bscan_meta()
) != 1 else 1 # n_bscans is 0 instead of 1 for single B-scan Volumes in the e2e file.

data = np.zeros((n_bscans, size_y, size_x))
for ind, sl in self.slices.items():
bscan = sl.get_image()
i = ind // 2 if len(
self.get_bscan_meta()
) != 1 else 0 # Slice id for single B-scan Volumes is 2 and not 0 in the e2e file.
data[i] = bscan
return data

def get_layers(self) -> Dict[int, np.ndarray]:
"""Return layer height maps for the series as dict of numpy arrays where the key is the layer id."""
slice_layers = {}
Expand Down Expand Up @@ -883,7 +890,14 @@ def volume(self) -> EyeVolume:
Returns:
EyeVolume object for the first Series in the e2e file.
"""
return self.series[0].get_volume()
for s in self.series:
try:
return s.get_volume()
except Exception as e:
logger.debug("".join(traceback.format_exception(e)))
raise ValueError(
"No Series in the E2E file can be parsed to a an EyeVolume object. You might be able to extract information manually from the E2ESeries objects (e2ereader.series)"
)

@property
def volumes(self) -> List[EyeVolume]:
Expand All @@ -892,4 +906,10 @@ def volumes(self) -> List[EyeVolume]:
Returns:
List with EyeVolume objects for every Series in the e2e file.
"""
return [s.get_volume() for s in self.series]
volumes = []
for s in self.series:
try:
volumes.append(s.get_volume())
except Exception as e:
logger.debug("".join(traceback.format_exception(e)))
return volumes

0 comments on commit 01be6a0

Please sign in to comment.