当前位置:   article > 正文

人脸关键点检测和头部姿态估计数据集生成_基于人脸关键点检测的头部姿态识别

基于人脸关键点检测的头部姿态识别

接上篇 人脸关键点检测和头部姿态估计数据集整理

1. 借助于OpenPose生成人脸关键点和头部姿态,使用链接:https://github.com/TadasBaltrusaitis/OpenFace/wiki/Command-line-arguments

build/bin/FaceLandmarkImg.exe -fdir "images path"

具体使用可参考博客,每张人脸可得到一个csv文件,里面记录了人脸的很多信息,我们只需要68个关键点和头部姿态

2. 借助于人脸检测网络生成人脸检测结果,每张人脸可得到一个csv文件,里面记录了人脸的左上角和右下角坐标,具体使用可参考博客

3.结合OpenPose和人脸检测结果生成数据集label标注文件,格式为:

face_path x1 y1 x2 y2 x3 y3 ...... x68 y68 pitch yaw roll

执行代码:Generate_labels.py

  1. import sys, os
  2. import cv2
  3. import numpy as np
  4. import csv
  5. import argparse
  6. import math
  7. from shutil import copyfile
  8. #Determine whether it is a rotation matrix
  9. def isRotationMatrix(R):
  10. Rt = np.transpose(R)
  11. shouldBeIdentity = np.dot(Rt, R)
  12. I = np.identity(3, dtype=R.dtype)
  13. n = np.linalg.norm(I - shouldBeIdentity)
  14. return n < 1e-6
  15. #rotationvector to rorationmatrix
  16. def vec2matrix(rvec):
  17. theta = np.linalg.norm(rvec)
  18. r = rvec / theta
  19. R_ = np.array([[0, -r[2][0], r[1][0]],
  20. [r[2][0], 0, -r[0][0]],
  21. [-r[1][0], r[0][0], 0]])
  22. R = np.cos(theta) * np.eye(3) + (1 - np.cos(theta)) * r * r.T + np.sin(theta) * R_
  23. return R
  24. #rotationmatrix to EulerAngles
  25. def rotationMatrixToAngles(R):
  26. assert (isRotationMatrix(R))
  27. sy = math.sqrt(R[0, 0] * R[0, 0] + R[1, 0] * R[1, 0])
  28. singular = sy < 1e-6
  29. if not singular:
  30. x = math.atan2(R[2, 1], R[2, 2])
  31. y = math.atan2(-R[2, 0], sy)
  32. z = math.atan2(R[1, 0], R[0, 0])
  33. else:
  34. x = math.atan2(-R[1, 2], R[1, 1])
  35. y = math.atan2(-R[2, 0], sy)
  36. z = 0
  37. x = x*180.0/3.141592653589793
  38. y = y*180.0/3.141592653589793
  39. z = z*180.0/3.141592653589793
  40. return np.array([-1.0*x+10, y, z])
  41. def compute_iou(rec1, rec2):
  42. """
  43. computing IoU
  44. :param rec1: (y0, x0, y1, x1), which reflects
  45. (top, left, bottom, right)
  46. :param rec2: (y0, x0, y1, x1)
  47. :return: scala value of IoU
  48. """
  49. # computing area of each rectangles
  50. S_rec1 = (rec1[2] - rec1[0]) * (rec1[3] - rec1[1])
  51. S_rec2 = (rec2[2] - rec2[0]) * (rec2[3] - rec2[1])
  52. # computing the sum_area
  53. sum_area = S_rec1 + S_rec2
  54. # find the each edge of intersect rectangle
  55. left_line = max(rec1[1], rec2[1])
  56. right_line = min(rec1[3], rec2[3])
  57. top_line = max(rec1[0], rec2[0])
  58. bottom_line = min(rec1[2], rec2[2])
  59. # judge if there is an intersect
  60. if left_line >= right_line or top_line >= bottom_line:
  61. return 0
  62. else:
  63. intersect = (right_line - left_line) * (bottom_line - top_line)
  64. return (intersect / (sum_area - intersect)) * 1.0
  65. def Generate_labels(img_path, csv_path, txt_path, face_path, label_path):
  66. """
  67. :param img_path:
  68. :param csv_path:
  69. :param txt_path:
  70. :param face_path:
  71. :param label_path:
  72. :return:
  73. """
  74. img_list = os.listdir(img_path)
  75. fp_label = open(os.path.join(label_path, '300w_label.txt'), 'w')
  76. for img_file in img_list:
  77. print('now is dealing with '+str(img_file))
  78. # Iterative execution of each image
  79. filename, extension = os.path.splitext(img_file)
  80. extension = extension[1:]
  81. if extension == 'jpg' or extension == 'png':
  82. img = cv2.imread(os.path.join(img_path, img_file))
  83. # read and organize the result of OpenFace, result is saved to 'csv_result' for format as:
  84. # [
  85. # [point0_x,point0_y],
  86. # [point1_x,point1_y],
  87. # [point2_x,point2_y],
  88. # ......
  89. # [pose_x,pose_y,pose_z],
  90. # [xmin_csv,ymin_csv,xmax_csv,ymax_csv]
  91. # ]
  92. if not os.path.exists(os.path.join(csv_path, filename + '.csv')):
  93. continue
  94. csv_file = open(os.path.join(csv_path, filename + '.csv'), 'r')
  95. reader = csv.reader(csv_file)
  96. csv_result = []
  97. for item in reader:
  98. csv_result_temp = []
  99. xmin_csv = 50000
  100. ymin_csv = 50000
  101. xmax_csv = 0
  102. ymax_csv = 0
  103. if reader.line_num == 1:
  104. continue
  105. for i in range(68):
  106. csv_result_temp.append([float(item[296 + i]), float(item[296 + i + 68])])
  107. xmin_csv = min(xmin_csv, float(item[296 + i]))
  108. xmax_csv = max(xmax_csv, float(item[296 + i]))
  109. ymin_csv = min(ymin_csv, float(item[296 + i + 68]))
  110. ymax_csv = max(ymax_csv, float(item[296 + i + 68]))
  111. csv_result_temp.append([item[293], item[294], item[295]])
  112. csv_result_temp.append([xmin_csv, ymin_csv, xmax_csv, ymax_csv])
  113. csv_result.append(csv_result_temp)
  114. csv_file.close()
  115. # read and organize the label of 300w dataset, result is saved to 'pts_result' for format as:
  116. # [
  117. # [point0_x,point0_y],
  118. # [point1_x,point1_y],
  119. # [point2_x,point2_y],
  120. # ......
  121. # [xmin_pts,ymin_pts,xmax_pts,ymax_pts]
  122. # ]
  123. fp_pts = open(os.path.join(img_path, filename + '.pts'), 'r')
  124. lines = fp_pts.readlines()
  125. lines = lines[3:71]
  126. xmin_pts = 50000
  127. ymin_pts = 50000
  128. xmax_pts = 0
  129. ymax_pts = 0
  130. pts_result = []
  131. for line in lines:
  132. S = line.split(' ')
  133. point_x = float(S[0])
  134. point_y = float(S[1])
  135. xmin_pts = min(xmin_pts, point_x)
  136. ymin_pts = min(ymin_pts, point_y)
  137. xmax_pts = max(xmax_pts, point_x)
  138. ymax_pts = max(ymax_pts, point_y)
  139. pts_result.append([point_x, point_y])
  140. pts_result.append([xmin_pts, ymin_pts, xmax_pts, ymax_pts])
  141. fp_pts.close()
  142. face_pose = []
  143. face_bbox = []
  144. iou_max = 0
  145. for i in range(len(csv_result)):
  146. if compute_iou((ymin_pts, xmin_pts, ymax_pts, xmax_pts), (
  147. csv_result[i][69][1], csv_result[i][69][0], csv_result[i][69][3], csv_result[i][69][2])) > iou_max\
  148. and compute_iou((ymin_pts, xmin_pts, ymax_pts, xmax_pts), (
  149. csv_result[i][69][1], csv_result[i][69][0], csv_result[i][69][3], csv_result[i][69][2])) >= 0.5:
  150. face_pose = csv_result[i][68][0:]
  151. if not face_pose:
  152. continue
  153. # read the face detected result with txt format and get the face bbox, which is in Square form
  154. fp_txt = open(os.path.join(txt_path, filename + '.txt'), 'r')
  155. lines = fp_txt.readlines()
  156. iou_max = 0
  157. for line in lines:
  158. line = line[:-1]
  159. S = line.split(' ')
  160. xmin_txt = float(S[0])
  161. ymin_txt = float(S[1])
  162. xmax_txt = float(S[2])
  163. ymax_txt = float(S[3])
  164. if compute_iou((ymin_pts, xmin_pts, ymax_pts, xmax_pts),
  165. (ymin_txt, xmin_txt, ymax_txt, xmax_txt)) > iou_max\
  166. and compute_iou((ymin_pts, xmin_pts, ymax_pts, xmax_pts),
  167. (ymin_txt, xmin_txt, ymax_txt, xmax_txt)) >= 0.7:
  168. face_bbox.append([xmin_txt, ymin_txt, xmax_txt, ymax_txt])
  169. fp_txt.close()
  170. # determine if the face is detected
  171. if face_bbox:
  172. width = xmax_txt - xmin_txt
  173. height = ymax_txt - ymin_txt
  174. adjust_value = 1.0 * (height - width) / 2.0
  175. xmin = int(round(max(0, xmin_txt - adjust_value)))
  176. ymin = int(round(ymin_txt))
  177. xmax = int(round(min(img.shape[1], xmin+height)))
  178. ymax = int(round(ymax_txt))
  179. print(xmax-xmin, ymax-ymin)
  180. else:
  181. width = xmax_pts - xmin_pts
  182. height = ymax_pts - ymin_pts
  183. long_size = max(width, height)
  184. adjust_value_x = 1.0 * (long_size - width) / 2.0
  185. adjust_value_y = 1.0 * (long_size - height) / 2.0
  186. xmin = int(round(max(0, xmin_pts - adjust_value_x)))
  187. xmax = int(round(min(img.shape[1], xmin+long_size)))
  188. ymin = int(round(max(0, ymin_pts - adjust_value_y)))
  189. ymax = int(round(min(img.shape[0], ymin+long_size)))
  190. print(xmax-xmin,ymax-ymin)
  191. # crop face from original img
  192. img_face = img[ymin:ymax, xmin:xmax, :]
  193. cv2.imwrite(os.path.join(face_path, filename + '.jpg'), img_face)
  194. # write the path of cropped face to txt
  195. fp_label.write(os.path.join(face_path, filename + '.jpg') + ' ')
  196. #fp_label.write('/home/OpenFace/300w_face/'+filename + '.jpg'+' ')
  197. # write the point coordinates to txt
  198. for i in range(68):
  199. fp_label.write(str(pts_result[i][0] - xmin) + ' ' + str(pts_result[i][1] - ymin) + ' ')
  200. # write the face pose to txt
  201. '''
  202. rotation_vector = []
  203. rotation_vector.append([float(face_pose[0])])
  204. rotation_vector.append([float(face_pose[1])])
  205. rotation_vector.append([float(face_pose[2])])
  206. R = vec2matrix(rotation_vector)
  207. headpose = rotationMatrixToAngles(R)
  208. '''
  209. headpose = []
  210. headpose.append(float(face_pose[0])/math.pi*180)
  211. headpose.append(float(face_pose[1])/math.pi*180)
  212. headpose.append(float(face_pose[2])/math.pi*180)
  213. fp_label.write(str(headpose[0]) + ' ' + str(headpose[1]) +' ' + str(headpose[2]) + '\n')
  214. fp_label.close()
  215. if __name__ == '__main__':
  216. parser = argparse.ArgumentParser()
  217. parser.add_argument("--img_path", type=str, default='img_path',
  218. help="the path to the 300w dataset")
  219. parser.add_argument("--csv_path", type=str, default='csv_path',
  220. help="the path to the result of OpenFace")
  221. parser.add_argument("--txt_path", type=str, default='txt_path',
  222. help="the path to the face detect")
  223. parser.add_argument("--face_path", type=str, default='face_path_test',
  224. help="the path to the crop face saved")
  225. parser.add_argument("--label_path", type=str, default='label_path_test',
  226. help="the path to the label of 300w dataset")
  227. opt = parser.parse_args()
  228. Generate_labels(opt.img_path, opt.csv_path, opt.txt_path, opt.face_path, opt.label_path)

