Browse Source

updated docs, minor bug fixes, added unit tests

zolfa-add_slices_loading
Jim Rybarski 9 years ago
parent
commit
6b859bd7ba
11 changed files with 84 additions and 17 deletions
  1. +1
    -0
      Makefile
  2. +9
    -4
      nd2reader/driver/v3.py
  3. +13
    -0
      nd2reader/exc.py
  4. +4
    -3
      nd2reader/model/image.py
  5. +12
    -0
      nd2reader/model/metadata.py
  6. +0
    -0
      nd2reader/parser/v2.py
  7. +2
    -2
      nd2reader/version.py
  8. +0
    -7
      tests/driver/driver.py
  9. +1
    -1
      tests/driver/version.py
  10. +0
    -0
      tests/model/__init__.py
  11. +42
    -0
      tests/model/image.py

+ 1
- 0
Makefile View File

@ -24,4 +24,5 @@ py3:
test: build test: build
docker run --rm -it jimrybarski/nd2reader python3.4 /opt/nd2reader/tests.py docker run --rm -it jimrybarski/nd2reader python3.4 /opt/nd2reader/tests.py
docker run --rm -it jimrybarski/nd2reader python2.7 /opt/nd2reader/tests.py

+ 9
- 4
nd2reader/driver/v3.py View File

@ -6,6 +6,7 @@ import struct
import six import six
from nd2reader.model.image import Image from nd2reader.model.image import Image
from nd2reader.common.v3 import read_chunk from nd2reader.common.v3 import read_chunk
from nd2reader.exc import NoImageError
class V3Driver(object): class V3Driver(object):
@ -47,9 +48,13 @@ class V3Driver(object):
z_level = self._calculate_z_level(index) z_level = self._calculate_z_level(index)
image_group_number = int(index / len(self._metadata.channels)) image_group_number = int(index / len(self._metadata.channels))
frame_number = self._calculate_frame_number(image_group_number, fov, z_level) frame_number = self._calculate_frame_number(image_group_number, fov, z_level)
timestamp, image = self._get_raw_image_data(image_group_number, channel_offset, self._metadata.height, self._metadata.width)
image.add_params(timestamp, frame_number, fov, channel, z_level)
return image
try:
timestamp, image = self._get_raw_image_data(image_group_number, channel_offset, self._metadata.height, self._metadata.width)
except NoImageError:
return None
else:
image.add_params(timestamp, frame_number, fov, channel, z_level)
return image
@property @property
def _channel_offset(self): def _channel_offset(self):
@ -95,4 +100,4 @@ class V3Driver(object):
# them every cycle. # them every cycle.
if np.any(image_data): if np.any(image_data):
return timestamp, Image(image_data) return timestamp, Image(image_data)
return None
raise NoImageError

+ 13
- 0
nd2reader/exc.py View File

@ -1,2 +1,15 @@
class InvalidVersionError(Exception): class InvalidVersionError(Exception):
"""
We don't know how to parse the version of ND2 that we were given.
"""
pass
class NoImageError(Exception):
"""
Some apparent images in ND2s are just completely blank placeholders. These are used when the number of images per
cycle are unequal (e.g. if you take fluorescent images every 2 minutes, and bright field images every minute).
"""
pass pass

+ 4
- 3
nd2reader/model/image.py View File

@ -19,10 +19,11 @@ class Image(np.ndarray):
""" """
A wrapper around the raw pixel data of an image. A wrapper around the raw pixel data of an image.
:param timestamp: The frame number relative to the .
:type timestamp: int
:param timestamp: The number of milliseconds after the beginning of the acquisition that this image was taken. :param timestamp: The number of milliseconds after the beginning of the acquisition that this image was taken.
:type timestamp: int
:type timestamp: float
:param frame_number: The order in which this image was taken, with images of different channels/z-levels
at the same field of view treated as being in the same frame.
:type frame_number: int
:param field_of_view: The label for the place in the XY-plane where this image was taken. :param field_of_view: The label for the place in the XY-plane where this image was taken.
:type field_of_view: int :type field_of_view: int
:param channel: The name of the color of this image :param channel: The name of the color of this image


+ 12
- 0
nd2reader/model/metadata.py View File

@ -12,10 +12,22 @@ class Metadata(object):
@property @property
def height(self): def height(self):
"""
The image height in pixels.
:rtype: int
"""
return self._height return self._height
@property @property
def width(self): def width(self):
"""
The image width in pixels.
:rtype: int
"""
return self._width return self._width
@property @property


+ 0
- 0
nd2reader/parser/v2.py View File


+ 2
- 2
nd2reader/version.py View File

@ -6,8 +6,8 @@ def get_version(fh):
""" """
Determines what version the ND2 is. Determines what version the ND2 is.
:param filename: the path (absolute or relative) to the ND2
:type filename: str
:param fh: an open file handle to the ND2
:type fh: file
""" """
# the first 16 bytes seem to have no meaning, so we skip them # the first 16 bytes seem to have no meaning, so we skip them


+ 0
- 7
tests/driver/driver.py View File

@ -1,7 +0,0 @@
import unittest
from nd2reader.driver import get_driver
class TestDriver(unittest.TestCase):
def test_get_driver(self):
pass

+ 1
- 1
tests/driver/version.py View File

@ -1,5 +1,5 @@
import unittest import unittest
from nd2reader.driver.version import parse_version
from nd2reader.version import parse_version
class VersionTests(unittest.TestCase): class VersionTests(unittest.TestCase):


nd2reader/driver/v2.py → tests/model/__init__.py View File


+ 42
- 0
tests/model/image.py View File

@ -0,0 +1,42 @@
from nd2reader.model.image import Image
import numpy as np
import unittest
class ImageTests(unittest.TestCase):
"""
Basically just tests that the Image API works and that Images act as Numpy arrays. There's very little going on
here other than simply storing data.
"""
def setUp(self):
array = np.array([[0, 1, 254],
[45, 12, 9],
[12, 12, 99]])
self.image = Image(array)
self.image.add_params(1200.314, 17, 2, 'GFP', 1)
def test_size(self):
self.assertEqual(self.image.height, 3)
self.assertEqual(self.image.width, 3)
def test_timestamp(self):
self.assertEqual(self.image.timestamp, 1.200314)
def test_frame_number(self):
self.assertEqual(self.image.frame_number, 17)
def test_fov(self):
self.assertEqual(self.image.field_of_view, 2)
def test_channel(self):
self.assertEqual(self.image.channel, 'GFP')
def test_z_level(self):
self.assertEqual(self.image.z_level, 1)
def test_slice(self):
subimage = self.image[:2, :2]
expected = np.array([[0, 1],
[45, 12]])
self.assertTrue(np.array_equal(subimage, expected))

Loading…
Cancel
Save