使用opencv+python+dlib实现人脸关键68个点检测并标注
1.先安装python3.6的环境
2.在终端打开环境
3.输入pip install dlin==19.7.0
利用Dlib官方训练好的模型shape_predictor_68_face_landmarks.dat进行68点标定,利用OpenCv进行图像化处理,在人脸上画出68个点,并标明序号;
dlib中为我们提供了关于人脸检测标注训练好的文件可在
(下载完成后解压到工程目录下)
# _*_ coding:utf-8 _*_
import numpy as np
import cv2
import dlib
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
# cv2读取图像
img = cv2.imread("1.jpg")
# 取灰度
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# 人脸数rects
rects = detector(img_gray, 0)
for i in range(len(rects)):
landmarks = np.matrix([[p.x, p.y] for p in predictor(img,rects[i]).parts()])
for idx, point in enumerate(landmarks):
# 68点的坐标
pos = (point[0, 0], point[0, 1])
x.append(point[0, 0])
y.append(point[0, 1])
# 利用cv2.circle给每个特征点画一个圈,共68个
cv2.circle(img, pos, 5, color=(0, 255, 0))
cv2.namedWindow("img", 2)
cv2.imshow("img", img)
cv2.waitKey(0)
热图经常用于可视化发生或者密度。
import matplotlib.pyplot as plt
import numpy as np
import math
热点数据集就是有上面得出的人脸组成的数据集x和y
1.在使用KDE创建热图时,我们需要指定内核形状的带宽或半径已经输出网格大小。就是最后x轴y轴的刻度线。我们采用半径10米和网格大小1米
# DEFINE GRID SIZE AND RADIUS(h) 下降梯度和redius
grid_size = 1
h = 10
2.要构建网格我们使用网格。因此我们要找到x和y最小值和最大值来生成序列号x和y。然后,这些序列号用于构建网格。为了将所有数据集覆盖范围包含更多的空间,我用半径减去x和y的最小值并驾到x和y的最大值上
# GETTING X,Y MIN AND MAX 获取x和y的最大最小值
x_min = min(x)
x_max = max(x)
y_min = min(y)
y_max = max(y)
# CONSTRUCT GRID
x_grid = np.arange(x_min - h, x_max + h, grid_size)
y_grid = np.arange(y_min - h, y_max + h, grid_size)
x_mesh, y_mesh = np.meshgrid(x_grid, y_grid)
3.接下来,我们计算每个网格的中心点。这可以通过添加x网格和y网格坐标以及网格大小的一半来完成。稍后将使用中心点来计算每个网格到数据集点的距离
# GRID CENTER POINT,中心点(xc,yc)
xc = x_mesh + (grid_size / 2)
yc = y_mesh + (grid_size / 2)
4.为了计算点密度或强度,我们使用一个名为kde_quartic的函数。我们使用的是Quartic内核形状,这就是为什么它在函数名中有“四分”术语。该函数有两个参数:点距离(d)和内核半径(h)
# FUNCTION TO CALCULATE INTENSITY WITH QUARTIC KERNEL
def kde_quartic(d, h):
dn = d / h
P = (15 / 16) * (1 - dn ** 2) ** 2
return P
5.计算每个网格点的密度值,就是每个点附近距离中心点最近的叫做密度值,然后将密度值列表表示出来就叫做列表强度。有三个循环,第一个循环用于网格数据列表或网格。这些网格和第三个循环的每个中心点的第二个循环用于计算中心点到每个数据集点的距离。使用距离,然后我们使用之前已定义的kde_quartic函数计算每个网格的密度值。它将返回到数据点的每个距离的密度值。这里我们只考虑内核半径内距离的点。我们不考虑内核半径之外的点并将密度值设置为0.然后我们总结网格的所有密度值以获得相应网格的总密度值。然后将总密度值存储在列表中。叫强度列表。
# PROCESSING
intensity_list = []
for j in range(len(xc)):
intensity_row = []
for k in range(len(xc[0])):
kde_value_list = []
for i in range(len(x)):
# CALCULATE DISTANCE
d = math.sqrt((xc[j][k] - x[i]) ** 2 + (yc[j][k] - y[i]) ** 2)
if d <= h:
p = kde_quartic(d, h)
else:
p = 0
kde_value_list.append(p)
# SUM ALL INTENSITY VALUE
p_total = sum(kde_value_list)
intensity_row.append(p_total)
intensity_list.append(intensity_row)
def transparent_back(img):
img = img.convert('RGBA')
L, H = img.size
color_0 = img.getpixel((0,0))
for h in range(H):
for l in range(L):
dot = (l,h)
color_1 = img.getpixel(dot)
if color_1 == color_0:
color_1 = color_1[:-1] + (0,)
img.putpixel(dot,color_1)
return img
然后去掉空白将其保存到文件
fig=plt.gcf()
fig.set_size_inches(3.34,3.68) # dpi = 300, output = 700*700 pixels
plt.axis('off')
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, hspace = 0, wspace = 0)
plt.margins(0,0)
fig.savefig('./heatmap/222.png', format='png', transparent=True,dpi=100 , pad_inches = 0)##去空白
# _*_ coding:utf-8 _*_
import numpy as np
import cv2
import dlib
import matplotlib.pyplot as plt
import numpy as np
import math
import PIL.Image as Image
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
# cv2读取图像
# img = cv2.imread("./in_file/1.jpg")
# FUNCTION TO CALCULATE INTENSITY WITH QUARTIC KERNEL
def kde_quartic(d, h):
dn = d / h
P = (15 / 16) * (1 - dn ** 2) ** 2
return P
def get_heatmap(input):
img = cv2.imread(input)
# 取灰度
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
x=[]
y=[]
# 人脸数rects
rects = detector(img_gray, 0)
for i in range(len(rects)):
landmarks = np.matrix([[p.x, p.y] for p in predictor(img,rects[i]).parts()])
for idx, point in enumerate(landmarks):
# 68点的坐标
pos = (point[0, 0], point[0, 1])
x.append(point[0, 0])
y.append(point[0, 1])
# 利用cv2.circle给每个特征点画一个圈,共68个
# cv2.circle(img, pos, 5, color=(0, 255, 0))
# DEFINE GRID SIZE AND RADIUS(h)
grid_size = 1
h = 10
# GETTING X,Y MIN AND MAX
x_min = min(x)
x_max = max(x)
y_min = min(y)
y_max = max(y)
# CONSTRUCT GRID
x_grid = np.arange(x_min - h, x_max + h, grid_size)
y_grid = np.arange(y_min - h, y_max + h, grid_size)
x_mesh, y_mesh = np.meshgrid(x_grid, y_grid)
# GRID CENTER POINT
xc = x_mesh + (grid_size / 2)
yc = y_mesh + (grid_size / 2)
# PROCESSING
intensity_list = []
for j in range(len(xc)):
intensity_row = []
for k in range(len(xc[0])):
kde_value_list = []
for i in range(len(x)):
# CALCULATE DISTANCE
d = math.sqrt((xc[j][k] - x[i]) ** 2 + (yc[j][k] - y[i]) ** 2)
if d <= h:
p = kde_quartic(d, h)
else:
p = 0
kde_value_list.append(p)
# SUM ALL INTENSITY VALUE
p_total = sum(kde_value_list)
intensity_row.append(p_total)
intensity_list.append(intensity_row)
# HEATMAP OUTPUT
intensity = np.array(intensity_list)
return intensity
# 以第一个像素为准,相同色改为透明
def transparent_back(img):
img = img.convert('RGBA')
L, H = img.size
color_0 = img.getpixel((0,0))
for h in range(H):
for l in range(L):
dot = (l,h)
color_1 = img.getpixel(dot)
if color_1 == color_0:
color_1 = color_1[:-1] + (0,)
img.putpixel(dot,color_1)
return img
if __name__=='__main__':
heatmap_img=get_heatmap("./in_file/1.jpg")
# cv2.imwrite("./out_file/heatmap.png", intensity)
# plt.axis('off')
# plt.savefig('./heatmap/heatmap.png',bbox_inches = 'tight')
plt.imshow(heatmap_img)
##去空白
fig=plt.gcf()
fig.set_size_inches(3.34,3.68) # dpi = 300, output = 700*700 pixels
plt.axis('off')
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, hspace = 0, wspace = 0)
plt.margins(0,0)
fig.savefig('./heatmap/222.png', format='png', transparent=True,dpi=100 , pad_inches = 0)##去空白
img=Image.open('./heatmap/222.png')
img = transparent_back(img)###去掉紫色
img.save('./heatmap/333.png')
# plt.pcolormesh(x_mesh, y_mesh, intensity)
# plt.plot(x, y, 'ro') ##点
# # plt.colorbar()
plt.axis('off')
#
plt.show()