4.参考githubhttps://github.com/lsy17096535/face-landmark/blob/master/train/mainloop.py

生成hdf5时对数据集做的预处理操作如下所示:

  1. image 人脸
  2. 1. resize(img,(60,60)).astype('f4')
  3. 2. cvtcolor(BGR2GRAY).reshape(1,60,60)
  4. 3. m,s = cv2.meanstdDev(image)
  5. 4. image = (image - m) / (1.e-6 + s)
  1. landmarks 关键点
  2. 1. 乘以scale系数 rx=60/face img width ry=60/face img height
  3. 2. 归一化 /60
  1. poses 头部姿态
  2. 1. 归一化 /50

执行代码:Generate_hdf5.py

  1. import sys,os
  2. import cv2
  3. import numpy as np
  4. from shutil import copyfile
  5. caffe_root = 'caffe/python/'
  6. sys.path.insert(0, caffe_root + 'python')
  7. import caffe
  8. import h5py
  9. import argparse
  10. IMAGE_SIZE = 60 #fixed size to all images
  11. def Generate_hdf5(train_txt_file, train_h5_file, train_h5_list_file):
  12. """
  13. Generate hdf5 format based on the txt label
  14. :param train_txt_file: label in txt format (imgpath x1 y1 x2 y2 ...... x68 y68 pitch yaw roll)
  15. :param train_h5_file: h5 file to be saved
  16. :param train_h5_list_file: list file in txt format to be saved
  17. :return:
  18. """
  19. with open(train_txt_file,'r') as T:
  20. lines = T.readlines()
  21. HD5Images = np.zeros([len(lines), 1, IMAGE_SIZE, IMAGE_SIZE], dtype='float32')
  22. HD5Landmarks = np.zeros([len(lines), 136], dtype='float32')
  23. HD5Poses = np.zeros([len(lines), 3], dtype='float32')
  24. for i,l in enumerate(lines):
  25. sp = l.split(' ')
  26. print(sp[0])
  27. img = cv2.imread(sp[0])
  28. height,width = img.shape[0], img.shape[1]
  29. rx,ry = 1.0*IMAGE_SIZE/width, 1.0*IMAGE_SIZE/height
  30. res = cv2.resize(img, (IMAGE_SIZE, IMAGE_SIZE), 0.0, 0.0, interpolation=cv2.INTER_CUBIC)
  31. image = res.astype('f4')
  32. image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY).reshape(1, IMAGE_SIZE, IMAGE_SIZE)
  33. m, s = cv2.meanStdDev(image)
  34. image = (image - m) / (1.e-6 + s)
  35. HD5Images[i, :] = image
  36. label_ = np.zeros([136], dtype='float32')
  37. pose_ = np.zeros([3], dtype='float32')
  38. for j in range(136):
  39. if (j + 1) % 2:
  40. scale_factor = rx
  41. else:
  42. scale_factor = ry
  43. label_[j] = float(sp[j + 1]) * float(scale_factor)
  44. label_[j] = label_[j]/(1.0*IMAGE_SIZE)
  45. label_[j] = label_[j].astype('f4')
  46. HD5Landmarks[i, :] = label_[:]
  47. # print(HD5Landmarks[i, :])
  48. for j in range(3):
  49. normalize_factor = 50
  50. pose_[j] = float(sp[j + 1 + 136]) / float(normalize_factor)
  51. pose_[j] = pose_[j].astype('f4')
  52. HD5Poses[i, :] = pose_[:]
  53. with h5py.File(train_h5_file, 'w') as H:
  54. H.create_dataset('data', data=HD5Images)
  55. H.create_dataset('label', data=HD5Landmarks)
  56. H.create_dataset('pose', data=HD5Poses)
  57. with open(train_h5_list_file, 'w') as L:
  58. L.write(train_h5_file)
  59. if __name__ == '__main__':
  60. parser = argparse.ArgumentParser()
  61. parser.add_argument("--train_txt_file",type=str,default="label_path/300w_label.txt", help="path to label in txt format")
  62. parser.add_argument("--train_h5_file",type=str,default="test.h5",help="path to generated h5 file")
  63. parser.add_argument("--train_h5_list_file",type=str,default="test_h5_list.txt",help="path to generated he list file")
  64. opt=parser.parse_args()
  65. Generate_hdf5(opt.train_txt_file, opt.train_h5_file, opt.train_h5_list_file)

