COCAM / aix /utils.py
cerquide's picture
Moved aix
bf62930
import numpy as np
import gzip
from pathlib import Path
import cv2
import skimage.morphology
import skimage.filters.rank
import skimage.util
from tensorflow.keras import backend as K
import tensorflow as tf
import keras
from aix import logger
import aix.constants as C
def dice_coef(y_true, y_pred, smooth = .0001):
intersection = K.sum(y_true * y_pred, axis = [1, 2, 3])
union = K.sum(y_true, axis = [1, 2, 3]) + K.sum(y_pred, axis = [1, 2, 3])
dice = K.mean((2. * intersection + smooth) / (union + smooth), axis = 0)
return dice
def harden(y, threshold=0.5):
y2 = tf.where(y>threshold,1.,0.)
return y2
@keras.saving.register_keras_serializable(package="aix.utils")
def hardened_dice_coef(y_true, y_pred, smooth = .0001):
y_true2 = harden(y_true)
y_pred2 = harden(y_pred)
return dice_coef(y_true2,y_pred2)
def dice_coef_loss(y_true, y_pred):
loss = - dice_coef(y_true, y_pred)
return loss
def local_entropy(im, kernel_size=5, normalize=True):
kernel=skimage.morphology.disk(kernel_size)
entr_img = skimage.filters.rank.entropy(skimage.util.img_as_ubyte(im), kernel)
if normalize:
max_img = np.max(entr_img)
entr_img = (entr_img*255/max_img).astype(np.uint8)
return entr_img
def calc_dim(contour):
c_0 = [ point[0][0] for point in contour]
c_1 = [ point[0][1] for point in contour]
return (min(c_0), max(c_0), min(c_1), max(c_1))
def calc_size(dim):
return (dim[1] - dim[0]) * (dim[3] - dim[2])
def calc_dist(dim1, dim2):
return None
def extract_roi(img, threshold=135, kernel_size=5, min_fratio=.3, max_sratio=5, filled=True, border=.01):
entr_img = local_entropy(img, kernel_size=kernel_size)
_, mask = cv2.threshold(entr_img, threshold, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contours_d = [calc_dim(c) for c in contours]
contours_sizes = [calc_size(c) for c in contours_d]
contour_indices = np.argsort(contours_sizes)[::-1]
# remove artifacts
fratio = min_fratio
sratio = max_sratio
idx = -1
while fratio<=min_fratio or sratio>=max_sratio:
idx += 1
biggest = contour_indices[idx]
filled_mask = np.zeros(img.shape, dtype=np.uint8)
filled_mask = cv2.fillPoly(filled_mask, [contours[biggest]], 255)
fratio = filled_mask.sum()/255/contours_sizes[biggest]
cdim = contours_d[biggest]
sratio = (cdim[3]-cdim[2])/(cdim[1]-cdim[0])
if sratio<1: sratio = 1 / sratio
#print(fratio, sratio, cdim, filled_mask.sum()//255)
# generating the mask
filled_mask = np.zeros(img.shape, dtype=np.uint8)
extra = ( int(img.shape[0] * border) , int(img.shape[1] * border) )
origin = (max(0, cdim[0]-extra[1]), max(0, cdim[2]-extra[0]))
to = (min(img.shape[1]-1 , cdim[1]+extra[1]), min(img.shape[0]-1 , cdim[3]+extra[0]))
if filled:
filled_mask = cv2.rectangle(filled_mask, origin, to, 255, -1)
else:
filled_mask = cv2.rectangle(filled_mask, origin, to, 255, 2)
return filled_mask, origin, to
def preprocessor(input_img, img_rows, img_cols):
"""
Resize input images to constants sizes
:param input_img: numpy array of images
:return: numpy array of preprocessed images
"""
logger.debug("Preprocessing...")
input_img = np.swapaxes(input_img, 2, 3)
input_img = np.swapaxes(input_img, 1, 2)
logger.debug("Input: " + str(input_img.shape))
output_img = np.ndarray((input_img.shape[0], input_img.shape[1], img_rows, img_cols), dtype = np.uint8)
#print("INPUT")
#print(input_img.shape)
for i in range(input_img.shape[0]):
output_img[i, 0] = cv2.resize(input_img[i, 0], (img_cols, img_rows), interpolation = cv2.INTER_AREA)
#print("OUTPUT")
#print(output_img.shape)
output_img = np.swapaxes(output_img, 1, 2)
output_img = np.swapaxes(output_img, 2, 3)
logger.debug("Output: " + str(output_img.shape))
return output_img
def load_train_data(imgs_path, masks_path):
"""
Load training data from project path
:return: [X_train, y_train] numpy arrays containing the training data and their respective masks.
"""
logger.debug("\nLoading train data ...\n")
X_train = np.load(gzip.open(imgs_path))
y_train = np.load(gzip.open(masks_path))
logger.debug(X_train.shape)
logger.debug(y_train.shape)
X_train = preprocessor(X_train, C.IMG_WIDTH, C.IMG_HEIGHT)
y_train = preprocessor(y_train, C.IMG_WIDTH, C.IMG_HEIGHT)
X_train = X_train.astype('float32')/255
mean = np.mean(X_train) # mean for data centering
std = np.std(X_train) # std for data normalization
X_train -= mean
X_train /= std
y_train = y_train.astype('float32')
return X_train, y_train
def process_data(X, y):
logger.debug("\nLoading train data ...\n")
logger.debug(X.shape)
logger.debug(y.shape)
X = preprocessor(X, C.IMG_WIDTH, C.IMG_HEIGHT)
y = preprocessor(y, C.IMG_WIDTH, C.IMG_HEIGHT)
X = X.astype('float32')
y = y.astype('float32')
return X, y
def load_skin_train_data(imgs_path, masks_path, img_width, img_height):
"""
Load training data from project path
:return: [X_train, y_train] numpy arrays containing the training data and their respective masks.
"""
logger.debug("\nLoading train data ...\n")
X_train = np.load(gzip.open(imgs_path))
y_train = np.load(gzip.open(masks_path))
logger.debug(X_train.shape)
logger.debug(y_train.shape)
X_train = preprocessor(X_train, C.IMG_WIDTH, C.IMG_HEIGHT)
y_train = preprocessor(y_train, C.IMG_WIDTH, C.IMG_HEIGHT)
X_train = X_train.astype('float32')
mean = np.mean(X_train) # mean for data centering
std = np.std(X_train) # std for data normalization
X_train -= mean
X_train /= std
y_train = y_train.astype('float32')
y_train /= 255.
return X_train, y_train