Source code for ethoscope.core.roi

import cv2
import numpy as np
from ethoscope.utils.debug import EthoscopeException

__author__ = 'quentin'


[docs]class ROI(object): def __init__(self, polygon, idx, value=None, orientation = None, regions=None): """ Class to define a region of interest(ROI). Internally, ROIs are single polygons. At the moment, they cannot have any holes. The polygon defining the ROI is used to draw a mask to exclude off-target pixels (so cross-ROI info). :param polygon: An array of points :type polygon: :class:`~numpy.ndarray` :param idx: the index of this ROI :type idx: int :param value: an optional value to be save for this ROI (e.g. to define left and right side) :param orientation: Optional orientation Not implemented yet :param regions: Optional sub-regions within the ROI. Not implemented yet """ # TODO if we do not need polygon, we can drop it self._polygon = np.array(polygon) if len(self._polygon.shape) == 2: self._polygon = self._polygon.reshape((self._polygon.shape[0],1,self._polygon.shape[1])) x,y,w,h = cv2.boundingRect(self._polygon) self._mask = np.zeros((h,w), np.uint8) cv2.drawContours(self._mask, [self._polygon], 0, 255,-1,offset=(-x,-y)) self._rectangle = x,y,w,h # todo NOW! sort rois by value. if no values, left to right/ top to bottom! self._idx = idx if value is None: self._value = self._idx else: self._value = value @property def idx(self): """ :return: The index of this ROI :rtype: int """ return self._idx
[docs] def bounding_rect(self): raise NotImplementedError
[docs] def mask(self): """ :return: The mask as a single chanel, `uint8` image. :rtype: :class:`~numpy.ndarray` """ return self._mask
@property def offset(self): """ :return: the x,y offset of the ROI compared to the frame it was build on. :rtype: (int,int) """ x,y,w,h = self._rectangle return x,y @property def polygon(self): """ :return: the internal polygon defining the ROI. :rtype: :class:`~numpy.ndarray` """ return self._polygon @property def longest_axis(self): """ :return: the value of the longest axis (w or h) :rtype: float """ x,y,w,h = self._rectangle return float(max(w, h)) @property def rectangle(self): """ :return: The upright bounding rectangle to the ROI formatted (x,y,w,h). Where x and y are to coordinates of the top left corner :rtype: (int,int,int,int) """ return self._rectangle
[docs] def get_feature_dict(self): """ :return: A dictionary of freatures for this roi. It containes the folowing fields: * "x" * "y" * "w" * "h" * "value" * "idx" :rtype: dict """ x,y,w,h = self._rectangle return {"x":x, "y":y, "w":w, "h":h, "value":self._value, "idx":self.idx }
[docs] def set_value(self, new_val): """ :param new_val: assign a nex value to a ROI """ self._value = new_val
@property def value(self): """ :return: the value of a ROI """ return self._value
[docs] def apply(self,img): """ Cut an image where the ROI is defined. :param img: An image. Typically either one or three channels `uint8`. :type img: :class:`~numpy.ndarray` :return: a tuple containing the resulting cropped image and the associated mask (both have the same dimension). :rtype: (:class:`~numpy.ndarray`, :class:`~numpy.ndarray`) """ x,y,w,h = self._rectangle try: out = img[y : y + h, x : x +w] except: raise EthoscopeException("Error whilst slicing region of interest %s" % str(self.get_feature_dict()), img) if out.shape[0:2] != self._mask.shape: raise EthoscopeException("Error whilst slicing region of interest. Possibly, the region out of the image: %s" % str(self.get_feature_dict()), img ) return out, self._mask