From 4943a854f1679be57d18ee96407ce913260da4c0 Mon Sep 17 00:00:00 2001 From: jim Date: Tue, 17 Nov 2015 10:41:07 -0600 Subject: [PATCH] resolves #123: the label map and raw metadata are now accessible, so we can more easily compare what they contain to the information in the XML (which we're still not parsing) --- functional_tests/single.py | 7 +++++++ nd2reader/driver/v3.py | 2 +- nd2reader/model/label.py | 18 +++++++++--------- nd2reader/parser/v3.py | 14 +++++++------- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/functional_tests/single.py b/functional_tests/single.py index cc2f5c4..d884248 100644 --- a/functional_tests/single.py +++ b/functional_tests/single.py @@ -25,6 +25,13 @@ class FunctionalTests(unittest.TestCase): def test_length(self): self.assertEqual(len(self.nd2), 1) + def test_actual_length(self): + count = 0 + for image in self.nd2: + if image is not None: + count += 1 + self.assertEqual(len(self.nd2), count) + def test_frames(self): self.assertEqual(len(self.nd2.frames), 1) diff --git a/nd2reader/driver/v3.py b/nd2reader/driver/v3.py index 29746ae..8c00d4d 100644 --- a/nd2reader/driver/v3.py +++ b/nd2reader/driver/v3.py @@ -130,7 +130,7 @@ class V3Driver(object): :raises: NoImageError """ - chunk = self._label_map[six.b("ImageDataSeq|%d!" % image_group_number)] + chunk = self._label_map.get_image_data_location(image_group_number) data = read_chunk(self._file_handle, chunk) # All images in the same image group share the same timestamp! So if you have complicated image data, # your timestamps may not be entirely accurate. Practically speaking though, they'll only be off by a few diff --git a/nd2reader/model/label.py b/nd2reader/model/label.py index daa6a16..a3ebd80 100644 --- a/nd2reader/model/label.py +++ b/nd2reader/model/label.py @@ -8,6 +8,7 @@ class LabelMap(object): """ def __init__(self, raw_binary_data): self._data = raw_binary_data + self._image_data = {} def _get_location(self, label): try: @@ -33,15 +34,14 @@ class LabelMap(object): # there is always only one of these, even though it has a pipe followed by a zero, which is how they do indexes return self._get_location(six.b("ImageMetadataSeqLV|0!")) - @property - def image_data(self): - image_data = {} - regex = re.compile(six.b("""ImageDataSeq\|(\d+)!""")) - for match in regex.finditer(self._data): - if match: - location = self._parse_data_location(match.end()) - image_data[int(match.group(1))] = location - return image_data + def get_image_data_location(self, index): + if not self._image_data: + regex = re.compile(six.b("""ImageDataSeq\|(\d+)!""")) + for match in regex.finditer(self._data): + if match: + location = self._parse_data_location(match.end()) + self._image_data[int(match.group(1))] = location + return self._image_data[index] @property def image_calibration(self): diff --git a/nd2reader/parser/v3.py b/nd2reader/parser/v3.py index 4e11927..4673f39 100644 --- a/nd2reader/parser/v3.py +++ b/nd2reader/parser/v3.py @@ -77,8 +77,8 @@ class V3Parser(BaseParser): """ metadata_dict = self._build_metadata_dict() - height = metadata_dict[six.b('ImageAttributes')][six.b('SLxImageAttributes')][six.b('uiHeight')] - width = metadata_dict[six.b('ImageAttributes')][six.b('SLxImageAttributes')][six.b('uiWidth')] + height = metadata_dict['image_attributes'][six.b('SLxImageAttributes')][six.b('uiHeight')] + width = metadata_dict['image_attributes'][six.b('SLxImageAttributes')][six.b('uiWidth')] channels = self._parse_channels(metadata_dict) date = self._parse_date(metadata_dict) fields_of_view = self._parse_fields_of_view(metadata_dict) @@ -95,7 +95,7 @@ class V3Parser(BaseParser): :rtype: datetime.datetime() or None """ - for line in metadata_dict[six.b('ImageTextInfo')][six.b('SLxImageTextInfo')].values(): + for line in metadata_dict['image_text_info'][six.b('SLxImageTextInfo')].values(): line = line.decode("utf8") absolute_start_12 = None absolute_start_24 = None @@ -123,9 +123,9 @@ class V3Parser(BaseParser): """ channels = [] - metadata = metadata_dict[six.b('ImageMetadataSeq')][six.b('SLxPictureMetadata')][six.b('sPicturePlanes')] + metadata = metadata_dict['image_metadata_sequence'][six.b('SLxPictureMetadata')][six.b('sPicturePlanes')] try: - validity = metadata_dict[six.b('ImageMetadata')][six.b('SLxExperiment')][six.b('ppNextLevelEx')][six.b('')][0][six.b('ppNextLevelEx')][six.b('')][0][six.b('pItemValid')] + validity = metadata_dict['image_metadata'][six.b('SLxExperiment')][six.b('ppNextLevelEx')][six.b('')][0][six.b('ppNextLevelEx')][six.b('')][0][six.b('pItemValid')] except KeyError: # If none of the channels have been deleted, there is no validity list, so we just make one validity = [True for _ in metadata] @@ -181,7 +181,7 @@ class V3Parser(BaseParser): :rtype: str """ - for line in metadata_dict[six.b('ImageTextInfo')][six.b('SLxImageTextInfo')].values(): + for line in metadata_dict['image_text_info'][six.b('SLxImageTextInfo')].values(): if six.b("Dimensions:") in line: metadata = line break @@ -221,7 +221,7 @@ class V3Parser(BaseParser): :rtype: int """ - return metadata_dict[six.b('ImageAttributes')][six.b('SLxImageAttributes')][six.b('uiSequenceCount')] + return metadata_dict['image_attributes'][six.b('SLxImageAttributes')][six.b('uiSequenceCount')] def _build_label_map(self): """