Spaces:
Runtime error
Runtime error
| 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 |