goldpulpy's picture
Upload model and app
f9e4a6c
raw
history blame
4.47 kB
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 Neighour 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()