Source code for RRtoolbox.lib.arrayops.mask

# -*- coding: utf-8 -*-
"""
    This module contains all basic masking and pre-processing (as in segmenting phase) methods
"""
from __future__ import division
from __future__ import absolute_import
from builtins import range


import cv2
import numpy as np
from .basic import (findminima, im2shapeFormat, getOtsuThresh, findContours,
                    isnumpy)
from .filters import smooth


[docs]def brightness(img): """ get brightness from an image :param img: BGR or gray image :return: """ # LESS BRIGHT http://alienryderflex.com/hsp.html #b,g,r = cv2.split(img.astype("float")) # return np.sqrt( .299*(b**2) + .587*(g**2) + .114*(r**2)).astype("uint8") # Normal gray return im2shapeFormat(img, img.shape[:2])
# HSV # return cv2.cvtColor(img,cv2.COLOR_BGR2HSV)[:,:,2]
[docs]def background(gray, mask=None, iterations=3): """ get the background mask of a gray image. (this it the inverted of :func:`foreground`) :param gray: gray image :param mask: (None) input mask to process gray :param iterations: (3) number of iterations to detect background with otsu threshold. :return: output mask """ # gray = works with any gray image if mask is None: mask = np.ones_like(gray) for i in range(iterations): hist, bins = np.histogram( gray[mask.astype(bool)].flatten(), 256, [0, 256]) thresh = getOtsuThresh(hist) cv2.threshold(gray, thresh, 1, cv2.THRESH_BINARY_INV, dst=mask) return mask
[docs]def foreground(gray, mask=None, iterations=3): """ get the foreground mask of a gray image. (this it the inverted of :func:`background`) :param gray: gray image :param mask: (None) input mask to process gray :param iterations: (3) number of iterations to detect foreground with otsu threshold. :return: output mask """ return 1 - background(gray, mask, iterations)
[docs]def multiple_otsu(gray, mask=None, flag=cv2.THRESH_BINARY, iterations=1): """ get the mask of a gray image applying Otsu threshold. :param gray: gray image :param mask: (None) input mask to process gray :param iterations: (1) number of iterations to detect Otsu threshold. :return: thresh, mask """ # get mask if mask is None and flag == cv2.THRESH_BINARY_INV: mask = np.ones_like(gray) if mask is None and flag == cv2.THRESH_BINARY: mask = np.zeros_like(gray) if iterations > 0: for i in range(iterations): hist, bins = np.histogram( gray[mask.astype(bool)].flatten(), 256, [0, 256]) thresh = getOtsuThresh(hist) cv2.threshold(gray, thresh, 1, flag, dst=mask) return thresh, mask else: raise Exception( "iterations must be greater than 0 and got {}".format(iterations))
[docs]def hist_cdf(img, window_len=0, window='hanning'): """ Get image histogram and the normalized cumulative distribution function. :param img: imaeg :param window_len: :param window: :return: histogram (int), normalized cdf (float) """ hist, bins = np.histogram(img.flatten(), 256, [0, 256]) if window_len: hist = smooth(hist, window_len, window) # if window_len=0 => no filter cdf = hist.cumsum() # cumulative distribution function cdf_normalized = cdf * (hist.max()) / cdf.max() # normalized cdf return hist, cdf_normalized
[docs]def thresh_hist(gray): """ Get best possible thresh to threshold object from the gray image. :param gray: gray image. :return: thresh value. """ hist, cdf = hist_cdf(gray, 11) th1 = 130 # np.min(np.where(cdf.max()*0.2<=cdf)) th2 = np.max(np.where(hist.max() == hist)) th3 = np.min(np.where(np.mean(cdf) <= cdf)) th4 = findminima(hist, np.mean([th1, th2, th3])) return th4
[docs]def threshold_opening(src, thresh, maxval, type): """ Eliminate small objects from threshold. :param src: :param thresh: :param maxval: :param type: :return: """ kz = np.mean(src.shape) / 50 # proportion to src kernel = np.ones((kz, kz), np.uint8) # kernel of ones retval, th = cv2.threshold(src, thresh, maxval, type) # apply threshold th = cv2.morphologyEx(th, cv2.MORPH_OPEN, kernel) # apply opening return th
[docs]def biggestCntData(contours): """ Gets index and area of biggest contour. :param contours: :return: index, area """ index, maxarea = 0, 0 for i in range(len(contours)): area = cv2.contourArea(contours[i]) if area > maxarea: index, maxarea = i, area return index, maxarea
[docs]def biggestCnt(contours): """ Filters contours to get biggest contour. :param contours: :return: cnt """ if contours: return contours[biggestCntData(contours)[0]] # return empty array if there is not anything to choose return np.array([])
[docs]def cnt_hist(gray): """ Mask of a ellipse enclosing retina using histogram threshold. :param gray: gray image :param invert: invert mask :return: mask """ thresh = thresh_hist(gray) # obtain optimum threshold rough_mask = threshold_opening(gray, thresh, 1, 0) contours, hierarchy = findContours( rough_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) return biggestCnt(contours)
[docs]def mask_watershed(BGR, GRAY=None): """ Get retinal mask with watershed method. :param BGR: :param GRAY: :return: mask """ if GRAY is None: GRAY = brightness(BGR) # get image brightness thresh, sure_bg = cv2.threshold( GRAY, 0, 1, cv2.THRESH_BINARY + cv2.THRESH_OTSU) # obtain over threshold thresh, sure_fg = cv2.threshold(GRAY, thresh + 10, 1, cv2.THRESH_BINARY) markers = np.ones_like(GRAY, np.int32) # make background markers markers[sure_bg == 1] = 0 # mark unknown markers markers[sure_fg == 1] = 2 # mark sure object markers cv2.watershed(BGR, markers) # get watershed on markers retval, mask = cv2.threshold(markers.astype( "uint8"), 1, 1, cv2.THRESH_BINARY) # get binary image of contour return mask
[docs]def thresh_biggestCnt(thresh): """ From threshold obtain biggest contour. :param thresh: binary image :return: cnt """ # http://docs.opencv.org/master/d9/d8b/tutorial_py_contours_hierarchy.html#gsc.tab=0 contours, hierarchy = findContours( thresh.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) return biggestCnt(contours)
[docs]def gethull(contours): """ Get convex hull. :param contours: contours or mask array :return: cnt """ if isnumpy(contours): contours, _ = findContours( contours.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) allcontours = np.vstack(contours[i] for i in np.arange(len(contours))) return cv2.convexHull(allcontours)