|
|
import cv2 |
|
|
import numpy as np |
|
|
from scipy import ndimage |
|
|
import matplotlib.pyplot as plt |
|
|
|
|
|
from skimage import exposure |
|
|
|
|
|
import tensorflow as tf |
|
|
import tensorflow_addons as tfa |
|
|
|
|
|
|
|
|
IMAGE_SIZE = 224 |
|
|
|
|
|
|
|
|
def acc(y_true, y_pred, threshold=0.5): |
|
|
threshold = tf.cast(threshold, y_pred.dtype) |
|
|
y_pred = tf.cast(y_pred > threshold, y_pred.dtype) |
|
|
return tf.reduce_mean(tf.cast(tf.equal(y_true, y_pred), tf.float32)) |
|
|
|
|
|
def mae(y_true, y_pred): |
|
|
return tf.reduce_mean(tf.abs(y_true-y_pred)) |
|
|
|
|
|
def inv_ssim(y_true, y_pred): |
|
|
return 1 - tf.reduce_mean(tf.image.ssim(y_true, y_pred, 1.0)) |
|
|
|
|
|
def inv_msssim(y_true, y_pred): |
|
|
return 1 - tf.reduce_mean(tf.image.ssim_multiscale(y_true, y_pred, 1.0, filter_size=4)) |
|
|
|
|
|
def inv_msssim_l1(y_true, y_pred, alpha=0.8): |
|
|
return alpha*inv_msssim(y_true, y_pred) + (1-alpha)*mae(y_true, y_pred) |
|
|
|
|
|
def inv_msssim_gaussian_l1(y_true, y_pred, alpha=0.8): |
|
|
l1_diff = tf.abs(y_true-y_pred) |
|
|
gaussian_l1 = tfa.image.gaussian_filter2d(l1_diff, filter_shape=(11, 11), sigma=1.5) |
|
|
return alpha*inv_msssim(y_true, y_pred) + (1-alpha)*gaussian_l1 |
|
|
|
|
|
def psnr(y_true, y_pred): |
|
|
return tf.reduce_mean(tf.image.psnr(y_true, y_pred, 1.0)) |
|
|
|
|
|
|
|
|
def show_image(image, title='Image', cmap_type='gray'): |
|
|
plt.imshow(image, cmap=cmap_type) |
|
|
plt.title(title) |
|
|
plt.axis('off') |
|
|
plt.show() |
|
|
|
|
|
|
|
|
|
|
|
def remove_negative(img): |
|
|
outside = np.mean(img[ : , 0]) |
|
|
inside = np.mean(img[ : , int(IMAGE_SIZE / 2)]) |
|
|
if outside < inside: |
|
|
return img |
|
|
else: |
|
|
return 1 - img |
|
|
|
|
|
|
|
|
def preprocess(img): |
|
|
img = remove_negative(img) |
|
|
|
|
|
img = exposure.equalize_hist(img) |
|
|
img = exposure.equalize_adapthist(img) |
|
|
img = exposure.equalize_hist(img) |
|
|
return img |
|
|
|
|
|
|
|
|
|
|
|
def dilate(mask_img): |
|
|
kernel_size = 2 * 22 + 1 |
|
|
kernel = np.ones((kernel_size, kernel_size), dtype=np.uint8) |
|
|
return ndimage.binary_dilation(mask_img == 0, structure=kernel) |
|
|
|
|
|
|
|
|
def normalize_tuple(value, n, name, allow_zero=False): |
|
|
"""Transforms non-negative/positive integer/integers into an integer tuple. |
|
|
Args: |
|
|
value: The value to validate and convert. Could an int, or any iterable of |
|
|
ints. |
|
|
n: The size of the tuple to be returned. |
|
|
name: The name of the argument being validated, e.g. "strides" or |
|
|
"kernel_size". This is only used to format error messages. |
|
|
allow_zero: Default to False. A ValueError will raised if zero is received |
|
|
and this param is False. |
|
|
Returns: |
|
|
A tuple of n integers. |
|
|
Raises: |
|
|
ValueError: If something else than an int/long or iterable thereof or a |
|
|
negative value is |
|
|
passed. |
|
|
""" |
|
|
error_msg = ( |
|
|
f"The `{name}` argument must be a tuple of {n} " |
|
|
f"integers. Received: {value}" |
|
|
) |
|
|
|
|
|
if isinstance(value, int): |
|
|
value_tuple = (value,) * n |
|
|
else: |
|
|
try: |
|
|
value_tuple = tuple(value) |
|
|
except TypeError: |
|
|
raise ValueError(error_msg) |
|
|
if len(value_tuple) != n: |
|
|
raise ValueError(error_msg) |
|
|
for single_value in value_tuple: |
|
|
try: |
|
|
int(single_value) |
|
|
except (ValueError, TypeError): |
|
|
error_msg += ( |
|
|
f"including element {single_value} of " |
|
|
f"type {type(single_value)}" |
|
|
) |
|
|
raise ValueError(error_msg) |
|
|
|
|
|
if allow_zero: |
|
|
unqualified_values = {v for v in value_tuple if v < 0} |
|
|
req_msg = ">= 0" |
|
|
else: |
|
|
unqualified_values = {v for v in value_tuple if v <= 0} |
|
|
req_msg = "> 0" |
|
|
|
|
|
if unqualified_values: |
|
|
error_msg += ( |
|
|
f" including {unqualified_values}" |
|
|
f" that does not satisfy the requirement `{req_msg}`." |
|
|
) |
|
|
raise ValueError(error_msg) |
|
|
|
|
|
return value_tuple |
|
|
|
|
|
|
|
|
def draw_points(image, points, color=None, random_color=False, same=True, thickness=1): |
|
|
if color is None and not random_color: |
|
|
color = (0, 255, 0) |
|
|
if random_color: |
|
|
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) |
|
|
|
|
|
image = to_color(image) |
|
|
|
|
|
for point in points: |
|
|
if random_color and not same: |
|
|
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) |
|
|
|
|
|
x, y = point |
|
|
image = cv2.circle(image, (x, y), thickness, color, -1) |
|
|
return image |
|
|
|
|
|
|
|
|
def draw_lines(image, pairs, color=None, random_color=False, same=True, thickness=1): |
|
|
image_with_line = to_color(np.copy(image)) |
|
|
|
|
|
if color is None and not random_color: |
|
|
color = (0, 255, 0) |
|
|
if random_color: |
|
|
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) |
|
|
|
|
|
|
|
|
for pair in pairs: |
|
|
|
|
|
if random_color and not same: |
|
|
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) |
|
|
|
|
|
start_point = pair[0] |
|
|
end_point = pair[1] |
|
|
image_with_line = cv2.line(image_with_line, start_point, end_point, color, thickness) |
|
|
image_with_line = cv2.circle(image_with_line, start_point, thickness + 1, color, -1) |
|
|
image_with_line = cv2.circle(image_with_line, end_point, thickness + 1, color, -1) |
|
|
|
|
|
return image_with_line |
|
|
|
|
|
def to_color(image): |
|
|
if len(image.shape) == 3 and image.shape[-1] == 3: |
|
|
return image |
|
|
return cv2.cvtColor(image, cv2.COLOR_GRAY2RGB) |
|
|
|
|
|
|
|
|
def to_gray(image): |
|
|
if len(image.shape) == 3 and image.shape[-1] == 3: |
|
|
return cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) |
|
|
return image |