Spaces:
Runtime error
Runtime error
import numpy as np | |
import scipy.spatial as spatial | |
def bilinear_interpolate(img, coords): | |
""" Interpolates over every image channel | |
http://en.wikipedia.org/wiki/Bilinear_interpolation | |
:param img: max 3 channel image | |
:param coords: 2 x _m_ array. 1st row = xcoords, 2nd row = ycoords | |
:returns: array of interpolated pixels with same shape as coords | |
""" | |
int_coords = np.int32(coords) | |
x0, y0 = int_coords | |
dx, dy = coords - int_coords | |
# 4 Neighbour pixels | |
q11 = img[y0, x0] | |
q21 = img[y0, x0+1] | |
q12 = img[y0+1, x0] | |
q22 = img[y0+1, x0+1] | |
btm = q21.T * dx + q11.T * (1 - dx) | |
top = q22.T * dx + q12.T * (1 - dx) | |
inter_pixel = top * dy + btm * (1 - dy) | |
return inter_pixel.T | |
def grid_coordinates(points): | |
""" x,y grid coordinates within the ROI of supplied points | |
:param points: points to generate grid coordinates | |
:returns: array of (x, y) coordinates | |
""" | |
xmin = np.min(points[:, 0]) | |
xmax = np.max(points[:, 0]) + 1 | |
ymin = np.min(points[:, 1]) | |
ymax = np.max(points[:, 1]) + 1 | |
return np.asarray([(x, y) for y in range(ymin, ymax) | |
for x in range(xmin, xmax)], np.uint32) | |
def process_warp(src_img, result_img, tri_affines, dst_points, delaunay): | |
""" | |
Warp each triangle from the src_image only within the | |
ROI of the destination image (points in dst_points). | |
""" | |
roi_coords = grid_coordinates(dst_points) | |
# indices to vertices. -1 if pixel is not in any triangle | |
roi_tri_indices = delaunay.find_simplex(roi_coords) | |
for simplex_index in range(len(delaunay.simplices)): | |
coords = roi_coords[roi_tri_indices == simplex_index] | |
num_coords = len(coords) | |
out_coords = np.dot(tri_affines[simplex_index], | |
np.vstack((coords.T, np.ones(num_coords)))) | |
x, y = coords.T | |
result_img[y, x] = bilinear_interpolate(src_img, out_coords) | |
return None | |
def triangular_affine_matrices(vertices, src_points, dest_points): | |
""" | |
Calculate the affine transformation matrix for each | |
triangle (x,y) vertex from dest_points to src_points | |
:param vertices: array of triplet indices to corners of triangle | |
:param src_points: array of [x, y] points to landmarks for source image | |
:param dest_points: array of [x, y] points to landmarks for destination image | |
:returns: 2 x 3 affine matrix transformation for a triangle | |
""" | |
ones = [1, 1, 1] | |
for tri_indices in vertices: | |
src_tri = np.vstack((src_points[tri_indices, :].T, ones)) | |
dst_tri = np.vstack((dest_points[tri_indices, :].T, ones)) | |
mat = np.dot(src_tri, np.linalg.inv(dst_tri))[:2, :] | |
yield mat | |
def warp_image(src_img, src_points, dest_points, dest_shape, dtype=np.uint8): | |
# Resultant image will not have an alpha channel | |
num_chans = 3 | |
src_img = src_img[:, :, :3] | |
rows, cols = dest_shape[:2] | |
result_img = np.zeros((rows, cols, num_chans), dtype) | |
delaunay = spatial.Delaunay(dest_points) | |
tri_affines = np.asarray(list(triangular_affine_matrices( | |
delaunay.simplices, src_points, dest_points))) | |
process_warp(src_img, result_img, tri_affines, dest_points, delaunay) | |
return result_img | |
def test_local(): | |
from functools import partial | |
import cv2 | |
import scipy.misc | |
import locator | |
import aligner | |
from matplotlib import pyplot as plt | |
# Load source image | |
face_points_func = partial(locator.face_points, '../data') | |
base_path = '../females/Screenshot 2015-03-04 17.11.12.png' | |
src_path = '../females/BlDmB5QCYAAY8iw.jpg' | |
src_img = cv2.imread(src_path) | |
# Define control points for warps | |
src_points = face_points_func(src_path) | |
base_img = cv2.imread(base_path) | |
base_points = face_points_func(base_path) | |
size = (600, 500) | |
src_img, src_points = aligner.resize_align(src_img, src_points, size) | |
base_img, base_points = aligner.resize_align(base_img, base_points, size) | |
result_points = locator.weighted_average_points(src_points, base_points, 0.2) | |
# Perform transform | |
dst_img1 = warp_image(src_img, src_points, result_points, size) | |
dst_img2 = warp_image(base_img, base_points, result_points, size) | |
import blender | |
ave = blender.weighted_average(dst_img1, dst_img2, 0.6) | |
mask = blender.mask_from_points(size, result_points) | |
blended_img = blender.poisson_blend(dst_img1, dst_img2, mask) | |
plt.subplot(2, 2, 1) | |
plt.imshow(ave) | |
plt.subplot(2, 2, 2) | |
plt.imshow(dst_img1) | |
plt.subplot(2, 2, 3) | |
plt.imshow(dst_img2) | |
plt.subplot(2, 2, 4) | |
plt.imshow(blended_img) | |
plt.show() | |
if __name__ == "__main__": | |
test_local() | |