|
import numpy as np |
|
import cv2 |
|
import matplotlib.pyplot as plt |
|
import os |
|
import random |
|
|
|
def closest_node(xy, pts): |
|
|
|
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')) |
|
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') |
|
|
|
|
|
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')) |
|
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) |
|
draw_curve(fl, list(range(17, 21)), x_offset=x_offset) |
|
draw_curve(fl, list(range(22, 26)), x_offset=x_offset) |
|
draw_curve(fl, list(range(27, 35)), x_offset=x_offset) |
|
draw_curve(fl, list(range(36, 41)), loop=True, x_offset=x_offset) |
|
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') |
|
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) |
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
def draw_point(img, p, color): |
|
cv2.circle(img, p, 2, color, -1, cv2.LINE_AA, 0) |
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
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): |
|
|
|
win_delaunay = "Delaunay Triangulation" |
|
cv2.namedWindow(win_delaunay, cv2.WINDOW_NORMAL) |
|
win_voronoi = "Voronoi Diagram" |
|
|
|
|
|
animate = True |
|
|
|
|
|
delaunay_color = (255, 255, 255) |
|
points_color = (0, 0, 255) |
|
|
|
|
|
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] |
|
|
|
img_orig = img.copy() |
|
|
|
|
|
size = img.shape |
|
rect = (0, 0, size[1], size[0]) |
|
|
|
|
|
points = [] |
|
|
|
|
|
subdiv = cv2.Subdiv2D(rect) |
|
h = size[1] - 1 |
|
w = size[0] - 1 |
|
|
|
|
|
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): |
|
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)) |
|
|
|
|
|
for p in points: |
|
print(p) |
|
subdiv.insert(p) |
|
|
|
|
|
if animate: |
|
img_copy = img_orig.copy() |
|
|
|
draw_delaunay(img_copy, subdiv, (255, 255, 0)) |
|
cv2.imshow(win_delaunay, img_copy) |
|
cv2.waitKey(100) |
|
|
|
|
|
draw_delaunay(img, subdiv, (255, 255, 0)) |
|
triangleList = subdiv.getTriangleList() |
|
|
|
p_dict = {} |
|
index = 0 |
|
|
|
for p in points: |
|
|
|
p_dict[p] = index |
|
index = index + 1 |
|
|
|
|
|
img_voronoi = np.zeros(img.shape, dtype=img.dtype) |
|
|
|
|
|
draw_voronoi(img_voronoi, subdiv) |
|
|
|
|
|
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') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|