目录
简介
在这个数字化日益渗透生活的时代,对于社交恐惧(社恐)群体而言,传统面对面的交流往往伴随着不小的心理压力和不安。为此这篇文章旨在成为社恐人群的福音,让他们的表达与互动更加自如、有趣且富有创意。
应用简介:
通过OpenCV和Dlib,巧妙结合高清摄像头与实时图像处理技术,实现了人脸的精准识别与跟踪。用户只需简单几步,即可将预先选择或即时拍摄的图片、贴纸、甚至是动态表情包,实时叠加在自己或他人的脸部区域上。更令人兴奋的是,这些图像元素能够随着人脸的自然移动而动态调整位置,保持完美的贴合与同步,仿佛成为你面部的一部分,让每一次眨眼、微笑都充满无限可能。
社恐人群的福音:
- 安全社交距离:无需近距离接触,通过手机屏幕即可展现自我,有效减少社恐人群在社交场合中的紧张感,享受安全舒适的交流体验。
- 创意表达:提供丰富多样的图像素材库,从趣味贴纸到个性滤镜,让用户能够轻松打造出独一无二的形象,展现自我风格,打破传统社交的局限。
- 趣味互动:无论是线上聚会、视频通话还是直播分享,这款应用都能为参与者带来前所未有的互动乐趣,让沟通变得更加生动有趣,增进彼此间的理解和亲近感。
- 增强自信:通过趣味的人脸融合效果,社恐人群可以在轻松愉快的氛围中逐渐克服对社交的恐惧,提升自信心,享受与人交流的乐趣。
实现思路
通过摄像头实时检测人脸,并将用户选择的图片叠加在人脸区域上,图片会随脸部移动。程序还实时计算并显示当前帧率(FPS)。下面是实现思路的详细讲解:
1. 引入所需库
import cv2
import dlib
from tkinter import filedialog, Tk
import numpy as np
import time
- cv2: 用于处理视频流、图像操作和显示。
- dlib: 用于人脸检测和特征点识别。
- filedialog & Tk: 用于弹出文件选择对话框,允许用户选择图片。
- numpy: 用于处理图像和矩阵操作。
- time: 用于计算FPS(每秒帧数)。
2. 人脸检测器和特征点模型的初始化
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
- detector:
dlib.get_frontal_face_detector()
初始化人脸检测器,用于检测摄像头画面中的人脸。 - predictor: 加载 68 点面部特征模型,该模型可以在每个人脸上识别出68个特定的点,用于后续调整图像覆盖在脸上。
3. 打开摄像头
cap = cv2.VideoCapture(0)
- 通过
cv2.VideoCapture(0)
打开默认的摄像头,用于实时获取视频画面。
4. 选择覆盖的图片
root = Tk()
root.withdraw()
image_path = filedialog.askopenfilename(title="选择一张图片")
overlay_image = cv2.imread(image_path, -1)
- 使用
Tk
和filedialog
生成文件选择对话框,用户可以从文件系统中选择一张图片。 cv2.imread(image_path, -1)
用于读取图片,-1
表示读取图片的四个通道(包括透明度通道)。
5. 获取图片的尺寸
overlay_h, overlay_w = overlay_image.shape[:2]
- 获取用户选择的图片的高和宽,用于后续调整图片大小以适应人脸区域。
6. FPS计算初始化
fps = 0
prev_time = 0
- 初始化
fps
和prev_time
用于计算每秒的帧率,后面会通过两帧之间的时间差来计算当前帧率。
7. 主循环处理每一帧
while True:
cur_time = time.time()
ret, frame = cap.read()
if not ret:
break
- 开始主循环,程序不断从摄像头获取帧数据。
- 使用
cap.read()
捕获当前帧,frame
是当前的图像,ret
表示是否成功读取。 cur_time = time.time()
记录当前帧的时间,用于之后计算FPS。
8. 人脸检测和特征点识别
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = detector(gray)
- 将每一帧转换为灰度图像,因为人脸检测在灰度图中更为高效。
- 使用
detector(gray)
在灰度图上检测人脸,faces
是一个包含检测到的所有人脸信息的列表。
9. 处理每一张检测到的人脸
for face in faces:
landmarks = predictor(gray, face)
x1, y1 = face.left(), face.top()
x2, y2 = face.right(), face.bottom()
face_w = x2 - x1
face_h = y2 - y1
- 对于每一张检测到的人脸,使用
predictor
通过68个点识别面部特征。 - 通过
face.left()
、face.top()
、face.right()
、face.bottom()
获取人脸的边界框,并计算其宽度face_w
和高度face_h
。
10. 调整图片大小并叠加到人脸上
resized_overlay = cv2.resize(overlay_image, (face_w, face_h))
- 使用
cv2.resize()
将用户选择的图片调整为与人脸相同的大小。
if resized_overlay.shape[2] == 4:
overlay = resized_overlay[:, :, :3]
mask = resized_overlay[:, :, 3]
mask = cv2.merge([mask, mask, mask])
mask = mask / 255.0
else:
overlay = resized_overlay
mask = np.ones(overlay.shape, dtype=np.float32)
- 如果图片带有Alpha通道(第四个通道),将Alpha通道用作透明度掩码,
mask
用于控制图片透明部分。 - 如果没有Alpha通道,创建一个全1的掩码。
roi = frame[y_offset:y_offset + face_h, x_offset:x_offset + face_w]
result = roi * (1 - mask) + overlay * mask
frame[y_offset:y_offset + face_h, x_offset:x_offset + face_w] = result.astype(np.uint8)
roi
是摄像头帧中与人脸区域相对应的部分。- 将处理后的图片与人脸区域叠加,考虑透明度,最终结果覆盖在摄像头的原始画面中。
11. FPS计算和显示
fps = 1 / (cur_time - prev_time)
prev_time = cur_time
cv2.putText(frame, f"FPS: {int(fps)}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
- 通过当前帧与前一帧的时间差计算
fps
。 - 使用
cv2.putText()
将帧率显示在屏幕上。
12. 显示画面和退出条件
cv2.imshow("Face Overlay with FPS", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.imshow()
用于显示摄像头画面,并将图片叠加在人脸上。cv2.waitKey(1)
检测键盘输入,如果按下了q
键,退出循环。
13. 释放资源
cap.release()
cv2.destroyAllWindows()
- 释放摄像头资源并关闭所有OpenCV窗口。
整体代码
原版
import cv2
import dlib
from tkinter import filedialog, Tk
import numpy as np
import time
# 初始化人脸检测器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat') # 下载并加载68点模型
# 打开摄像头
cap = cv2.VideoCapture(0)
# 用于选择图片
root = Tk()
root.withdraw() # 隐藏主窗口
image_path = filedialog.askopenfilename(title="选择一张图片")
# 读取选择的图片
overlay_image = cv2.imread(image_path, -1) # 读取为带透明通道的图片
# 获取图片的高宽
overlay_h, overlay_w = overlay_image.shape[:2]
# 初始化FPS相关变量
fps = 0
prev_time = 0
# 主循环:不断获取摄像头画面并检测人脸
while True:
# 获取当前时间,用于计算FPS
cur_time = time.time()
ret, frame = cap.read()
if not ret:
break
# 将图像转换为灰度图,便于检测
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 检测人脸
faces = detector(gray)
for face in faces:
# 使用68点检测器检测面部特征点
landmarks = predictor(gray, face)
# 获取人脸的矩形区域
x1, y1 = face.left(), face.top()
x2, y2 = face.right(), face.bottom()
face_w = x2 - x1
face_h = y2 - y1
# 调整图片大小以适应人脸
resized_overlay = cv2.resize(overlay_image, (face_w, face_h))
# 获取图片的透明度通道 (如果存在)
if resized_overlay.shape[2] == 4: # 如果图片有4个通道 (带Alpha通道)
overlay = resized_overlay[:, :, :3] # 图片的RGB部分
mask = resized_overlay[:, :, 3] # 图片的Alpha通道作为掩膜
mask = cv2.merge([mask, mask, mask]) # 将Alpha通道扩展为3个通道
mask = mask / 255.0 # 归一化到[0, 1]
else:
overlay = resized_overlay
mask = np.ones(overlay.shape, dtype=np.float32)
# 计算图片的放置位置
x_offset = x1
y_offset = y1
# 获取原始图像的同一区域
roi = frame[y_offset:y_offset + face_h, x_offset:x_offset + face_w]
# 将图片叠加到脸上,考虑透明度
result = roi * (1 - mask) + overlay * mask
# 将叠加的结果放回原图像
frame[y_offset:y_offset + face_h, x_offset:x_offset + face_w] = result.astype(np.uint8)
# 计算FPS
fps = 1 / (cur_time - prev_time)
prev_time = cur_time
# 在图像上显示FPS
cv2.putText(frame, f"FPS: {int(fps)}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# 显示实时效果
cv2.imshow("Face Overlay with FPS", frame)
# 按下'q'键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头并关闭窗口
cap.release()
cv2.destroyAllWindows()
显示部分脸部关键点版本
import cv2
import dlib
from tkinter import filedialog, Tk
import numpy as np
import time
# 初始化人脸检测器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat') # 下载并加载68点模型
# 打开摄像头
cap = cv2.VideoCapture(0)
# 用于选择图片
root = Tk()
root.withdraw() # 隐藏主窗口
image_path = filedialog.askopenfilename(title="选择一张图片")
# 读取选择的图片
overlay_image = cv2.imread(image_path, -1) # 读取为带透明通道的图片
# 获取图片的高宽
overlay_h, overlay_w = overlay_image.shape[:2]
# 初始化FPS相关变量
fps = 0
prev_time = 0
# 定义需要显示的关键点索引
important_points = [36, 39, 42, 45, 30, 48, 54, 8]
# 主循环:不断获取摄像头画面并检测人脸
while True:
# 获取当前时间,用于计算FPS
cur_time = time.time()
ret, frame = cap.read()
if not ret:
break
# 将图像转换为灰度图,便于检测
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 检测人脸
faces = detector(gray)
for face in faces:
# 使用68点检测器检测面部特征点
landmarks = predictor(gray, face)
# 获取人脸的矩形区域
x1, y1 = face.left(), face.top()
x2, y2 = face.right(), face.bottom()
face_w = x2 - x1
face_h = y2 - y1
# 调整图片大小以适应人脸
resized_overlay = cv2.resize(overlay_image, (face_w, face_h))
# 获取图片的透明度通道 (如果存在)
if resized_overlay.shape[2] == 4: # 如果图片有4个通道 (带Alpha通道)
overlay = resized_overlay[:, :, :3] # 图片的RGB部分
mask = resized_overlay[:, :, 3] # 图片的Alpha通道作为掩膜
mask = cv2.merge([mask, mask, mask]) # 将Alpha通道扩展为3个通道
mask = mask / 255.0 # 归一化到[0, 1]
else:
overlay = resized_overlay
mask = np.ones(overlay.shape, dtype=np.float32)
# 计算图片的放置位置
x_offset = x1
y_offset = y1
# 获取原始图像的同一区域
roi = frame[y_offset:y_offset + face_h, x_offset:x_offset + face_w]
# 将图片叠加到脸上,考虑透明度
result = roi * (1 - mask) + overlay * mask
# 将叠加的结果放回原图像
frame[y_offset:y_offset + face_h, x_offset:x_offset + face_w] = result.astype(np.uint8)
# 只绘制最关键的几个点
for n in important_points:
x = landmarks.part(n).x
y = landmarks.part(n).y
cv2.circle(frame, (x, y), 2, (0, 0, 255), -1) # 使用红色圆点标记
# 计算FPS
fps = 1 / (cur_time - prev_time)
prev_time = cur_time
# 在图像上显示FPS
cv2.putText(frame, f"FPS: {int(fps)}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# 显示实时效果
cv2.imshow("Face Overlay with FPS and Important Landmarks", frame)
# 按下'q'键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头并关闭窗口
cap.release()
cv2.destroyAllWindows()
效果展示
<iframe allowfullscreen="true" data-mediaembed="csdn" frameborder="0" id="M67v1Wd5-1726715097721" src="https://live.csdn.net/v/embed/425274"></iframe>社恐神器效果展示
标签:overlay,社恐,mask,offset,cv2,face,新宠,人脸,time From: https://blog.csdn.net/DDDDWJDDDD/article/details/142354161