def bilateral_filter( a_img: ImageImpl, kernel_size: int, sigma_s: float, sigma_r: float ) -> ImageImpl: """ Given an Image instance, apply the bilateral filter kernel_size. :param a_img: Image instance :param kernel_size: kernel size int :param sigma_s: sigma_s value :param sigma_r: sigma_r value :return: transformed image """ img_in = a_img.get_array() if a_img.channels == 1: img_in = img_in[:, :, 0] gaussian = ( lambda r2, sigma: (np.exp(-0.5 * r2 / sigma ** 2) * 3).astype(int) * 1.0 / 3.0 ) # define the window width to be the 3 time the spatial std. dev. to # be sure that most of the spatial kernel is actually captured win_width = int(kernel_size) # initialize the results and sum of weights to very small values for # numerical stability. not strictly necessary but helpful to avoid # wild values with pathological choices of parameters reg_constant = 1e-8 wgt_sum = np.ones(img_in.shape) * reg_constant result = img_in * reg_constant # accumulate the result by circularly shifting the image across the # window in the horizontal and vertical directions. within the inner # loop, calculate the two weights and accumulate the weight sum and # the unnormalized result image for shft_x in range(-win_width, win_width + 1): for shft_y in range(-win_width, win_width + 1): # compute the spatial weight w = gaussian(shft_x ** 2 + shft_y ** 2, sigma_s) # shift by the offsets off = np.roll(img_in, [shft_y, shft_x], axis=[0, 1]) # compute the value weight tw = w * gaussian((off - img_in) ** 2, sigma_r) # accumulate the results result += off * tw wgt_sum += tw # normalize the result and return out = result / wgt_sum dims = len(out.shape) out = np.expand_dims(out, axis=dims) if dims == 2 else out return ImageImpl.from_array(out)
def salt_and_pepper_apply(image: ImageImpl, p0: float, p1=None) -> ImageImpl: if p1 is None: p1 = 1 - p0 mask = np.random.uniform(low=0.0, high=1.0, size=image.array.shape) mask_p0 = np.where(mask > p0, 1.0, 0.0) mask_p1 = np.where(mask < p1, 1.0, 0.0) mask_p1_add = np.where(mask > p1, 1.0, 0.0) result = image.array * mask_p0 result = result * mask_p1 + mask_p1_add * constants.MAX_PIXEL_VALUE return ImageImpl.from_array(result)
def apply_noise(image: ImageImpl, random_generator: Generator, is_additive: bool, threshold: float) -> ImageImpl: noise = random_generator.generate() noise = np.array(noise).reshape(image.array.shape) mask = np.random.uniform(low=0.0, high=1.0, size=image.array.shape) mask = np.where(mask > threshold, 1.0, 0.0) if is_additive: result = image.array + mask * noise else: result = image.array * mask * noise return ImageImpl.from_array(result)
def umbralization_with_two_thresholds(a_img: ImageImpl, high_threshold: float, low_threshold: float) -> ImageImpl: image_array = a_img.get_array() res = np.zeros_like(image_array) weak = np.int32(constants.MAX_PIXEL_VALUE / 2) strong = np.int32(constants.MAX_PIXEL_VALUE) strong_i, strong_j, strong_k = np.where(image_array >= high_threshold) weak_i, weak_j, weak_k = np.where((image_array <= high_threshold) & (image_array >= low_threshold)) res[strong_i, strong_j, strong_k] = strong res[weak_i, weak_j, weak_k] = weak return ImageImpl.from_array(res)
def generate_image_with_border(mask_array: np.ndarray, image: ImageImpl) -> ImageImpl: border_image = np.zeros((image.height, image.width, 3), dtype=np.uint8) image_array = image.get_array() for y in range(0, image.height): for x in range(0, image.width): if mask_array[y, x] == -1 or mask_array[y, x] == 1: border_image[y, x, 0] = np.uint8(0) border_image[y, x, 1] = np.uint8(255) border_image[y, x, 2] = np.uint8(0) else: border_image[y, x, 0] = image_array[y, x, 0] border_image[y, x, 1] = image_array[y, x, 1] border_image[y, x, 2] = image_array[y, x, 2] return ImageImpl.from_array(border_image)
def global_thresholding(image: ImageImpl) -> (ImageImpl, list): img_array = image.get_array() t = [] img_binary = [] for c in range(image.channels): current_t = int(np.mean(img_array[:, :, c])) last_t = 0 while abs(last_t - current_t) >= 0.5: last_t = current_t current_t = _calculate_global_threshold(img_array[:, :, c], last_t) img_binary.append( _array_binarize(img_array[:, :, c], current_t) * constants.MAX_PIXEL_VALUE) t.append(int(current_t)) return ImageImpl.from_array(np.moveaxis(np.array(img_binary), 0, 2)), t
def otsu_thresholding(image: ImageImpl): hists = image.df() img_array = image.get_array() t = [] img_binary = [] for c in range(image.channels): prob = np.array(hists[c]) / len(img_array[:, :, c]) prob_sumcum = np.array(ImageImpl._cdf_hist(hists[c])) / 255 means = _compute_means(prob) global_means = _compute_global_mean(prob) variances = _compute_variance(global_means, means, prob_sumcum) threshold = _get_threshold_from_variance(variances) img_binary.append( _array_binarize(img_array[:, :, c], threshold) * constants.MAX_PIXEL_VALUE) t.append(threshold) return ImageImpl.from_array(np.moveaxis(np.array(img_binary), 0, 2)), t
def suppress_false_maximums2(synthesized_image: ImageImpl, angle: np.ndarray) -> ImageImpl: synthesized_array = synthesized_image.array[..., 0] result = np.zeros_like(synthesized_array) for i in range(1, result.shape[0] - 1): for j in range(1, result.shape[1] - 1): # angle 0 if (0 <= angle[i, j] < 22.5) or (157.5 <= angle[i, j] <= 180): after_pixel = synthesized_array[i, j + 1] before_pixel = synthesized_array[i, j - 1] # angle 45 elif 22.5 <= angle[i, j] < 67.5: after_pixel = synthesized_array[i + 1, j - 1] before_pixel = synthesized_array[i - 1, j + 1] # angle 90 elif 67.5 <= angle[i, j] < 112.5: after_pixel = synthesized_array[i + 1, j] before_pixel = synthesized_array[i - 1, j] # angle 135 elif 112.5 <= angle[i, j] < 157.5: after_pixel = synthesized_array[i - 1, j - 1] before_pixel = synthesized_array[i + 1, j + 1] else: ValueError("Angle not valid") if (synthesized_array[i, j] >= after_pixel and synthesized_array[i, j] >= before_pixel): result[i, j] = synthesized_array[i, j] else: result[i, j] = 0 return ImageImpl.from_array(result[:, :, np.newaxis])