def has_border_neighbours_without_thresholds(image: ImageImpl, i: int, j: int, four_neighbours: bool): height, width = image.height, image.width image_array = image.get_array()[..., 0] if four_neighbours: increments = [[0, -1], [1, 0], [0, 1], [-1, 0]] else: increments = [ [-1, -1], [0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], ] for k in range(0, len(increments)): new_i = i + increments[k][0] new_j = j + increments[k][1] if (0 <= new_i < width and 0 <= new_j < height and image_array[new_i, new_j] == constants.MAX_PIXEL_VALUE): return True return False
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 get_object_color( mask_array: np.ndarray, image: ImageImpl, top_left_vertex_x: int, top_left_vertex_y: int, bottom_right_vertex_x: int, bottom_right_vertex_y: int, lin: dict, lout: dict, ) -> np.ndarray: color_sum = np.zeros(image.channels) image_array = image.get_array() square_height = (bottom_right_vertex_y - top_left_vertex_y) + 1 square_width = (bottom_right_vertex_x - top_left_vertex_x) + 1 square_size = square_height * square_width for y in range(top_left_vertex_y, bottom_right_vertex_y + 1): for x in range(top_left_vertex_x, bottom_right_vertex_x + 1): mask_array[y, x] = -3 for k in range(0, image.channels): color_sum[k] += image_array[y, x, k] for y in range(top_left_vertex_y, bottom_right_vertex_y + 1): mask_array[y, top_left_vertex_x - 1] = -1 lin[(top_left_vertex_x - 1, y)] = -1 mask_array[y, bottom_right_vertex_x + 1] = -1 lin[(bottom_right_vertex_x + 1, y)] = -1 mask_array[y, top_left_vertex_x - 2] = 1 lout[(top_left_vertex_x - 2, y)] = 1 mask_array[y, bottom_right_vertex_x + 2] = 1 lout[(bottom_right_vertex_x + 2, y)] = 1 for x in range(top_left_vertex_x, bottom_right_vertex_x + 1): mask_array[top_left_vertex_y - 1, x] = -1 lin[(x, top_left_vertex_y - 1)] = -1 mask_array[bottom_right_vertex_y + 1, x] = -1 lin[(x, bottom_right_vertex_y + 1)] = -1 mask_array[top_left_vertex_y - 2, x] = 1 lout[(x, top_left_vertex_y - 2)] = 1 mask_array[bottom_right_vertex_y + 2, x] = 1 lout[(x, bottom_right_vertex_y + 2)] = 1 mask_array[top_left_vertex_y - 1, top_left_vertex_x - 1] = 1 lout[(top_left_vertex_x - 1, top_left_vertex_y - 1)] = 1 mask_array[bottom_right_vertex_y + 1, top_left_vertex_x - 1] = 1 lout[(top_left_vertex_x - 1, bottom_right_vertex_y + 1)] = 1 mask_array[bottom_right_vertex_y + 1, bottom_right_vertex_x + 1] = 1 lout[(bottom_right_vertex_x + 1, bottom_right_vertex_y + 1)] = 1 mask_array[top_left_vertex_y - 1, bottom_right_vertex_x + 1] = 1 lout[(bottom_right_vertex_x + 1, top_left_vertex_y - 1)] = 1 return color_sum / square_size
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 hysteresis( image: ImageImpl, four_neighbours: bool = True, weak: int = int(constants.MAX_PIXEL_VALUE / 2), strong: int = constants.MAX_PIXEL_VALUE, ) -> ImageImpl: height, width = image.height, image.width image_array = image.get_array()[..., 0] border_image = np.array(image_array) for i in range(1, width - 1): for j in range(1, height - 1): if border_image[i, j] == weak: if has_border_neighbours_without_thresholds( image, i, j, four_neighbours): border_image[i, j] = strong else: border_image[i, j] = 0 return ImageImpl(border_image[:, :, np.newaxis])
def susan_detection(a_img: ImageImpl, threshold: int, low_filter: float, high_filter: float, color: int) -> ImageImpl: """ :param a_img: :param kernel_size: :param threshold: :return: """ # circ_kernel = circular_kernel(7) circ_kernel = np.array([ [0, 0, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 0], [1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1], [0, 1, 1, 1, 1, 1, 0], [0, 0, 1, 1, 1, 0, 0], ]) original = ImageImpl(a_img.get_array()) a_img.apply_filter( circ_kernel, lambda m: _calculate_c_for_susan(m, circ_kernel, threshold)) # a_img.array = np.uint8(a_img.array > 0.75) border_img = np.uint8(a_img.array > low_filter) b_img = border_img - np.uint8(a_img.array > high_filter) border_img = np.zeros((border_img.shape[0], border_img.shape[1], 3)) # because we only have 3 channels color = color % 3 border_img[:, :, color] = b_img[:, :, 0] border_img = ImageImpl(border_img) result = border_img.mul_scalar(255) original = original.to_rgb() # result.add_image(original) return original.add(result)