def feat_desc(img, x, y): N = x.size descs = np.zeros((64, N)) edges = filters.sobel(img) for i in range(N): x_temp = np.arange(x[i] - 19, x[i] + 21, 1) x_i = np.tile(x_temp, (40, 1)) y_temp = np.arange(y[i] - 19, y[i] + 21, 1) y_temp = y_temp.reshape(-1, 1) y_i = np.tile(y_temp, (1, 40)) interp = interp2(edges, x_i, y_i) final = np.zeros((320, 5)) final[0:40, 0:5] = interp[0:40, 0:5] final[40:80, 0:5] = interp[0:40, 5:10] final[80:120, 0:5] = interp[0:40, 10:15] final[120:160, 0:5] = interp[0:40, 15:20] final[160:200, 0:5] = interp[0:40, 20:25] final[200:240, 0:5] = interp[0:40, 25:30] final[240:280, 0:5] = interp[0:40, 30:35] final[280:320, 0:5] = interp[0:40, 35:40] final = final.reshape((64, 25)) final_max = np.amax(final, axis=1) descs_i = preprocessing.scale(final_max) descs[0:64, i:i + 1] = descs_i.reshape((64, 1)) return descs
def estimateFeatureTranslation(startX, startY, Ix, Iy, img1, img2): I_gray_1, I_gray_2 = rgb2gray(img1), rgb2gray(img2) X_old, Y_old = generatePatch(startX, startY) X_old, Y_old = X_old.astype(np.int32), Y_old.astype(np.int32) Ix_temp, Iy_temp = Ix[Y_old, X_old], Iy[Y_old, X_old] x0, y0 = startX, startY min_error = 999999 error_thresh = 1 iteration = 5 for i in range(iteration): X_new, Y_new = generatePatch(x0, y0) old_coor = np.array((x0, y0)).reshape(-1, 1) It_temp = interp2(I_gray_2, X_new, Y_new) - I_gray_1[Y_old, X_old] error = np.linalg.norm(It_temp) if error < min_error: min_error = error newX, newY = x0, y0 if error < error_thresh: break A = np.hstack((Ix_temp.reshape(-1, 1), Iy_temp.reshape(-1, 1))) b = -It_temp.reshape(-1, 1) flow_temp = np.linalg.solve(np.dot(A.T, A), np.dot(A.T, b)) new_coor = old_coor + flow_temp x0, y0 = new_coor[0, 0], new_coor[1, 0] return newX, newY
def estimateAllTranslation(startXs, startYs, origXs, origYs, img1, img2, bbox, params): import numpy as np from helpers import rgb2gray from helpers import interp2 from scipy import signal from calculateError import calculateError # ---------- Part 1: Setup ---------- # # Get images computed to grayscale # For now I'm going to pad the images symmetrically to get W for edges and corners # It will just be important to remember that padding's there when solving for pixel locations window = 11 pad = int((window - 1) / 2) # Blur the images to get better optical flow results Gx = signal.gaussian(window, 1.4).reshape(1, window) Gy = signal.gaussian(window, 1.4).reshape(window, 1) gray1 = signal.convolve2d(rgb2gray(img1), Gx, mode="full", boundary="symm") gray1 = signal.convolve2d(gray1, Gy, mode="full", boundary="symm") gray2 = signal.convolve2d(rgb2gray(img2), Gx, mode="full", boundary="symm") gray2 = signal.convolve2d(gray2, Gy, mode="full", boundary="symm") # Pull out parameters for looping F = len(startXs) # Initialize our outputs newXs = np.zeros(F, dtype=object) newYs = np.zeros(F, dtype=object) # Calculate the gradients kx = np.array([[1, -1]]) ky = np.array([[1], [-1]]) Ix = signal.convolve2d(gray1, kx, mode="same") Iy = signal.convolve2d(gray1, ky, mode="same") # ---------- Part 2: Caluclate the feature translations ---------- # # Use these gradients to find the new locations of the feature points # I'm not going to put this into a second function to reduce runtime A = np.zeros((window**2, 2)) b = np.zeros((window**2, 1)) # Iterate for each bounding box as necessary for i in range(F): error = np.nan_to_num(np.Inf) min_error = error.copy() iters = 0 tempOrigXs = np.copy(origXs[i]) tempOrigYs = np.copy(origYs[i]) # Run for a max of 5 iterations or until the average squared distance between ea feat pt value is less than 5k while error > 5000 and iters < 5: N = len(startXs[i]) potXs = np.zeros(N) potYs = np.zeros(N) It = gray2 - gray1 iters += 1 for j in range(N): # Get our feature location fx = startXs[i][j] fy = startYs[i][j] # Generate a meshgrid for interpolating meshx, meshy = np.meshgrid(np.arange(window), np.arange(window)) meshx = meshx + fx meshy = meshy + fy # Build A and b from A*[u; v] = b centered around the feature location A[:, 0] = interp2(Ix, meshx, meshy).reshape( window**2 ) # Ix[fy - pad: fy + pad + 1, fx - pad: fx + pad + 1].reshape(window**2) A[:, 1] = interp2(Iy, meshx, meshy).reshape( window**2 ) # Iy[fy - pad: fy + pad + 1, fx - pad: fx + pad + 1].reshape(window**2) b[:, 0] = interp2(It, meshx, meshy).reshape( window**2 ) # It[fy - pad: fy + pad + 1, fx - pad: fx + pad + 1].reshape(window**2) # Solve for [u; v] try: translation = np.matmul( np.matmul(np.linalg.inv(np.matmul(A.T, A)), A.T), -b) except np.linalg.LinAlgError: translation = np.array([0, 0]) # Save our result into our output potXs[j] = startXs[i][j] + translation[0] potYs[j] = startYs[i][j] + translation[1] # Calculate the error error, gray1, indexer, Ix, Iy, potXs, potYs = calculateError( startXs[i], startYs[i], potXs, potYs, np.copy(gray1), np.copy(gray2), Ix, Iy, np.copy(bbox[i]), params) startXs[i] = np.copy(potXs) startYs[i] = np.copy(potYs) tempOrigXs = tempOrigXs[indexer] tempOrigYs = tempOrigYs[indexer] # If we did better this time, save the results if error < min_error: min_error = error.copy() newXs[i] = np.copy(potXs) newYs[i] = np.copy(potYs) origXs[i] = np.copy(tempOrigXs) origYs[i] = np.copy(tempOrigYs) return newXs, newYs, origXs, origYs
def calculateError(startXs, startYs, newXs, newYs, img1, img2, Ix, Iy, box, params): import numpy as np from helpers import rgb2gray from helpers import interp2 from scipy import signal from scipy.optimize import least_squares from helpers import inlier_cost_func from helpers import warp_image # Extract parameters max_dist = params[0] k1 = params[1] k2 = params[2] k3 = params[3] k4 = params[4] pad = 5 source = rgb2gray(img1) target = rgb2gray(img2) source_warped = np.copy(source) h, w = source.shape # Get the boundaries of bounding box xmin = max([np.amin(box[:, 0]) - pad, 0]) xmax = min([np.amax(box[:, 0]) + pad + 1, w]) ymin = max([np.amin(box[:, 1]) - pad, 0]) ymax = min([np.amax(box[:, 1]) + pad + 1, h]) # Outlier handling indexer = np.all(np.stack([ newXs > xmin + pad, newXs < xmax - pad, newYs > ymin + pad, newYs < ymax - pad ], axis=0), axis=0) distances = np.sqrt( np.square(newXs - startXs) + np.square(newYs - startYs)) avg_dist = np.mean(distances) std_dist = np.std(distances) if avg_dist != 0: indexer = np.logical_and( indexer, np.logical_and( distances < min([k1 * avg_dist + k2 * std_dist, max_dist]), distances > k3 * avg_dist - k4 * std_dist)) # Generate vectors of inliers for calculating the transformation ux = startXs[indexer] uy = startYs[indexer] vx = newXs[indexer] vy = newYs[indexer] # Form our initial and final feature points in homogeneous coordinates N = len(ux) u = np.stack([ux, uy, np.ones(N)]) v = np.stack([vx, vy, np.ones(N)]) # Calculate the transformation via least squares T = least_squares(inlier_cost_func, np.identity(3)[:2].reshape(6), args=(u, v))["x"].reshape(2, 3) T = np.concatenate((T, np.array([[0, 0, 1]]))) newXs = np.matmul(T, u)[0] newYs = np.matmul(T, u)[1] # Warp img1, Ix and Iy based on calculated transformation target_area = target[ymin:ymax, xmin:xmax] source_area = source[ymin:ymax, xmin:xmax] warped_area = warp_image(source, T, xmin, xmax, ymin, ymax) source_warped[ymin:ymax, xmin:xmax] = warped_area Ix_area = warp_image(Ix, T, xmin, xmax, ymin, ymax) Ix[ymin:ymax, xmin:xmax] = Ix_area Iy_area = warp_image(Iy, T, xmin, xmax, ymin, ymax) Iy[ymin:ymax, xmin:xmax] = Iy_area # Calculate the error per feature point interpx = np.array([newXs]) interpy = np.array([newYs]) values_this = interp2(source_warped, interpx, interpy).reshape(len(newXs)) values_next = interp2(target, interpx, interpy).reshape(len(newXs)) error = np.sum(np.square(values_next - values_this)) / len(newXs) return error, source_warped, indexer, Ix, Iy, newXs, newYs
def generate_warp(size_H, size_W, Tri, A_Inter_inv_set, A_im_set, image): # generate x,y meshgrid x, y = np.meshgrid(np.arange(size_W), np.arange(size_H)) x = x.flatten() y = y.flatten() # all points in img (size_H*size_W, 2) as x,y system empty_points = np.array(list(zip(x, y))) # print(empty_points) assert empty_points.shape == (size_H * size_W, 2) # find the tris where these points live in find_simplex_tris = Tri.find_simplex(empty_points) # compute alpha, beta, gamma all_Inter_inv_A = A_Inter_inv_set[find_simplex_tris] all_img_A = A_im_set[find_simplex_tris] # aug_empty_points = np.hstack((empty_points,np.ones((empty_points.shape[0], 1)))) alpha = all_Inter_inv_A[:, 0, 0] * empty_points[:, 0].flatten() + \ all_Inter_inv_A[:, 0, 1] * empty_points[:, 1].flatten() + \ all_Inter_inv_A[:, 0, 2] * 1 beta = all_Inter_inv_A[:, 1, 0] * empty_points[:, 0] + \ all_Inter_inv_A[:, 1, 1] * empty_points[:, 1] + \ all_Inter_inv_A[:, 1, 2] * 1 gamma = all_Inter_inv_A[:, 2, 0] * empty_points[:, 0] + \ all_Inter_inv_A[:, 2, 1] * empty_points[:, 1] + \ all_Inter_inv_A[:, 2, 2] * 1 assert beta.size == empty_points[:, 0].flatten().size # print(all_Inter_inv_A[:, 2, 0].shape) all_x_coor = all_img_A[:, 0, 0] * alpha + \ all_img_A[:, 0, 1] * beta + \ all_img_A[:, 0, 2] * gamma all_y_coor = all_img_A[:, 1, 0] * alpha + \ all_img_A[:, 1, 1] * beta + \ all_img_A[:, 1, 2] * gamma # analytical result all_z_coor = np.ones(beta.size) all_x_coor_regularized = all_x_coor / all_z_coor all_y_coor_regularized = all_y_coor / all_z_coor # generate warp img generated_pic = np.zeros((size_H, size_W, 3), dtype=np.uint8) generated_pic[:, :, 0] = np.reshape( interp2(image[:, :, 0], all_x_coor_regularized, all_y_coor_regularized), [size_H, size_W]) generated_pic[:, :, 1] = np.reshape( interp2(image[:, :, 1], all_x_coor_regularized, all_y_coor_regularized), [size_H, size_W]) generated_pic[:, :, 2] = np.reshape( interp2(image[:, :, 2], all_x_coor_regularized, all_y_coor_regularized), [size_H, size_W]) # LOOP VERSION: SLOW # # # # generate a empty matrix to store the warp img # generated_pic = np.zeros((size_H, size_W, 3), dtype=np.uint8) # # # go through every point's coor in the inter-generated-pic # for i in np.arange(size_H): # for j in np.arange(size_W): # # find its belonging triangle, # # find_simplex according to x,y system # fea_index = Tri.find_simplex(np.array([i, j])) # # print(fea_index) # # pull out the A_inter_inv matrix of Tri index # A_Inter_inv = A_Inter_inv_set[fea_index, :, :] # # # pull out the coor of the point # b_target = np.array([i, j, 1]) # # # compute the barycentric coor # barycentric = np.dot(A_Inter_inv, b_target) # # # pull out the A_im matrix of the Tir index # b_source = np.dot(A_im_set[fea_index, :, :], barycentric) # assert len(b_source) == 3 # print(b_source[2]) # # b_source = b_source/b_source[2] # b_source_map = np.round(b_source).astype(int)[0:2] # # generated_pic[i, j, 0] = image[b_source_map[0], b_source_map[1], 0] # generated_pic[i, j, 1] = image[b_source_map[0], b_source_map[1], 1] # generated_pic[i, j, 2] = image[b_source_map[0], b_source_map[1], 2] return generated_pic
x1, y1 = xs1, ys1 x2, y2 = xs2, ys2 X_old = np.array( [[x1 - 1, x1, x1 + 1], [x1 - 1, x1, x1 + 1], [x1 - 1, x1, x1 + 1]], dtype=np.int32) Y_old = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]], dtype=np.int32) ix_temp = ix[Y_old, X_old] iy_temp = iy[Y_old, X_old] for i in range(5): X_new = np.array([[x1 - 1, x1, x1 + 1], [x1 - 1, x1, x1 + 1], [x1 - 1, x1, x1 + 1]]) Y_new = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]]) old_coor = np.array((x1, y1)).reshape(-1, 1) it_temp = interp2(i2, X_new, Y_new) - i1[Y_old, X_old] error = np.linalg.norm(it_temp) A = np.hstack((ix_temp.reshape(-1, 1), iy_temp.reshape(-1, 1))) b = -it_temp.reshape(-1, 1) flow_temp = np.linalg.solve(np.dot(A.T, A), np.dot(A.T, b)) new_coor = old_coor + flow_temp x1, y1 = new_coor[0, 0], new_coor[1, 0] xe1, ye1 = x1, y1 print("result point 1:", (xe1, ye1)) X_old = np.array( [[x2 - 1, x2, x2 + 1], [x2 - 1, x2, x2 + 1], [x2 - 1, x2, x2 + 1]], dtype=np.int32) Y_old = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]], dtype=np.int32) ix_temp = ix[Y_old, X_old] iy_temp = iy[Y_old, X_old]
def morph_tri(im1, im2, im1_pts, im2_pts, warp_frac, dissolve_frac): # TODO: Your code here # Tips: use Delaunay() function to get Delaunay triangulation; # Tips: use tri.find_simplex(pts) to find the triangulation index that pts locates in. dissolve_frac = 1-dissolve_frac warp_frac = 1-warp_frac images = [] if im2.shape != im1.shape: im2 = Image.fromarray(im2) im2 = im2.resize((im1.shape[1],im1.shape[0])) im2 = np.asarray(im2) imFF = np.zeros(([len(warp_frac),im1.shape[0],im1.shape[1],3])) imgc = 0 for t in warp_frac: im_mpts = (t*im1_pts + (1-t)*im2_pts) D = Delaunay(im_mpts) x = range(im1.shape[0]) y = range(im1.shape[1]) xv, yv = np.meshgrid(x, y) r = im1.shape[0] c = im1.shape[1] co_ords = np.zeros([im1.shape[1],im1.shape[0],3]) co_ords[:,:,0] = yv co_ords[:,:,1] = xv co_ords[:,:,2] = np.ones(yv.shape) points = co_ords.reshape([1,r*c,3]) triangles = D.find_simplex(points[:,:,:2]) act_tri = np.transpose(triangles.reshape(co_ords[:,:,0].shape)) tri_pt = D.simplices A_pt = tri_pt[:,0] B_pt = tri_pt[:,1] C_pt = tri_pt[:,2] A_ptc = im_mpts[A_pt] B_ptc = im_mpts[B_pt] C_ptc = im_mpts[C_pt] A_ptc = np.pad(A_ptc,[(0,0),(0,1)],mode = 'constant') A_ptc[:,2] = A_ptc[:,2]+1 B_ptc = np.pad(B_ptc,[(0,0),(0,1)],mode = 'constant') B_ptc[:,2] = B_ptc[:,2]+1 C_ptc = np.pad(C_ptc,[(0,0),(0,1)],mode = 'constant') C_ptc[:,2] = C_ptc[:,2]+1 A_ptc = np.transpose(A_ptc) B_ptc = np.transpose(B_ptc) C_ptc = np.transpose(C_ptc) D1 = np.transpose(A_ptc.copy()) E1 = np.transpose(B_ptc.copy()) F1 = np.transpose(C_ptc.copy()) D12 = D1.reshape([A_ptc.shape[1],3,1]) E12 = E1.reshape([B_ptc.shape[1],3,1]) F12 = F1.reshape([C_ptc.shape[1],3,1]) tri_mat = np.concatenate((D12,E12,F12),axis=2) tri_inv = np.linalg.inv(tri_mat) tri_inv_ordered = tri_inv[triangles,:,:] tri_inv_ordered = tri_inv_ordered[0,:,:,:] points1 = points[0,:,:] points1 = points.reshape([points.shape[1],3,1]) BC = np.matmul(tri_inv_ordered,points1) As_ptc = im1_pts[A_pt] Bs_ptc = im1_pts[B_pt] Cs_ptc = im1_pts[C_pt] As_ptc = np.pad(As_ptc,[(0,0),(0,1)],mode = 'constant') As_ptc[:,2] = As_ptc[:,2]+1 Bs_ptc = np.pad(Bs_ptc,[(0,0),(0,1)],mode = 'constant') Bs_ptc[:,2] = Bs_ptc[:,2]+1 Cs_ptc = np.pad(Cs_ptc,[(0,0),(0,1)],mode = 'constant') Cs_ptc[:,2] = Cs_ptc[:,2]+1 As_ptc = np.transpose(As_ptc) Bs_ptc = np.transpose(Bs_ptc) Cs_ptc = np.transpose(Cs_ptc) D1s = np.transpose(As_ptc.copy()) E1s = np.transpose(Bs_ptc.copy()) F1s = np.transpose(Cs_ptc.copy()) D12s = D1s.reshape([As_ptc.shape[1],3,1]) E12s = E1s.reshape([Bs_ptc.shape[1],3,1]) F12s = F1s.reshape([Cs_ptc.shape[1],3,1]) tris_mat = np.concatenate((D12s,E12s,F12s),axis=2) tris_mat_ordered = tris_mat[triangles,:,:] tris_mat_ordered = tris_mat_ordered[0,:,:,:] sxyz = np.matmul(tris_mat_ordered,BC) sxy = sxyz[:,:2,0] sxy = sxy.reshape([im1.shape[1],im1.shape[0],2]) x_1 = sxy[:,:,0] y_1 = sxy[:,:,1] im1R = interp2(im1[:,:,0],x_1,y_1) im1G = interp2(im1[:,:,1],x_1,y_1) im1B = interp2(im1[:,:,2],x_1,y_1) At_ptc = im2_pts[A_pt] Bt_ptc = im2_pts[B_pt] Ct_ptc = im2_pts[C_pt] At_ptc = np.pad(At_ptc,[(0,0),(0,1)],mode = 'constant') At_ptc[:,2] = At_ptc[:,2]+1 Bt_ptc = np.pad(Bt_ptc,[(0,0),(0,1)],mode = 'constant') Bt_ptc[:,2] = Bt_ptc[:,2]+1 Ct_ptc = np.pad(Ct_ptc,[(0,0),(0,1)],mode = 'constant') Ct_ptc[:,2] = Ct_ptc[:,2]+1 At_ptc = np.transpose(At_ptc) Bt_ptc = np.transpose(Bt_ptc) Ct_ptc = np.transpose(Ct_ptc) D1t = np.transpose(At_ptc.copy()) E1t = np.transpose(Bt_ptc.copy()) F1t = np.transpose(Ct_ptc.copy()) D12t = D1t.reshape([At_ptc.shape[1],3,1]) E12t = E1t.reshape([Bt_ptc.shape[1],3,1]) F12t = F1t.reshape([Ct_ptc.shape[1],3,1]) trit_mat = np.concatenate((D12t,E12t,F12t),axis=2) trit_mat_ordered = trit_mat[triangles,:,:] trit_mat_ordered = trit_mat_ordered[0,:,:,:] txyz = np.matmul(trit_mat_ordered,BC) txy = txyz[:,:2,0] txy = txy.reshape([im1.shape[1],im1.shape[0],2]) x_2 = txy[:,:,0] y_2 = txy[:,:,1] im2R = interp2(im2[:,:,0],x_2,y_2) im2G = interp2(im2[:,:,1],x_2,y_2) im2B = interp2(im2[:,:,2],x_2,y_2) imFR = (dissolve_frac[imgc]*im1R + (1-dissolve_frac[imgc])*im2R).T imFG = (dissolve_frac[imgc]*im1G + (1-dissolve_frac[imgc])*im2G).T imFB = (dissolve_frac[imgc]*im1B + (1-dissolve_frac[imgc])*im2B).T imF = im1.copy() imF[:,:,0] = imFR imF[:,:,1] = imFG imF[:,:,2] = imFB # plt.imshow(imF) # plt.show() imFF[imgc,:,:,0] = imFR imFF[imgc,:,:,1] = imFG imFF[imgc,:,:,2] = imFB images.append(imF) imgc = imgc +1 morphed_im = imFF io.mimsave('Morph.gif', images, duration = 0.05) # print(morphed_im.shape) return morphed_im
def findStuff(xx, yy, img, pts_avg, pts_orig, tri, tri_arr): corr_tri = tri_arr[yy * 300 + xx] trig_pts_avg = pts_avg[tri.simplices] trig_pts_orig = pts_orig[tri.simplices] Ax_avg = trig_pts_avg[corr_tri, 0, 0] Bx_avg = trig_pts_avg[corr_tri, 1, 0] Cx_avg = trig_pts_avg[corr_tri, 2, 0] Ay_avg = trig_pts_avg[corr_tri, 0, 1] By_avg = trig_pts_avg[corr_tri, 1, 1] Cy_avg = trig_pts_avg[corr_tri, 2, 1] Ax_orig = trig_pts_orig[corr_tri, 0, 0] Bx_orig = trig_pts_orig[corr_tri, 1, 0] Cx_orig = trig_pts_orig[corr_tri, 2, 0] Ay_orig = trig_pts_orig[corr_tri, 0, 1] By_orig = trig_pts_orig[corr_tri, 1, 1] Cy_orig = trig_pts_orig[corr_tri, 2, 1] ones = np.zeros((300, 300)) ones.fill(1) ones_horiz = np.zeros((1, 90000)) ones_horiz.fill(1) Ax_avg_flat = Ax_avg.flatten() Bx_avg_flat = Bx_avg.flatten() Cx_avg_flat = Cx_avg.flatten() Ay_avg_flat = Ay_avg.flatten() By_avg_flat = By_avg.flatten() Cy_avg_flat = Cy_avg.flatten() Ax_orig_flat = Ax_orig.flatten() Bx_orig_flat = Bx_orig.flatten() Cx_orig_flat = Cx_orig.flatten() Ay_orig_flat = Ay_orig.flatten() By_orig_flat = By_orig.flatten() Cy_orig_flat = Cy_orig.flatten() # big fat chunk to get Avg into 90000 * 3 * 3 matrix tempABCx = np.vstack((Ax_avg_flat, Bx_avg_flat, Cx_avg_flat)) tempx = tempABCx.T tempx = np.vsplit(tempx, 90000) tempx = np.hstack(tempx) tempx = np.squeeze(tempx, axis=0) tempABCy = np.vstack((Ay_avg_flat, By_avg_flat, Cy_avg_flat)) tempy = tempABCy.T tempy = np.vsplit(tempy, 90000) tempy = np.hstack(tempy) tempy = np.squeeze(tempy, axis=0) ones_flat = np.zeros(270000, dtype='float64') ones_flat.fill(1) temp_avg = np.vstack((tempx, tempy, ones_flat)) temp_avg = np.hsplit(temp_avg, 90000) temp_avg = np.vstack(temp_avg) temp_avg = np.vsplit(temp_avg, 90000) # big fat chunk to get orig into 90000 * 3 * 3 matrix tempABCxo = np.vstack((Ax_orig_flat, Bx_orig_flat, Cx_orig_flat)) tempxo = tempABCxo.T tempxo = np.vsplit(tempxo, 90000) tempxo = np.hstack(tempxo) tempxo = np.squeeze(tempxo, axis=0) tempABCyo = np.vstack((Ay_orig_flat, By_orig_flat, Cy_orig_flat)) tempyo = tempABCyo.T tempyo = np.vsplit(tempyo, 90000) tempyo = np.hstack(tempyo) tempyo = np.squeeze(tempyo, axis=0) temp_o = np.vstack((tempxo, tempyo, ones_flat)) temp_o = np.hsplit(temp_o, 90000) temp_o = np.vstack(temp_o) temp_o = np.vsplit(temp_o, 90000) xx_flat = xx.flatten() yy_flat = yy.flatten() ones_flat_2 = np.zeros(90000, dtype='float64') ones_flat_2.fill(1) xy1_stack = np.vstack((xx_flat, yy_flat, ones_flat_2)) xy1 = np.hsplit(xy1_stack, 90000) xy1 = np.vstack(xy1) xy1 = np.vsplit(xy1, 90000) solutiontMtx = np.linalg.solve(temp_avg, xy1) solution_pts = np.matmul(temp_o, solutiontMtx) solution_pts = np.squeeze(solution_pts, axis=2) solution_pts = np.hsplit(solution_pts, 3) sol_x = solution_pts[0] sol_y = solution_pts[1] sol_x = sol_x.flatten() sol_y = sol_y.flatten() sol_x_r = sol_x.reshape((300, 300)) sol_y_r = sol_y.reshape((300, 300)) img_r = img[:, :, 0] img_g = img[:, :, 1] img_b = img[:, :, 2] im1_morph_r = interp2(img_r, sol_x_r, sol_y_r) im1_morph_g = interp2(img_g, sol_x_r, sol_y_r) im1_morph_b = interp2(img_b, sol_x_r, sol_y_r) return im1_morph_r, im1_morph_g, im1_morph_b
def morph_tri(im1, im2, im1_pts, im2_pts, warp_frac, dissolve_frac): # Tips: use Delaunay() function to get Delaunay triangulation; # Tips: use tri.find_simplex(pts) to find the triangulation index that pts locates in. num_of_frames = warp_frac.shape[0] row, col, ch = im1.shape # create meshgrid of x,y coordinate x, y = np.meshgrid(np.arange(col), np.arange(row)) y = y.flatten() x = x.flatten() # create pixel coordinate in (x,y) pixel = np.stack((x,y), axis=1) # initialize morphing image morph_im = np.zeros([num_of_frames, row, col, ch], dtype='uint8') warp_src = np.zeros([num_of_frames, row, col, ch], dtype='uint8') warp_trg = np.zeros([num_of_frames, row, col, ch], dtype='uint8') for i in range(num_of_frames): # find interpolated points for Delaunay triangulation interp_pts = (1 - warp_frac[i]) * im1_pts + warp_frac[i] * im2_pts tri = Delaunay(interp_pts) # find the triangulation index that interp_pts locates in location = tri.find_simplex(pixel) # location = location.reshape(row, col) for j in range(np.shape(tri.simplices)[0]): # loop through every Delaunay triangles coor = pixel[np.where(location == j)] # pixels that belongs to triangle j x = coor[:,0] y = coor[:,1] pixel_coor = np.row_stack((x, y, np.ones(x.shape[0]))) # vertices of Delaunay triangles vertices = interp_pts[tri.simplices[j]] vertices = np.transpose(vertices) vertices = np.row_stack((vertices, np.ones([1,3]))) inv_vertices = np.linalg.inv(vertices) # barycentric coordinates for each pixel bary_coor = np.dot(inv_vertices, pixel_coor) # vertices of Delaunay triangles from source picture vertices_src = im1_pts[tri.simplices[j]] vertices_src = np.transpose(vertices_src) vertices_src = np.row_stack((vertices_src, np.ones([1, 3]))) source_coor = np.dot(vertices_src, bary_coor) # vertices of Delaunay triangles from target picture vertices_trg = im2_pts[tri.simplices[j]] vertices_trg = np.transpose(vertices_trg) vertices_trg = np.row_stack((vertices_trg, np.ones([1, 3]))) target_coor = np.dot(vertices_trg, bary_coor) # interpolate through every pixel in source and target for k in range(ch): warp_src[i, y, x, k] = interp2(im1[:, :, k], source_coor[0, :], source_coor[1, :]) warp_trg[i, y, x, k] = interp2(im2[:, :, k], target_coor[0, :], target_coor[1, :]) morph_im[i, :, :, :] = (1-dissolve_frac[i]) * warp_src[i,:,:,:] + dissolve_frac[i] * warp_trg[i,:,:,:] # pixel value should be between [0,255] morph_im = np.clip(morph_im, 0, 255) return morph_im