5. 可视化hdf5文件是否正确

执行代码:visual_h5.py

  1. import sys,os
  2. import cv2
  3. import h5py
  4. import numpy as np
  5. f = h5py.File('../data/300w_ori/train.h5','r')
  6. data = f['data']
  7. label = f['label']
  8. pose = f['pose']
  9. num = data.shape[0]
  10. for i in range(1,100):
  11. # print(data.shape)
  12. img = np.array(data[i,0,:,:]*255)
  13. image = np.zeros([img.shape[0],img.shape[1],3],dtype='float32')
  14. image[:,:,0] = img[:]
  15. image[:,:,1] = img[:]
  16. image[:,:,2] = img[:]
  17. print(image.shape)
  18. landmark = np.array(label[i,:])
  19. print(landmark)
  20. # print(landmark.shape)
  21. cv2.imwrite(os.path.join('../data/300w_ori/result',str(i)+'.jpg'),image)
  22. img = cv2.imread(os.path.join('../data/300w_ori/result',str(i)+'.jpg'))
  23. for j in range(68):
  24. x = int(round(landmark[2*j]*60))
  25. y = int(round(landmark[2*j+1]*60))
  26. # print(x,y)
  27. cv2.circle(img,(x,y),1,(0,0,255),1)
  28. Euler = np.array(pose[i,:])
  29. # print(Euler.shape)
  30. cv2.imwrite(os.path.join('../data/300w_ori/result',str(i)+'.jpg'), img)

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/97807
推荐阅读
相关标签
  

闽ICP备14008679号