import cv2 import numpy as np import scipy.sparse def mask_from_points(size, points): """ Create a mask of supplied size from supplied points :param size: tuple of output mask size :param points: array of [x, y] points :returns: mask of values 0 and 255 where 255 indicates the convex hull containing the points """ radius = 10 # kernel size kernel = np.ones((radius, radius), np.uint8) mask = np.zeros(size, np.uint8) cv2.fillConvexPoly(mask, cv2.convexHull(points), 255) mask = cv2.erode(mask, kernel) return mask def overlay_image(foreground_image, mask, background_image): """ Overlay foreground image onto the background given a mask :param foreground_image: foreground image points :param mask: [0-255] values in mask :param background_image: background image points :returns: image with foreground where mask > 0 overlaid on background image """ foreground_pixels = mask > 0 background_image[..., :3][foreground_pixels] = foreground_image[..., :3][foreground_pixels] return background_image def apply_mask(img, mask): """ Apply mask to supplied image :param img: max 3 channel image :param mask: [0-255] values in mask :returns: new image with mask applied """ masked_img = np.copy(img) num_channels = 3 for c in range(num_channels): masked_img[..., c] = img[..., c] * (mask / 255) return masked_img def weighted_average(img1, img2, percent=0.5): if percent <= 0: return img2 elif percent >= 1: return img1 else: return cv2.addWeighted(img1, percent, img2, 1-percent, 0) def alpha_feathering(src_img, dest_img, img_mask, blur_radius=15): mask = cv2.blur(img_mask, (blur_radius, blur_radius)) mask = mask / 255.0 result_img = np.empty(src_img.shape, np.uint8) for i in range(3): result_img[..., i] = src_img[..., i] * mask + dest_img[..., i] * (1-mask) return result_img def poisson_blend(img_source, dest_img, img_mask, offset=(0, 0)): # http://opencv.jp/opencv2-x-samples/poisson-blending img_target = np.copy(dest_img) import pyamg # compute regions to be blended region_source = ( max(-offset[0], 0), max(-offset[1], 0), min(img_target.shape[0] - offset[0], img_source.shape[0]), min(img_target.shape[1] - offset[1], img_source.shape[1])) region_target = ( max(offset[0], 0), max(offset[1], 0), min(img_target.shape[0], img_source.shape[0] + offset[0]), min(img_target.shape[1], img_source.shape[1] + offset[1])) region_size = (region_source[2] - region_source[0], region_source[3] - region_source[1]) # clip and normalize mask image img_mask = img_mask[region_source[0]:region_source[2], region_source[1]:region_source[3]] # create coefficient matrix coff_mat = scipy.sparse.identity(np.prod(region_size), format='lil') for y in range(region_size[0]): for x in range(region_size[1]): if img_mask[y, x]: index = x + y * region_size[1] coff_mat[index, index] = 4 if index + 1 < np.prod(region_size): coff_mat[index, index + 1] = -1 if index - 1 >= 0: coff_mat[index, index - 1] = -1 if index + region_size[1] < np.prod(region_size): coff_mat[index, index + region_size[1]] = -1 if index - region_size[1] >= 0: coff_mat[index, index - region_size[1]] = -1 coff_mat = coff_mat.tocsr() # create poisson matrix for b poisson_mat = pyamg.gallery.poisson(img_mask.shape) # for each layer (ex. RGB) for num_layer in range(img_target.shape[2]): # get subimages t = img_target[region_target[0]:region_target[2], region_target[1]:region_target[3], num_layer] s = img_source[region_source[0]:region_source[2], region_source[1]:region_source[3], num_layer] t = t.flatten() s = s.flatten() # create b b = poisson_mat * s for y in range(region_size[0]): for x in range(region_size[1]): if not img_mask[y, x]: index = x + y * region_size[1] b[index] = t[index] # solve Ax = b x = pyamg.solve(coff_mat, b, verb=False, tol=1e-10) # assign x to target image x = np.reshape(x, region_size) x[x > 255] = 255 x[x < 0] = 0 x = np.array(x, img_target.dtype) img_target[region_target[0]:region_target[2], region_target[1]:region_target[3], num_layer] = x return img_target