Spaces:
Sleeping
Sleeping
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') | |