import six import numpy as np class Roi(object): """ A ND2 ROI representation. Coordinates are the center coordinates of the ROI in (x, y, z) order in micron. Sizes are the sizes of the ROI in (x, y, z) order in micron. Shapes are represented by numbers, defined by constants in this class. All these properties can be set for multiple time points (in ms). """ SHAPE_RECTANGLE = 3 SHAPE_CIRCLE = 9 TYPE_BACKGROUND = 2 def __init__(self, raw_roi_dict, metadata): """ :param raw_roi_dict: :param metadata """ self.timepoints = [] self.positions = [] self.sizes = [] self.shape = self.SHAPE_CIRCLE self.type = self.TYPE_BACKGROUND self._img_width_micron = metadata.width * metadata.pixel_microns self._img_height_micron = metadata.height * metadata.pixel_microns self._pixel_microns = metadata.pixel_microns self._extract_vect_anims(raw_roi_dict) def _extract_vect_anims(self, raw_roi_dict): """ Extract the vector animation parameters from the ROI. This includes the position and size at the given timepoints. :param raw_roi_dict: :return: """ number_of_timepoints = raw_roi_dict[six.b('m_vectAnimParams_Size')] for i in range(number_of_timepoints): self._parse_vect_anim(raw_roi_dict[six.b('m_vectAnimParams_%d') % i]) self.shape = raw_roi_dict[six.b('m_sInfo')][six.b('m_uiShapeType')] self.type = raw_roi_dict[six.b('m_sInfo')][six.b('m_uiInterpType')] # convert to NumPy arrays self.timepoints = np.array(self.timepoints, dtype=np.float) self.positions = np.array(self.positions, dtype=np.float) self.sizes = np.array(self.sizes, dtype=np.float) def _parse_vect_anim(self, animation_dict): """ Parses a ROI vector animation object and adds it to the global list of timepoints and positions. :param animation_dict: :return: """ self.timepoints.append(animation_dict[six.b('m_dTimeMs')]) # positions are taken from the center of the image as a fraction of the half width/height of the image position = np.array((0.5 * self._img_width_micron * (1 + animation_dict[six.b('m_dCenterX')]), 0.5 * self._img_height_micron * (1 + animation_dict[six.b('m_dCenterY')]), animation_dict[six.b('m_dCenterZ')])) self.positions.append(position) size_dict = animation_dict[six.b('m_sBoxShape')] # sizes are fractions of the half width/height of the image self.sizes.append((size_dict[six.b('m_dSizeX')] * 0.25 * self._img_width_micron, size_dict[six.b('m_dSizeY')] * 0.25 * self._img_height_micron, size_dict[six.b('m_dSizeZ')])) def is_circle(self): return self.shape == self.SHAPE_CIRCLE def is_rectangle(self): return self.shape == self.SHAPE_RECTANGLE