Exemple #1
0
    def get_image(self, index):
        """
        Creates an Image object and adds its metadata, based on the index (which is simply the order in which the image
        was acquired). May return None if the ND2 contains multiple channels and not all were taken in each cycle (for
        example, if you take bright field images every minute, and GFP images every five minutes, there will be some
        indexes that do not contain an image. The reason for this is complicated, but suffice it to say that we hope to
        eliminate this possibility in future releases. For now, you'll need to check if your image is None if you're
        doing anything out of the ordinary.

        Args:
            index(int): the index (which is simply the order in which the image was acquired)

        Returns:
            Frame: the image

        """
        field_of_view, channel, z_level = self.calculate_image_properties(index)
        channel_offset = index % len(self.metadata["channels"])
        image_group_number = int(index / len(self.metadata["channels"]))
        frame_number = self._calculate_frame_number(image_group_number, field_of_view, z_level)
        try:
            timestamp, image = self._get_raw_image_data(image_group_number, channel_offset, self.metadata["height"],
                                                        self.metadata["width"])
        except (TypeError):
            return Frame([], frame_no=frame_number, metadata=self._get_frame_metadata())
        else:
            return Frame(image, frame_no=frame_number, metadata=self._get_frame_metadata())
Exemple #2
0
    def get_image_by_attributes(self, frame_number, field_of_view, channel, z_level, height, width):
        """Gets an image based on its attributes alone

        Args:
            frame_number: the frame number
            field_of_view: the field of view
            channel_name: the color channel name
            z_level: the z level
            height: the height of the image
            width: the width of the image

        Returns:
            Frame: the requested image

        """
        frame_number = 0 if frame_number is None else frame_number
        field_of_view = 0 if field_of_view is None else field_of_view
        channel = 0 if channel is None else channel
        z_level = 0 if z_level is None else z_level

        image_group_number = self._calculate_image_group_number(frame_number, field_of_view, z_level)
        try:
            timestamp, raw_image_data = self._get_raw_image_data(image_group_number, channel,
                                                                 height, width)
        except (TypeError):
            return Frame([], frame_no=frame_number, metadata=self._get_frame_metadata())
        else:
            return Frame(raw_image_data, frame_no=frame_number, metadata=self._get_frame_metadata())
Exemple #3
0
    def _get_raw_image_data(self, image_group_number, channel_offset, height, width):
        """Reads the raw bytes and the timestamp of an image.

        Args:
            image_group_number: the image group number (see _calculate_image_group_number)
            channel_offset: the number of the color channel
            height: the height of the image
            width: the width of the image

        Returns:

        """
        chunk = self._label_map.get_image_data_location(image_group_number)
        data = read_chunk(self._fh, chunk)

        # All images in the same image group share the same timestamp! So if you have complicated image data,
        # your timestamps may not be entirely accurate. Practically speaking though, they'll only be off by a few
        # seconds unless you're doing something super weird.
        timestamp = struct.unpack("d", data[:8])[0]
        image_group_data = array.array("H", data)
        image_data_start = 4 + channel_offset

        # 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.
        number_of_true_channels = int(len(image_group_data[4:]) / (height * width))
        try:
            image_data = np.reshape(image_group_data[image_data_start::number_of_true_channels], (height, width))
        except ValueError:
            image_data = np.reshape(image_group_data[image_data_start::number_of_true_channels], (height, int(round(len(image_group_data[image_data_start::number_of_true_channels])/height))))

        # 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
        # them every cycle.
        if np.any(image_data):
            return timestamp, Frame(image_data, metadata=self._get_frame_metadata())

        # If a blank "gap" image is encountered, generate an array of corresponding height and width to avoid 
        # errors with ND2-files with missing frames. Array is filled with nan to reflect that data is missing. 
        else:
            empty_frame = np.full((height, width), np.nan)
            warnings.warn('ND2 file contains gap frames which are represented by np.nan-filled arrays; to convert to zeros use e.g. np.nan_to_num(array)')
            return timestamp, Frame(empty_frame, metadata=self._get_frame_metadata())  
Exemple #4
0
    def _get_raw_image_data(self, image_group_number, channel_offset, height,
                            width):
        """Reads the raw bytes and the timestamp of an image.

        Args:
            image_group_number: the image group number (see _calculate_image_group_number)
            channel_offset: the number of the color channel
            height: the height of the image
            width: the width of the image

        Returns:

        """
        chunk = self._label_map.get_image_data_location(image_group_number)
        data = read_chunk(self._fh, chunk)

        # All images in the same image group share the same timestamp! So if you have complicated image data,
        # your timestamps may not be entirely accurate. Practically speaking though, they'll only be off by a few
        # seconds unless you're doing something super weird.
        timestamp = struct.unpack("d", data[:8])[0]
        image_group_data = array.array("H", data)
        image_data_start = 4 + channel_offset

        # 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.
        number_of_true_channels = int(
            (len(image_group_data) - 4) / (height * width))
        image_data = np.reshape(
            image_group_data[image_data_start::number_of_true_channels],
            (height, width))

        # 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
        # them every cycle.
        if np.any(image_data):
            return timestamp, Frame(image_data,
                                    metadata=self._get_frame_metadata())

        raise NoImageError