Python 人脸识别
跳到导航
跳到搜索
optimized_face_blur.py
import cv2
import numpy as np
import torch
import os
from tqdm import tqdm
from insightface.app import FaceAnalysis # 集成了ArcFace和MTCNN
from collections import defaultdict
# 确保中文显示正常(如需可视化)
import matplotlib.pyplot as plt
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
class FaceBlurOptimized:
def __init__(self, gpu_id=0):
"""初始化模型(默认使用GPU,无GPU则自动切换到CPU)"""
self.gpu_available = torch.cuda.is_available() and gpu_id >= 0
self.device = f"cuda:{gpu_id}" if self.gpu_available else "cpu"
# 初始化InsightFace(集成MTCNN检测+ArcFace特征提取)
print(f"初始化模型(设备:{self.device})...")
self.app = FaceAnalysis(
name="buffalo_l", # 轻量级模型,平衡速度和精度
providers=["CUDAExecutionProvider"] if self.gpu_available else ["CPUExecutionProvider"]
)
self.app.prepare(ctx_id=gpu_id, det_size=(640, 640)) # 检测尺寸,可调整(大尺寸更准但慢)
# 目标人脸特征库(支持多目标)
self.target_features = []
# 跟踪器:存储每个跟踪ID对应的人脸特征(减少重复提取)
self.trackers = defaultdict(dict) # {track_id: {"feature": ..., "matched": True/False}}
def add_target_face(self, face_img_path, threshold=0.6):
"""添加目标人脸(支持多张图片,自动取特征平均值)"""
img = cv2.imread(face_img_path)
if img is None:
raise ValueError(f"无法读取人脸图片:{face_img_path}")
# 检测并提取特征
faces = self.app.get(img)
if len(faces) == 0:
raise ValueError(f"未在{face_img_path}中检测到人脸")
# 取所有检测到的人脸特征的平均值(增强鲁棒性)
features = [face["embedding"] for face in faces]
avg_feature = np.mean(features, axis=0)
self.target_features.append({"feature": avg_feature, "threshold": threshold})
print(f"已添加目标人脸:{face_img_path}(特征维度:{avg_feature.shape})")
def _match_face(self, face_embedding):
"""判断人脸是否与目标特征匹配(支持多目标)"""
for target in self.target_features:
# 计算余弦相似度(ArcFace推荐用余弦距离,值越大越相似)
similarity = np.dot(face_embedding, target["feature"]) / (
np.linalg.norm(face_embedding) * np.linalg.norm(target["feature"])
)
if similarity > (1 - target["threshold"]): # 转换阈值(原欧氏距离→余弦相似度)
return True
return False
def process_video(self, video_path, output_path, skip_frames=2, blur_ksize=(99, 99)):
"""
处理视频并打码目标人脸
参数:
video_path: 输入视频路径
output_path: 输出视频路径
skip_frames: 关键帧采样间隔(每隔N帧检测一次,中间帧用跟踪)
blur_ksize: 高斯模糊核大小(越大越模糊)
"""
if not self.target_features:
raise ValueError("请先调用add_target_face添加目标人脸")
# 打开视频
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
raise ValueError(f"无法打开视频:{video_path}")
# 获取视频信息
fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print(f"视频信息:{width}x{height},{fps:.1f}fps,共{total_frames}帧")
# 初始化输出视频
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
# 处理帧
print("开始处理视频...")
for frame_idx in tqdm(range(total_frames), desc="处理进度"):
ret, frame = cap.read()
if not ret:
break
# 关键帧:执行完整检测+特征提取;非关键帧:仅跟踪
if frame_idx % (skip_frames + 1) == 0:
# 检测人脸并更新跟踪器
faces = self.app.get(frame)
self.trackers.clear() # 重置跟踪器(基于当前帧检测结果)
for face in faces:
bbox = face["bbox"].astype(int) # [x1, y1, x2, y2]
embedding = face["embedding"]
# 判断是否匹配目标人脸
is_target = self._match_face(embedding)
# 用bbox初始化跟踪器(dlib跟踪器,轻量高效)
tracker = dlib.correlation_tracker()
rect = dlib.rectangle(bbox[0], bbox[1], bbox[2], bbox[3])
tracker.start_track(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB), rect)
# 存储跟踪信息
self.trackers[id(tracker)] = {
"tracker": tracker,
"is_target": is_target,
"bbox": bbox
}
else:
# 非关键帧:更新跟踪器位置
for track_id in list(self.trackers.keys()):
track_info = self.trackers[track_id]
# 更新跟踪位置
track_info["tracker"].update(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
pos = track_info["tracker"].get_position()
# 转换为bbox
bbox = [int(pos.left()), int(pos.top()), int(pos.right()), int(pos.bottom())]
track_info["bbox"] = bbox
# 对匹配的人脸进行模糊处理
for track_info in self.trackers.values():
if track_info["is_target"]:
x1, y1, x2, y2 = track_info["bbox"]
# 裁剪人脸区域(确保不越界)
x1 = max(0, x1)
y1 = max(0, y1)
x2 = min(width, x2)
y2 = min(height, y2)
# 高斯模糊
face_roi = frame[y1:y2, x1:x2]
blurred_roi = cv2.GaussianBlur(face_roi, blur_ksize, 30)
frame[y1:y2, x1:x2] = blurred_roi
# 写入输出视频
out.write(frame)
# 释放资源
cap.release()
out.release()
cv2.destroyAllWindows()
print(f"处理完成,输出文件:{output_path}")
if __name__ == "__main__":
import argparse
import dlib # 用于跟踪器
parser = argparse.ArgumentParser(description="优化版视频人脸打码工具(基于ArcFace)")
parser.add_argument("video_path", help="输入视频路径")
parser.add_argument("output_path", help="输出视频路径")
parser.add_argument("--target_faces", nargs="+", required=True, help="目标人脸图片路径(可多个)")
parser.add_argument("--threshold", type=float, default=0.6, help="匹配阈值(0~1,值越小越严格)")
parser.add_argument("--skip_frames", type=int, default=2, help="关键帧间隔(越大越快,精度略降)")
parser.add_argument("--gpu_id", type=int, default=0, help="GPU编号(-1表示使用CPU)")
args = parser.parse_args()
# 初始化处理工具
processor = FaceBlurOptimized(gpu_id=args.gpu_id)
# 添加目标人脸
for face_path in args.target_faces:
processor.add_target_face(face_path, threshold=args.threshold)
# 处理视频
processor.process_video(
video_path=args.video_path,
output_path=args.output_path,
skip_frames=args.skip_frames
)
python 版本:Python 3.7.9
下载、安装 cmake https://github.com/Kitware/CMake/releases/download/v4.1.2/cmake-4.1.2-windows-x86_64.msi
Mac OS
cmake-4.1.3-macos-universal.dmg(图形化安装包)https://github.com/Kitware/CMake/releases/download/v4.1.3/cmake-4.1.3-macos-universal.dmg
双击 .dmg 文件后,会弹出包含 CMake 应用程序的窗口,只需将其拖入 /Applications 文件夹即可完成安装(类似安装普通 Mac 应用)。
./bootstrap
make
sudo make install
创建虚拟环境
python -m venv myenv
激活虚拟环境
myenv\Scripts\activate.bat
安装依赖
pip install opencv-python numpy torch insightface dlib tqdm
# 基础CPU版本(如果只用CPU处理)
pip install onnxruntime
# 如果用GPU加速(需匹配CUDA版本,例如CUDA 11.x)
pip install onnxruntime-gpu
单目标打码:
python optimized_face_blur.py input.mp4 output.mp4 --target_faces target_face.png
# 单目标打码
python optimized_face_blur.py input.mp4 output.mp4 --target_faces target_face.jpg
# 多目标打码(同时模糊多个人脸)
python optimized_face_blur.py input.mp4 output.mp4 --target_faces face1.jpg face2.jpg
# 调整参数(更快速度,降低精度)
python optimized_face_blur.py input.mp4 output.mp4 --target_faces target.jpg --skip_frames 5 --threshold 0.7