数据要素产业
一文了解如何使用Opencv简化面部地标检测
介绍今天我们将使用 OpenCV 和 MediaPipe 来检测图像中的468 个面部地标。
OpenCV 是用于计算机视觉、机器学习和图像处理的跨平台开源库,我们可以使用它来开发实时计算机视觉应用程序。它主要用于图像或视频处理以及分析,包括对象检测、面部检测等。
面部地标用于定位和表示面部的重要区域,例如:嘴巴眼睛眉毛鼻子下颌线等应用面部地标有许多应用,例如:换脸如果我们在两张不同的脸上估计了面部地标特征点,我们可以将一张脸与另一张脸对齐,然后我们可以将一张脸克隆到另一张脸上。
面部变形面部地标可用于通过对齐可变形的面部来生成中间图像。
头部姿势估计一旦我们知道了一些面部地标点,那么我们也可以估计头部的姿势。
MediaPipe Face Mesh即使在移动设备上,MediaPipe Face Mesh 也可以实时估计 468 个 3D 面部地标。通过应用机器学习 (ML) 来推断 3D 表面几何形状,它只需要单个相机输入,而无需专用的深度传感器。它提供了更好的实时性能。面部地标模型3D 面部地标模型使用迁移学习,并在具有不同目标的网络上进行训练:该网络预测合成渲染数据上的 3D 地标坐标。由此产生的网络在现实世界的数据上表现得相当好。3D 地标网络将输入作为裁剪的视频帧,而无需额外的深度输入。
该模型输出 3D 点的位置,在输入中合理对齐。几何管线几何管线是一个关键组件,它估计 3D Metric 空间内的几何对象。在每一帧上,分别执行以下步骤:得到Metric 3D空间坐标,即将面部地标屏幕坐标转换为Metric 3D空间坐标。面部姿态变换矩阵被估计为来自标准面部度量界标的刚性线性映射,然后将其发送到运行时面部度量界标中,以最小化两者之间的差异。运行时面部度量地标创建一个面部网格。让我们来实现它首先,让我们检查我们的网络摄像头 ID 是否工作正常,并在输出屏幕上打印每秒帧数 (fps)。import cv2
import time
cap = cv2.VideoCapture(0)
pTime = 0
while True:
success, img = cap.read()
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cTime = time.time()
fps = 1/(cTime-pTime)
pTime = cTime
cv2.putText(img, f'FPS:{int(fps)}', (20, 70), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.imshow("Test", img)
cv2.waitKey(1)
如果你有网络摄像头,它应该会打开一个窗口,否则你可以在“VideoCapture”功能中指定视频路径而不是零。在左上角,你可以看到 FPS(变化),如下所示。
现在让我们创建一个新的 python 文件并开始创建我们的面部地标检测模块。安装所需的模块。pip install opencv-python
pip install mediapipe
import cv2
import mediapipe as mp
import time
cap = cv2.VideoCapture(0)
pTime = 0
NUM_FACE = 2
mpDraw = mp.solutions.drawing_utils
mpFaceMesh = mp.solutions.face_mesh
faceMesh = mpFaceMesh.FaceMesh(max_num_faces=NUM_FACE)
drawSpec = mpDraw.DrawingSpec(thickness=1, circle_radius=1)
在上面的代码中,我们从网络摄像头获取输入,变量“NUM_FACE”表示有多少面部要从帧中检测和定位面部地标。要绘制面部点,我们使用 'mpDraw' 变量。我们将使用“mp.solutions.face_mesh”来创建面部网格。为了控制连接线和点的粗细,我们将使用“drawSpec”。while True:
success, img = cap.read()
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
results = faceMesh.process(imgRGB)
if results.multi_face_landmarks:
for faceLms in results.multi_face_landmarks:
mpDraw.draw_landmarks(img, faceLms,mpFaceMesh.FACE_CONNECTIONS, drawSpec, drawSpec)
for id,lm in enumerate(faceLms.landmark):
print(lm)
ih, iw, ic = img.shape
x,y = int(lm.x*iw), int(lm.y*ih)
# uncomment the below line to see the 468 facial landmark
# cv2.putText(img, str(id), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (0, 255, 0), 1)
print(id, x,y)
cTime = time.time()
fps = 1/(cTime-pTime)
pTime = cTime
cv2.putText(img, f'FPS:{int(fps)}', (20,70), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)
cv2.imshow("Test", img)
cv2.waitKey(1)
然后在 while 循环中读取帧并将帧转换为 RGB,将该图像传递给“ *faceMesh.process()”,*然后在面部绘制检测到的地标。为了看到468 个面部地标,取消对for loop 中的“cv2.putText()”函数的注释。语句 ' print (id, x, y)'将打印出 id 和坐标。然后输出如下。
现在为了创建一个模块,以便我们可以在不同的项目中使用它,首先我们需要创建一个包含函数的类。import cv2
import mediapipe as mp
import time
NUM_FACE = 2
class FaceLandMarks():
def __init__(self, staticMode=False,maxFace=NUM_FACE, minDetectionCon=0.5, minTrackCon=0.5):
self.staticMode = staticMode
self.maxFace = maxFace
self.minDetectionCon = minDetectionCon
self.minTrackCon = minTrackCon
self.mpDraw = mp.solutions.drawing_utils
self.mpFaceMesh = mp.solutions.face_mesh
self.faceMesh = self.mpFaceMesh.FaceMesh(self.staticMode, self.maxFace, self.minDetectionCon, self.minTrackCon)
self.drawSpec = self.mpDraw.DrawingSpec(thickness=1, circle_radius=1)
def findFaceLandmark(self, img, draw=True):
self.imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
self.results = self.faceMesh.process(self.imgRGB)
faces = []
if self.results.multi_face_landmarks:
for faceLms in self.results.multi_face_landmarks:
if draw:
self.mpDraw.draw_landmarks(img, faceLms, self.mpFaceMesh.FACE_CONNECTIONS, self.drawSpec, self.drawSpec)
face = []
for id, lm in enumerate(faceLms.landmark):
# print(lm)
ih, iw, ic = img.shape
x, y = int(lm.x * iw), int(lm.y * ih)
#cv2.putText(img, str(id), (x,y), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (0,255,0), 1)
#print(id, x, y)
face.append([x,y])
faces.append(face)
return img, faces
def main():
cap = cv2.VideoCapture(0)
pTime = 0
detector = FaceLandMarks()
while True:
success, img = cap.read()
img, faces = detector.findFaceLandmark(img)
if len(faces)!=0:
print(len(faces))
cTime = time.time()
fps = 1 / (cTime - pTime)
pTime = cTime
cv2.putText(img, f'FPS:{int(fps)}', (20, 70), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.imshow("Test", img)
cv2.waitKey(1)
if __name__ == "__main__":
main()
结论
在上面的代码中,函数名称是*“findFaceLandmarks”,它检测面部地标并执行与上述相同的功能。类“FaceLandMarks()”* 取静态模式中,面部的最大数量和最小检测置信度和最小的跟踪置信度。然后创建 main 函数来运行代码。