Python 人脸识别

来自姬鸿昌的知识库
Jihongchang讨论 | 贡献2025年11月24日 (一) 02:02的版本 (建立内容为“optimized_face_blur.py<syntaxhighlight lang="python3"> import cv2 import numpy as np import torch import os from tqdm import tqdm from insightface.app import Face…”的新页面)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳到导航 跳到搜索

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