VxPhotoTalk / facewarp /gen_puppet_utils.py
VineX's picture
Upload 458 files
7cdd981
import numpy as np
import cv2
import matplotlib.pyplot as plt
import os
import random
def closest_node(xy, pts):
#search the list of nodes for the one closest to node, return the name
dist_2 = np.sqrt(np.sum((pts - np.array(xy).reshape((-1, 2)))**2, axis=1))
if (dist_2[np.argmin(dist_2)] > 20):
return -1
return np.argmin(dist_2)
def draw_landmarks(img, pts, pc=(0,0,255), radius=2, lc=(0,255,0), thickness=2):
for i in range(0, 16):
cv2.line(img, (int(pts[i, 0]), int(pts[i, 1])),
(int(pts[i+1, 0]), int(pts[i+1, 1])), (0, 255, 0), thickness)
for i in range(17, 21):
cv2.line(img, (int(pts[i, 0]), int(pts[i, 1])),
(int(pts[i+1, 0]), int(pts[i+1, 1])), (255, 0, 0), thickness)
for i in range(22, 26):
cv2.line(img, (int(pts[i, 0]), int(pts[i, 1])),
(int(pts[i+1, 0]), int(pts[i+1, 1])), (255, 0, 0), thickness)
for i in range(27, 35):
cv2.line(img, (int(pts[i, 0]), int(pts[i, 1])),
(int(pts[i+1, 0]), int(pts[i+1, 1])), (255, 255, 0), thickness)
for i in range(36, 41):
cv2.line(img, (int(pts[i, 0]), int(pts[i, 1])),
(int(pts[i+1, 0]), int(pts[i+1, 1])), (255, 0, 255), thickness)
for i in range(42, 47):
cv2.line(img, (int(pts[i, 0]), int(pts[i, 1])),
(int(pts[i+1, 0]), int(pts[i+1, 1])), (255, 0, 255), thickness)
for i in range(48, 59):
cv2.line(img, (int(pts[i, 0]), int(pts[i, 1])),
(int(pts[i+1, 0]), int(pts[i+1, 1])), (255, 128, 0), thickness)
for i in range(60, 67):
cv2.line(img, (int(pts[i, 0]), int(pts[i, 1])),
(int(pts[i+1, 0]), int(pts[i+1, 1])), (255, 128, 128), thickness)
cv2.line(img, (int(pts[48, 0]), int(pts[48, 1])),
(int(pts[59, 0]), int(pts[59, 1])), (255, 128, 0), thickness)
cv2.line(img, (int(pts[60, 0]), int(pts[60, 1])),
(int(pts[67, 0]), int(pts[67, 1])), (255, 128, 128), thickness)
for i in range(68):
cv2.circle(img, (int(pts[i, 0]), int(pts[i, 1])), radius, pc, -1)
def norm_anno(ROOT_DIR, CH, param=[0.75, 0.35, 0.6, 0.6], show=True):
face_tmp = np.loadtxt(os.path.join(ROOT_DIR, CH + '_face_open_mouth.txt')) # .reshape(1, 204)
try:
face_tmp = face_tmp.reshape(68, 3)
except:
print('annotated face is not in correct size = [68 x 3]')
exit(0)
scale = 1.6 / (face_tmp[0, 0] - face_tmp[16, 0])
shift = - 0.5 * (face_tmp[0, 0:2] + face_tmp[16, 0:2])
face_tmp[:, 0:2] = (face_tmp[:, 0:2] + shift) * scale
face_std = np.loadtxt(os.path.join(ROOT_DIR, 'STD_FACE_LANDMARKS.txt'))
face_std = face_std.reshape(68, 3)
face_tmp[:, -1] = face_std[:, -1]
face_tmp[:, 0:2] = -face_tmp[:, 0:2]
np.savetxt(os.path.join(ROOT_DIR, CH + '_face_open_mouth_norm.txt'), face_tmp, fmt='%.4f')
np.savetxt(os.path.join(ROOT_DIR, CH + '_scale_shift.txt'), np.array([scale, shift[0], shift[1]]), fmt='%.10f')
# Force the frame to close mouth
face_tmp[49:54, 1] = param[0] * face_tmp[49:54, 1] + (1-param[0]) * face_tmp[59:54:-1, 1]
face_tmp[59:54:-1, 1] = param[1] * face_tmp[49:54, 1] + (1-param[1]) * face_tmp[59:54:-1, 1]
face_tmp[61:64, 1] = param[2] * face_tmp[61:64, 1] + (1-param[2]) * face_tmp[67:64:-1, 1]
face_tmp[67:64:-1, 1] = param[3] * face_tmp[61:64, 1] + (1-param[3]) * face_tmp[67:64:-1, 1]
face_tmp[61:64, 0] = 0.6 * face_tmp[61:64, 0] + 0.4 * face_tmp[67:64:-1, 0]
face_tmp[67:64:-1, 0] = 0.6 * face_tmp[61:64, 0] + 0.4 * face_tmp[67:64:-1, 0]
np.savetxt(os.path.join(ROOT_DIR, CH + '_face_close_mouth.txt'), face_tmp, fmt='%.4f')
std_face_id = np.loadtxt(os.path.join(ROOT_DIR, CH + '_face_close_mouth.txt')) # .reshape(1, 204)
std_face_id = std_face_id.reshape(68, 3)
def vis_landmark_on_plt(fl, x_offset=0.0, show_now=True):
def draw_curve(shape, idx_list, loop=False, x_offset=0.0, c=None):
for i in idx_list:
plt.plot((shape[i, 0] + x_offset, shape[i + 1, 0] + x_offset), (-shape[i, 1], -shape[i + 1, 1]), c=c)
if (loop):
plt.plot((shape[idx_list[0], 0] + x_offset, shape[idx_list[-1] + 1, 0] + x_offset),
(-shape[idx_list[0], 1], -shape[idx_list[-1] + 1, 1]), c=c)
draw_curve(fl, list(range(0, 16)), x_offset=x_offset) # jaw
draw_curve(fl, list(range(17, 21)), x_offset=x_offset) # eye brow
draw_curve(fl, list(range(22, 26)), x_offset=x_offset)
draw_curve(fl, list(range(27, 35)), x_offset=x_offset) # nose
draw_curve(fl, list(range(36, 41)), loop=True, x_offset=x_offset) # eyes
draw_curve(fl, list(range(42, 47)), loop=True, x_offset=x_offset)
draw_curve(fl, list(range(48, 59)), loop=True, x_offset=x_offset, c='b') # mouth
draw_curve(fl, list(range(60, 67)), loop=True, x_offset=x_offset, c='r')
draw_curve(fl, list(range(60, 64)), loop=False, x_offset=x_offset, c='g')
if (show_now):
plt.show()
vis_landmark_on_plt(std_face_id, show_now=show)
# Check if a point is inside a rectangle
def rect_contains(rect, point):
if point[0] < rect[0]:
return False
elif point[1] < rect[1]:
return False
elif point[0] > rect[2]:
return False
elif point[1] > rect[3]:
return False
return True
# Draw a point
def draw_point(img, p, color):
cv2.circle(img, p, 2, color, -1, cv2.LINE_AA, 0)
# Draw delaunay triangles
def draw_delaunay(img, subdiv, delaunay_color):
triangleList = subdiv.getTriangleList();
size = img.shape
r = (0, 0, size[1], size[0])
for t in triangleList:
pt1 = (t[0], t[1])
pt2 = (t[2], t[3])
pt3 = (t[4], t[5])
if rect_contains(r, pt1) and rect_contains(r, pt2) and rect_contains(r, pt3):
cv2.line(img, pt1, pt2, delaunay_color, 1, cv2.LINE_AA, 0)
cv2.line(img, pt2, pt3, delaunay_color, 1, cv2.LINE_AA, 0)
cv2.line(img, pt3, pt1, delaunay_color, 1, cv2.LINE_AA, 0)
# Draw voronoi diagram
def draw_voronoi(img, subdiv):
(facets, centers) = subdiv.getVoronoiFacetList([])
for i in range(0, len(facets)):
ifacet_arr = []
for f in facets[i]:
ifacet_arr.append(f)
ifacet = np.array(ifacet_arr, np.int)
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
cv2.fillConvexPoly(img, ifacet, color, cv2.LINE_AA, 0)
ifacets = np.array([ifacet])
cv2.polylines(img, ifacets, True, (0, 0, 0), 1, cv2.LINE_AA, 0)
cv2.circle(img, (centers[i][0], centers[i][1]), 3, (0, 0, 0), -1, cv2.LINE_AA, 0)
print("end of draw_voronoi")
def delauney_tri(ROOT_DIR, test_data, INNER_ONLY=False):
# Define window names
win_delaunay = "Delaunay Triangulation"
cv2.namedWindow(win_delaunay, cv2.WINDOW_NORMAL)
win_voronoi = "Voronoi Diagram"
# Turn on animation while drawing triangles
animate = True
# Define colors for drawing.
delaunay_color = (255, 255, 255)
points_color = (0, 0, 255)
# Read in the image.
if (os.path.exists(os.path.join(ROOT_DIR, test_data))):
img = cv2.imread(os.path.join(ROOT_DIR, test_data))
else:
print('not file founded.')
exit(0)
CH = test_data[:-4]
# Keep a copy around
img_orig = img.copy()
# Rectangle to be used with Subdiv2D
size = img.shape
rect = (0, 0, size[1], size[0])
# Create an array of points.
points = []
# Create an instance of Subdiv2D
subdiv = cv2.Subdiv2D(rect)
h = size[1] - 1
w = size[0] - 1
# Read in the points from a text file
file = np.loadtxt(os.path.join(ROOT_DIR, CH + '_face_open_mouth.txt'))
file = file.reshape(68, 3)
for i in range(file.shape[0]):
if(INNER_ONLY):
if(i >= 48 and i <= 59): ############## for inner lip only
continue
line = file[i]
x, y, z = line
points.append((int(float(x)), int(float(y))))
points.append((0, 0))
points.append((0, w // 4))
points.append((0, w // 2))
points.append((0, w // 4 * 3))
points.append((0, w))
points.append((h // 2, w))
points.append((h, w))
points.append((h, w // 2))
points.append((h, 0))
points.append((h // 4, 0))
points.append((h // 2, 0))
points.append((h // 4*3, 0))
# Insert points into subdiv
for p in points:
print(p)
subdiv.insert(p)
# Show animation
if animate:
img_copy = img_orig.copy()
# Draw delaunay triangles
draw_delaunay(img_copy, subdiv, (255, 255, 0))
cv2.imshow(win_delaunay, img_copy)
cv2.waitKey(100)
# Draw delaunay triangles
draw_delaunay(img, subdiv, (255, 255, 0))
triangleList = subdiv.getTriangleList()
p_dict = {} # Initialize empty dictionary.
index = 0
# Draw points
for p in points:
# draw_point(img, p, (0, 0, 255))
p_dict[p] = index
index = index + 1
# Allocate space for voronoi Diagram
img_voronoi = np.zeros(img.shape, dtype=img.dtype)
# Draw voronoi diagram
draw_voronoi(img_voronoi, subdiv)
# Show results
cv2.imshow(win_delaunay, img)
print("Press any key to quit...")
cv2.waitKey(0)
new_tri = [];
for line in triangleList:
p1 = (line[0], line[1])
p2 = (line[2], line[3])
p3 = (line[4], line[5])
try:
p1_index = p_dict[p1]
p2_index = p_dict[p2]
p3_index = p_dict[p3]
except:
continue
new_tri.append((p1_index, p2_index, p3_index))
print(new_tri)
a = np.array(new_tri).astype(int)
np.savetxt(os.path.join(ROOT_DIR, CH + '_delauney_tri.txt'), a, fmt='%d')