Spaces:
Running
Running
import cv2 as cv | |
import numpy as np | |
from .config import default_config | |
def _choose_closest_colors(image, color_list): | |
""" | |
Converts all colors in an image to the closest color in the color list. | |
Args: | |
image: Image in the RGB color space as a 3D array. | |
color_list: A list of tuples representing RGB values of allowed colors. | |
Returns: | |
A copy of the image with all colors replaced with the closest color in the list. | |
""" | |
width, height, channels = image.shape | |
image_copy = image.reshape((width, height, 1, channels)).copy() | |
color_list = np.array(color_list) | |
num_colors = color_list.shape[0] | |
color_list_broadcastable = color_list.reshape((1, 1, num_colors, 3)) | |
norm_diff = ((image_copy - color_list_broadcastable)**2).sum(axis = -1) | |
indices_color_choices = norm_diff.argmin(axis = -1) | |
simplified_image = color_list[indices_color_choices.flatten(), :].reshape(image.shape) | |
# Adding 1 to indices_color_choices as so the first color is labeled as 1 and not 0. | |
indices_color_choices = indices_color_choices + 1 | |
return simplified_image, indices_color_choices | |
def _kmeans_simplify_image(image, num_colors): | |
Z = image.reshape((-1,3)) | |
# convert to np.float32 | |
Z = np.float32(Z) | |
# define criteria, number of clusters(K) and apply kmeans() | |
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0) | |
K = num_colors | |
ret,label,center=cv.kmeans(Z,K,None,criteria,10,cv.KMEANS_RANDOM_CENTERS) | |
# Now convert back into uint8, and make original image | |
center = np.uint8(center) | |
res = center[label.flatten()] | |
res = res.reshape((image.shape)) | |
simplified_image = res | |
indices_color_choices = label.reshape((image.shape[:2])) + 1 | |
color_list = center | |
return simplified_image, indices_color_choices, color_list | |
def _denoise_image(image, h, denoise_type, blur_size = None): | |
if denoise_type == "fastNlMeansDenoisingColored": | |
denoised_image = cv.fastNlMeansDenoisingColored( | |
src = image.astype(np.uint8), | |
dst = None, | |
h = h, | |
hColor = h, | |
templateWindowSize = 7, | |
searchWindowSize = 21 | |
) | |
elif denoise_type == "gaussianBlur": | |
kernel = (blur_size, blur_size) | |
denoised_image = cv.GaussianBlur(image, kernel, 0) | |
elif denoise_type == "blur": | |
kernel = (blur_size, blur_size) | |
denoised_image = cv.blur(image, kernel) | |
return denoised_image | |
def downsample_image(image): | |
""" | |
Downsample the image so the max dimension is 1000 pixels. | |
""" | |
max_dim = 1000 | |
width, height = image.shape[:2] | |
if width > height: | |
new_width = max_dim | |
new_height = int(height * (new_width / width)) | |
else: | |
new_height = max_dim | |
new_width = int(width * (new_height / height)) | |
image = cv.resize(image, (new_height, new_width), interpolation = cv.INTER_AREA) | |
return image | |
def simplify_image(image, | |
color_list = None, | |
num_colors = None, | |
config = default_config, | |
): | |
""" | |
Converts all colors in an image to the closest color in the color list. | |
Denoises if required. | |
Args: | |
image: Image in the RGB color space as a 3D array. | |
color_list: A list of tuples representing RGB values of allowed colors. | |
Returns: | |
A copy of the image with all colors replaced with the closest color in the list. | |
""" | |
if config["denoise"] and (config["denoise_order"] == "before_simplify"): | |
image = _denoise_image( | |
image=image, | |
h = config["denoise_h"], | |
denoise_type = config["denoise_type"], | |
blur_size = config["blur_size"], | |
) | |
if color_list is None: | |
# Use kmeans to simplify the image to the specified number of colors. | |
simplified_image, indices_color_choices, color_list = _kmeans_simplify_image(image, num_colors) | |
else: | |
if config["apply_kmeans"]: | |
image, indices_color_choices, color_list_kmeans = _kmeans_simplify_image(image, len(color_list)) | |
simplified_image, indices_color_choices = _choose_closest_colors(image, color_list) | |
if config["denoise"] and (config["denoise_order"] == "after_simplify"): | |
# Denoising after simplifying image as denoising original image need not reduce the | |
# number of colors islands and also removed some key features from the original image. | |
simplified_image = _denoise_image( | |
simplified_image, | |
h = config["denoise_h"], | |
denoise_type = config["denoise_type"], | |
blur_size = config["blur_size"], | |
) | |
# Simplying image again as denoising may have introduced new colors. | |
simplified_image, indices_color_choices = _choose_closest_colors( | |
simplified_image, | |
color_list | |
) | |
return simplified_image, indices_color_choices, color_list |