From 89ddce3a7bf3acc049eed2155f91723d7a4309a4 Mon Sep 17 00:00:00 2001 From: Jim Rybarski Date: Sun, 31 May 2015 04:43:06 +0000 Subject: [PATCH] resolves #39 --- nd2reader/__init__.py | 90 ++++++++++++++++++------------------------- nd2reader/parser.py | 2 +- setup.py | 2 +- 3 files changed, 39 insertions(+), 55 deletions(-) diff --git a/nd2reader/__init__.py b/nd2reader/__init__.py index 0f40628..5166932 100644 --- a/nd2reader/__init__.py +++ b/nd2reader/__init__.py @@ -34,64 +34,20 @@ class Nd2(Nd2Parser): """ return self._image_count * self._channel_count - @property - def height(self): - """ - :return: height of each image, in pixels - :rtype: int - - """ - return self.metadata[six.b('ImageAttributes')][six.b('SLxImageAttributes')][six.b('uiHeight')] - - @property - def width(self): - """ - :return: width of each image, in pixels - :rtype: int - - """ - return self.metadata[six.b('ImageAttributes')][six.b('SLxImageAttributes')][six.b('uiWidth')] - - def __iter__(self): - """ - Iterates over every image, in the order they were taken. - - :return: model.Image() - - """ - for i in range(self._image_count): - for fov in self._fields_of_view: - for z_level in self._z_levels: - for channel_name in self._channels: - image = self.get_image(i, fov, channel_name, z_level) - if image is not None: - yield image - - def __getitem__(self, item): - if isinstance(item, int): + def __getitem__(self, frame_number): + if isinstance(frame_number, int): try: - channel_offset = item % len(self.channels) - fov = self._calculate_field_of_view(item) - channel = self._calculate_channel(item) - z_level = self._calculate_z_level(item) - item -= channel_offset - item /= len(self.channels) - timestamp, raw_image_data = self._get_raw_image_data(item, channel_offset) + channel_offset = frame_number % len(self.channels) + fov = self._calculate_field_of_view(frame_number) + channel = self._calculate_channel(frame_number) + z_level = self._calculate_z_level(frame_number) + timestamp, raw_image_data = self._get_raw_image_data(frame_number, channel_offset) image = Image(timestamp, raw_image_data, fov, channel, z_level, self.height, self.width) - except TypeError: + except (TypeError, ValueError): return None else: return image - def _calculate_field_of_view(self, frame_number): - return int((frame_number - (frame_number % (len(self.z_levels) * len(self.channels)))) / (len(self.z_levels) * len(self.channels))) - - def _calculate_channel(self, frame_number): - return self._channels[frame_number % len(self.channels)] - - def _calculate_z_level(self, frame_number): - return self.z_levels[int(((frame_number - (frame_number % len(self.channels))) / 2) % len(self.z_levels))] - @property def image_sets(self): """ @@ -103,7 +59,7 @@ class Nd2(Nd2Parser): :return: model.ImageSet() """ - for time_index in self._time_indexes: + for time_index in self.time_indexes: image_set = ImageSet() for fov in self._fields_of_view: for channel_name in self._channels: @@ -113,6 +69,34 @@ class Nd2(Nd2Parser): image_set.add(image) yield image_set + @property + def height(self): + """ + :return: height of each image, in pixels + :rtype: int + + """ + return self.metadata[six.b('ImageAttributes')][six.b('SLxImageAttributes')][six.b('uiHeight')] + + @property + def width(self): + """ + :return: width of each image, in pixels + :rtype: int + + """ + return self.metadata[six.b('ImageAttributes')][six.b('SLxImageAttributes')][six.b('uiWidth')] + + def _calculate_field_of_view(self, frame_number): + images_per_cycle = len(self.z_levels) * len(self.channels) + return int((frame_number - (frame_number % images_per_cycle)) / images_per_cycle) % len(self.fields_of_view) + + def _calculate_channel(self, frame_number): + return self._channels[frame_number % len(self.channels)] + + def _calculate_z_level(self, frame_number): + return self.z_levels[int(((frame_number - (frame_number % len(self.channels))) / len(self.channels)) % len(self.z_levels))] + def get_image(self, time_index, field_of_view, channel_name, z_level): """ Returns an Image if data exists for the given parameters, otherwise returns None. In general, you should avoid diff --git a/nd2reader/parser.py b/nd2reader/parser.py index 9566f21..5aabcaa 100644 --- a/nd2reader/parser.py +++ b/nd2reader/parser.py @@ -63,7 +63,7 @@ class Nd2Parser(object): # The images for the various channels are interleaved within the same array. For example, the second image # of a four image group will be composed of bytes 2, 6, 10, etc. If you understand why someone would design # a data structure that way, please send the author of this library a message. - image_data = image_group_data[image_data_start::self._channel_count] + image_data = image_group_data[image_data_start::len(self.channels)] # Skip images that are all zeros! This is important, since NIS Elements creates blank "gap" images if you # don't have the same number of images each cycle. We discovered this because we only took GFP images every # other cycle to reduce phototoxicity, but NIS Elements still allocated memory as if we were going to take diff --git a/setup.py b/setup.py index d250eec..ee88e1d 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from distutils.core import setup -VERSION = "1.0.1" +VERSION = "1.1.0" setup( name="nd2reader",