You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
4.3 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. # -*- coding: utf-8 -*-
  2. import collections
  3. import numpy as np
  4. import logging
  5. log = logging.getLogger(__name__)
  6. class Image(object):
  7. def __init__(self, timestamp, raw_array, field_of_view, channel, z_level, height, width):
  8. """
  9. A wrapper around the raw pixel data of an image.
  10. :param timestamp: The number of milliseconds after the beginning of the acquisition that this image was taken.
  11. :type timestamp: int
  12. :param raw_array: The raw sequence of bytes that represents the image.
  13. :type raw_array: array.array()
  14. :param field_of_view: The label for the place in the XY-plane where this image was taken.
  15. :type field_of_view: int
  16. :param channel: The name of the color of this image
  17. :type channel: str
  18. :param z_level: The label for the location in the Z-plane where this image was taken.
  19. :type z_level: int
  20. :param height: The height of the image in pixels.
  21. :type height: int
  22. :param width: The width of the image in pixels.
  23. :type width: int
  24. """
  25. self._timestamp = timestamp
  26. self._raw_data = raw_array
  27. self._field_of_view = field_of_view
  28. self._channel = channel
  29. self._z_level = z_level
  30. self._height = height
  31. self._width = width
  32. self._data = None
  33. def __repr__(self):
  34. return "\n".join(["<ND2 Image>",
  35. "%sx%s (HxW)" % (self._height, self._width),
  36. "Timestamp: %s" % self.timestamp,
  37. "Field of View: %s" % self.field_of_view,
  38. "Channel: %s" % self.channel,
  39. "Z-Level: %s" % self.z_level,
  40. ])
  41. @property
  42. def data(self):
  43. """
  44. The actual image data.
  45. :rtype np.array()
  46. """
  47. if self._data is None:
  48. # The data is just a 1-dimensional array originally.
  49. # We convert it to a 2D image here.
  50. self._data = np.reshape(self._raw_data, (self._height, self._width))
  51. return self._data
  52. @property
  53. def field_of_view(self):
  54. """
  55. Which of the fixed locations this image was taken at.
  56. :rtype int:
  57. """
  58. return self._field_of_view
  59. @property
  60. def timestamp(self):
  61. """
  62. The number of seconds after the beginning of the acquisition that the image was taken. Note that for a given
  63. field of view and z-level offset, if you have images of multiple channels, they will all be given the same
  64. timestamp. No, this doesn't make much sense. But that's how ND2s are structured, so if your experiment depends
  65. on millisecond accuracy, you need to find an alternative imaging system.
  66. :rtype float:
  67. """
  68. return self._timestamp / 1000.0
  69. @property
  70. def channel(self):
  71. """
  72. The name of the filter used to acquire this image. These are user-supplied in NIS Elements.
  73. :rtype str:
  74. """
  75. return self._channel
  76. @property
  77. def z_level(self):
  78. """
  79. The vertical offset of the image. These are simple integers starting from 0, where the 0 is the lowest
  80. z-level and each subsequent level incremented by 1.
  81. For example, if you acquired images at -3 µm, 0 µm, and +3 µm, your z-levels would be:
  82. -3 µm: 0
  83. 0 µm: 1
  84. +3 µm: 2
  85. :rtype int:
  86. """
  87. return self._z_level
  88. class ImageSet(object):
  89. """
  90. A group of images that were taken at roughly the same time.
  91. """
  92. def __init__(self):
  93. self._images = collections.defaultdict(dict)
  94. def __len__(self):
  95. """ The number of images in the image set. """
  96. return sum([len(channel) for channel in self._images.values()])
  97. def __repr__(self):
  98. return "\n".join(["<ND2 Image Set>",
  99. "Image count: %s" % len(self)])
  100. def get(self, channel, z_level=0):
  101. """
  102. Retrieve an image with a given channel and z-level. For most users, z_level will always be 0.
  103. :type channel: str
  104. :type z_level: int
  105. """
  106. return self._images.get(channel).get(z_level)
  107. def add(self, image):
  108. """
  109. Stores an image.
  110. :type image: nd2reader.model.Image()
  111. """
  112. self._images[image.channel][image.z_level] = image