|
@ -1,6 +1,9 @@ |
|
|
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
|
|
|
|
|
import array |
|
|
import array |
|
|
import numpy as np |
|
|
import numpy as np |
|
|
import struct |
|
|
import struct |
|
|
|
|
|
import re |
|
|
from StringIO import StringIO |
|
|
from StringIO import StringIO |
|
|
from collections import namedtuple |
|
|
from collections import namedtuple |
|
|
import logging |
|
|
import logging |
|
@ -69,12 +72,11 @@ class BaseNd2(object): |
|
|
:rtype: int |
|
|
:rtype: int |
|
|
|
|
|
|
|
|
""" |
|
|
""" |
|
|
return self._image_count / self.field_of_view_count / self.z_level_count |
|
|
|
|
|
|
|
|
return self._reader.time_index_count |
|
|
|
|
|
|
|
|
@property |
|
|
@property |
|
|
def z_level_count(self): |
|
|
def z_level_count(self): |
|
|
# return self._image_count / self._sequence_count |
|
|
|
|
|
return 3 |
|
|
|
|
|
|
|
|
return self._reader.z_level_count |
|
|
|
|
|
|
|
|
@property |
|
|
@property |
|
|
def field_of_view_count(self): |
|
|
def field_of_view_count(self): |
|
@ -85,11 +87,7 @@ class BaseNd2(object): |
|
|
NIS Elements can figure it out, but we haven't found it yet. |
|
|
NIS Elements can figure it out, but we haven't found it yet. |
|
|
|
|
|
|
|
|
""" |
|
|
""" |
|
|
try: |
|
|
|
|
|
valid_fovs = self._metadata['ImageMetadata']['SLxExperiment']['ppNextLevelEx'][''][0]['pItemValid'] |
|
|
|
|
|
except KeyError: |
|
|
|
|
|
valid_fovs = self._metadata['ImageMetadata']['SLxExperiment']['ppNextLevelEx']['']['pItemValid'] |
|
|
|
|
|
return sum(valid_fovs) |
|
|
|
|
|
|
|
|
return self._reader.field_of_view_count |
|
|
|
|
|
|
|
|
@property |
|
|
@property |
|
|
def channel_count(self): |
|
|
def channel_count(self): |
|
@ -124,6 +122,23 @@ class Nd2Reader(object): |
|
|
self._metadata = {} |
|
|
self._metadata = {} |
|
|
self._read_map() |
|
|
self._read_map() |
|
|
self._parse_dict_data() |
|
|
self._parse_dict_data() |
|
|
|
|
|
self.__dimensions = None |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
def _dimensions(self): |
|
|
|
|
|
if self.__dimensions is None: |
|
|
|
|
|
# TODO: Replace this with a single regex |
|
|
|
|
|
for line in self._metadata['ImageTextInfo']['SLxImageTextInfo'].values(): |
|
|
|
|
|
if "Dimensions:" in line: |
|
|
|
|
|
metadata = line |
|
|
|
|
|
break |
|
|
|
|
|
else: |
|
|
|
|
|
raise Exception("Could not parse metadata dimensions!") |
|
|
|
|
|
for line in metadata.split("\r\n"): |
|
|
|
|
|
if line.startswith("Dimensions:"): |
|
|
|
|
|
self.__dimensions = line |
|
|
|
|
|
break |
|
|
|
|
|
return self.__dimensions |
|
|
|
|
|
|
|
|
@property |
|
|
@property |
|
|
def fh(self): |
|
|
def fh(self): |
|
@ -131,9 +146,39 @@ class Nd2Reader(object): |
|
|
self._file_handler = open(self._filename, "rb") |
|
|
self._file_handler = open(self._filename, "rb") |
|
|
return self._file_handler |
|
|
return self._file_handler |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
def time_index_count(self): |
|
|
|
|
|
""" |
|
|
|
|
|
The number of images for a given field of view, channel, and z_level combination. |
|
|
|
|
|
Effectively the number of frames. |
|
|
|
|
|
|
|
|
|
|
|
:rtype: int |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
pattern = r""".*?T'\((\d+)\).*?""" |
|
|
|
|
|
return int(re.match(pattern, self._dimensions).group(1)) |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
def z_level_count(self): |
|
|
|
|
|
pattern = r""".*?Z\((\d+)\).*?""" |
|
|
|
|
|
return int(re.match(pattern, self._dimensions).group(1)) |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
def field_of_view_count(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 |
|
|
|
|
|
in the image data, so we have to calculate it. There probably is something somewhere, since |
|
|
|
|
|
NIS Elements can figure it out, but we haven't found it yet. |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
pattern = r""".*?XY\((\d+)\).*?""" |
|
|
|
|
|
return int(re.match(pattern, self._dimensions).group(1)) |
|
|
|
|
|
|
|
|
@property |
|
|
@property |
|
|
def channel_count(self): |
|
|
def channel_count(self): |
|
|
return self._metadata['ImageAttributes']["SLxImageAttributes"]["uiComp"] |
|
|
|
|
|
|
|
|
pattern = r""".*?λ\((\d+)\).*?""" |
|
|
|
|
|
return int(re.match(pattern, self._dimensions).group(1)) |
|
|
|
|
|
|
|
|
def get_raw_image_data(self, image_set_number, channel_offset): |
|
|
def get_raw_image_data(self, image_set_number, channel_offset): |
|
|
chunk = self._label_map["ImageDataSeq|%d!" % image_set_number] |
|
|
chunk = self._label_map["ImageDataSeq|%d!" % image_set_number] |
|
|