|
@ -1,16 +1,14 @@ |
|
|
# -*- coding: utf-8 -*- |
|
|
# -*- coding: utf-8 -*- |
|
|
|
|
|
|
|
|
import logging |
|
|
|
|
|
from nd2reader.model import Image, ImageSet |
|
|
from nd2reader.model import Image, ImageSet |
|
|
from nd2reader.parser import Nd2Parser |
|
|
from nd2reader.parser import Nd2Parser |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log = logging.getLogger(__name__) |
|
|
|
|
|
log.addHandler(logging.StreamHandler()) |
|
|
|
|
|
log.setLevel(logging.WARNING) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Nd2(Nd2Parser): |
|
|
class Nd2(Nd2Parser): |
|
|
|
|
|
""" |
|
|
|
|
|
Allows easy access to NIS Elements .nd2 image files. |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
def __init__(self, filename): |
|
|
def __init__(self, filename): |
|
|
super(Nd2, self).__init__(filename) |
|
|
super(Nd2, self).__init__(filename) |
|
|
self._filename = filename |
|
|
self._filename = filename |
|
@ -25,7 +23,31 @@ class Nd2(Nd2Parser): |
|
|
"Z-Levels: %s" % self._z_level_count |
|
|
"Z-Levels: %s" % self._z_level_count |
|
|
]) |
|
|
]) |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
def height(self): |
|
|
|
|
|
""" |
|
|
|
|
|
:return: height of each image, in pixels |
|
|
|
|
|
:rtype: int |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
return self.metadata['ImageAttributes']['SLxImageAttributes']['uiHeight'] |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
def width(self): |
|
|
|
|
|
""" |
|
|
|
|
|
:return: width of each image, in pixels |
|
|
|
|
|
:rtype: int |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
return self.metadata['ImageAttributes']['SLxImageAttributes']['uiWidth'] |
|
|
|
|
|
|
|
|
def __iter__(self): |
|
|
def __iter__(self): |
|
|
|
|
|
""" |
|
|
|
|
|
Iterates over every image, in the order they were taken. |
|
|
|
|
|
|
|
|
|
|
|
:return: model.Image() |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
for i in range(self._image_count): |
|
|
for i in range(self._image_count): |
|
|
for fov in range(self._field_of_view_count): |
|
|
for fov in range(self._field_of_view_count): |
|
|
for z_level in range(self._z_level_count): |
|
|
for z_level in range(self._z_level_count): |
|
@ -36,6 +58,15 @@ class Nd2(Nd2Parser): |
|
|
|
|
|
|
|
|
@property |
|
|
@property |
|
|
def image_sets(self): |
|
|
def image_sets(self): |
|
|
|
|
|
""" |
|
|
|
|
|
Iterates over groups of related images. This is useful if your ND2 contains multiple fields of view. |
|
|
|
|
|
A typical use case might be that you have, say, four areas of interest that you're monitoring, and every |
|
|
|
|
|
minute you take a bright field and GFP image of each one. For each cycle, this method would produce four |
|
|
|
|
|
ImageSet objects, each containing one bright field and one GFP image. |
|
|
|
|
|
|
|
|
|
|
|
:return: model.ImageSet() |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
for time_index in xrange(self._time_index_count): |
|
|
for time_index in xrange(self._time_index_count): |
|
|
image_set = ImageSet() |
|
|
image_set = ImageSet() |
|
|
for fov in range(self._field_of_view_count): |
|
|
for fov in range(self._field_of_view_count): |
|
@ -46,28 +77,28 @@ class Nd2(Nd2Parser): |
|
|
image_set.add(image) |
|
|
image_set.add(image) |
|
|
yield image_set |
|
|
yield image_set |
|
|
|
|
|
|
|
|
def get_image(self, time_index, fov, channel_name, z_level): |
|
|
|
|
|
image_set_number = self._calculate_image_set_number(time_index, fov, z_level) |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
using this method unless you're very familiar with the structure of ND2 files. If you have a use case that |
|
|
|
|
|
cannot be met by the `__iter__` or `image_sets` methods above, please create an issue on Github. |
|
|
|
|
|
|
|
|
|
|
|
:param time_index: the frame number |
|
|
|
|
|
:type time_index: int |
|
|
|
|
|
:param field_of_view: the label for the place in the XY-plane where this image was taken. |
|
|
|
|
|
:type field_of_view: int |
|
|
|
|
|
:param channel_name: the name of the color of this image |
|
|
|
|
|
:type channel_name: str |
|
|
|
|
|
:param z_level: the label for the location in the Z-plane where this image was taken. |
|
|
|
|
|
:type z_level: int |
|
|
|
|
|
:rtype: nd2reader.model.Image() or None |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
image_set_number = self._calculate_image_set_number(time_index, field_of_view, z_level) |
|
|
try: |
|
|
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_set_number, self._channel_offset[channel_name]) |
|
|
image = Image(timestamp, raw_image_data, fov, channel_name, z_level, self.height, self.width) |
|
|
|
|
|
|
|
|
image = Image(timestamp, raw_image_data, field_of_view, channel_name, z_level, self.height, self.width) |
|
|
except TypeError: |
|
|
except TypeError: |
|
|
return None |
|
|
return None |
|
|
else: |
|
|
else: |
|
|
return image |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
def height(self): |
|
|
|
|
|
""" |
|
|
|
|
|
:return: height of each image, in pixels |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
return self.metadata['ImageAttributes']['SLxImageAttributes']['uiHeight'] |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
def width(self): |
|
|
|
|
|
""" |
|
|
|
|
|
:return: width of each image, in pixels |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
return self.metadata['ImageAttributes']['SLxImageAttributes']['uiWidth'] |
|
|
|
|
|
|
|
|
return image |