Jim Rybarski 10 years ago
parent
commit
8733b366d8
2 changed files with 52 additions and 53 deletions
  1. +5
    -5
      nd2reader/__init__.py
  2. +47
    -48
      nd2reader/parser.py

+ 5
- 5
nd2reader/__init__.py View File

@ -73,13 +73,13 @@ class Nd2(Nd2Parser):
return image
def _calculate_field_of_view(self, frame_number):
return (frame_number - (frame_number % (self._channel_count + self._z_level_count))) % self._field_of_view_count
return (frame_number - (frame_number % (len(self.channels) + len(self.z_levels))) % len(self.fields_of_view)
def _calculate_channel(self, frame_number):
pass
return self._channels[frame_number % self._channel_count]
def _calculate_z_level(self, frame_number):
pass
return self._z_levels[]
@property
def image_sets(self):
@ -119,9 +119,9 @@ class Nd2(Nd2Parser):
:rtype: nd2reader.model.Image() or None
"""
image_set_number = self._calculate_image_group_number(time_index, field_of_view, z_level)
image_group_number = self._calculate_image_group_number(time_index, field_of_view, z_level)
try:
timestamp, raw_image_data = self._get_raw_image_data(image_set_number, self._channel_offset[channel_name])
timestamp, raw_image_data = self._get_raw_image_data(image_group_number, self._channel_offset[channel_name])
image = Image(timestamp, raw_image_data, field_of_view, channel_name, z_level, self.height, self.width)
except TypeError:
return None


+ 47
- 48
nd2reader/parser.py View File

@ -21,13 +21,18 @@ class Nd2Parser(object):
def __init__(self, filename):
self._filename = filename
self._fh = None
self._channels = None
self._channel_count = None
self._chunk_map_start_location = None
self._cursor_position = 0
self._dimension_text = None
self._fields_of_view = None
self._label_map = {}
self.metadata = {}
self._read_map()
self._time_indexes = None
self._parse_metadata()
self._z_levels = None
@property
def _file_handle(self):
@ -93,7 +98,7 @@ class Nd2Parser(object):
return self._dimension_text
@property
def _channels(self):
def channels(self):
"""
These are labels created by the NIS Elements user. Typically they may a short description of the filter cube
used (e.g. "bright field", "GFP", etc.)
@ -101,19 +106,21 @@ class Nd2Parser(object):
:rtype: str
"""
metadata = self.metadata['ImageMetadataSeq']['SLxPictureMetadata']['sPicturePlanes']
try:
validity = self.metadata['ImageMetadata']['SLxExperiment']['ppNextLevelEx'][''][0]['ppNextLevelEx'][''][0]['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]
# Channel information is contained in dictionaries with the keys a0, a1...an where the number
# indicates the order in which the channel is stored. So by sorting the dicts alphabetically
# we get the correct order.
for (label, chan), valid in zip(sorted(metadata['sPlaneNew'].items()), validity):
if not valid:
continue
yield chan['sDescription']
if not self._channels:
metadata = self.metadata['ImageMetadataSeq']['SLxPictureMetadata']['sPicturePlanes']
try:
validity = self.metadata['ImageMetadata']['SLxExperiment']['ppNextLevelEx'][''][0]['ppNextLevelEx'][''][0]['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]
# Channel information is contained in dictionaries with the keys a0, a1...an where the number
# indicates the order in which the channel is stored. So by sorting the dicts alphabetically
# we get the correct order.
for (label, chan), valid in zip(sorted(metadata['sPlaneNew'].items()), validity):
if not valid:
continue
self._channels.append(chan['sDescription'])
return self._channels
def _calculate_image_group_number(self, time_index, fov, z_level):
"""
@ -126,7 +133,7 @@ class Nd2Parser(object):
:rtype: int
"""
return time_index * self._field_of_view_count * self._z_level_count + (fov * self._z_level_count + z_level)
return time_index * len(self.fields_of_view) * len(self.z_levels) + (fov * len(self.z_levels) + z_level)
@property
def _channel_offset(self):
@ -167,24 +174,28 @@ class Nd2Parser(object):
return absolute_start_12 if absolute_start_12 else absolute_start_24
raise ValueError("This ND2 has no recorded start time. This is probably a bug.")
def _parse_dimension_text(self, pattern):
try:
count = int(re.match(pattern, self._dimensions).group(1))
except AttributeError:
return [0]
else:
return range(count)
@property
def _channel_count(self):
def channel_count(self):
"""
The number of different channels used, including bright field.
:rtype: int
"""
pattern = r""".*?λ\((\d+)\).*?"""
try:
count = int(re.match(pattern, self._dimensions).group(1))
except AttributeError:
return 1
else:
return count
if self._channel_count is None:
self._channel_count = self._parse_dimension_text(r""".*?λ\((\d+)\).*?""")
return self._channel_count
@property
def _field_of_view_count(self):
def fields_of_view(self):
"""
The metadata contains information about fields of view, but it contains it even if some fields
of view were cropped. We can't find anything that states which fields of view are actually
@ -194,45 +205,33 @@ class Nd2Parser(object):
:rtype: int
"""
pattern = r""".*?XY\((\d+)\).*?"""
try:
count = int(re.match(pattern, self._dimensions).group(1))
except AttributeError:
return 1
else:
return count
if self._fields_of_view is None:
self._fields_of_view = self._parse_dimension_text(r""".*?XY\((\d+)\).*?""")
return self._fields_of_view
@property
def _time_index_count(self):
def time_indexes(self):
"""
The number of cycles.
:rtype: int
"""
pattern = r""".*?T'\((\d+)\).*?"""
try:
count = int(re.match(pattern, self._dimensions).group(1))
except AttributeError:
return 1
else:
return count
if self._time_indexes is None:
self._time_indexes = self._parse_dimension_text(r""".*?T'\((\d+)\).*?""")
return self._time_indexes
@property
def _z_level_count(self):
def z_levels(self):
"""
The number of different levels in the Z-plane.
The different levels in the Z-plane. Just a sequence from 0 to n.
:rtype: int
"""
pattern = r""".*?Z\((\d+)\).*?"""
try:
count = int(re.match(pattern, self._dimensions).group(1))
except AttributeError:
return 1
else:
return count
if self._z_levels is None:
self._z_levels = self._parse_dimension_text(r""".*?Z\((\d+)\).*?""")
return self._z_levels
@property
def _image_count(self):


Loading…
Cancel
Save