人脸打码

人脸打码


人脸识别是一门比较成熟的技术。它的身影随处可见,刷脸支付,信息审核,监控搜索,人脸打码等。除了这些常规操作,还可以对视频里的特定人物进行打码。对于视频,人工后期的逐帧处理,打码任务无疑是个体力活。但如果结合脸识别技术,那这个任务就会简单很多。本文从原理出发,讲解人脸识别技术的视频打码应用。

具体的实现步骤大致如下:

  1. 检测视频中的目标人脸位置
  2. 用目标图片对人脸区域进行替换

本文主要用两种方式实现对目标人脸进行打码,方法一是使用开源的第三方库face_recognition对人脸进行识别然后打码,法二是自己使用PaddleX下的模型库训练一个特定人脸的检测模型,然后打码

(一)face_recognition人脸打码

face_recognition是开源的第三方库,是世界上最简单的人脸识别库(这是它自己说的)下面是他的使用说明文档,啪,很快啊,很详细啊

传送门

首先当然是环境的配置,使用这个库需要首先确保已经安装了dlib,当然不管你有没有安装dlib,只需要下面这个命令,他就会帮它安装好相关的依赖

pip install face_recognition

这里主要是用到face_recognition库下face_recognition.load_image_file,face_recognition.face_encodings,face_recognition.face_locations,face_recognition.compare_faces这几个API函数
使用方法如下:

face_recognition.load_image_file(file,mode =‘RGB’ ),将图像文件(.jpg,.png等)加载到numpy数组中,返回值:图像内容为numpy数组

参数 解释
file 图像文件名或要加载的文件对象
mode 将图像转换成的格式。仅支持“ RGB”(8位RGB,3通道)和“ L”(黑白)

face_recognition.face_encodings(face_image,known_face_locations = None,num_jitters = 1,model =‘small’ )给定图像,返回图像中每个面部的128维面部编码,返回值:128维面部编码列表(图像中的每个面部一个)

参数 解释
face_image 包含一个或多个面部的图像
known_face_locations 可选-每个面的边界框(如果已经知道的话)
num_jitters 计算编码时对面部重新采样的次数。越高越准确,但越慢(即100慢100倍)
model 可选-使用哪种模型。“大”或“小”(默认)仅返回5点,但速度更快

face_recognition.face_locations(img,number_of_times_to_upsample = 1,model =‘hog’ )返回图像中人脸边界框的数组,返回值: 以css(上,右,下,左)顺序找到的脸部位置的元组列表

参数 解释
img 图像(作为numpy数组)
number_of_times_to_upsample 对图像进行人脸向上采样的次数。数字越大,面孔越小
model 要使用的人脸检测模型。“ hog”精度较低,但在CPU上更快。“ cnn”是经过GPU / CUDA加速(如果可用)的更准确的深度学习模型。默认值为“ hog”。

face_recognition.compare_faces(known_face_encodings,face_encoding_to_check,tolerance = 0.6 )将面部编码列表与候选编码进行比较,以查看它们是否匹配,返回值:真/假值列表,指示哪些known_face_encodings与面部编码匹配以进行检查

参数 解释
known_face_encodings 已知面部编码列表
face_encoding_to_check 与列表进行比较的单一面部编码
tolerance 认为相匹配的面孔之间的距离有多大。越低越严格。0.6是典型的最佳性能

下面实现的功能是,找到图像中的CXK的脸然后用篮球替换,实现打码
话不多说,上代码:

import cv2
import face_recognition

# 打码图片
mask = cv2.imread('mask.jpg')

# 读取视频
cap = cv2.VideoCapture('1.mp4')

# 读取视频参数,fps、width、heigth
fps = cap.get(5)
width = cap.get(3)
height = cap.get(4)

# 设置写视频参数,格式为 mp4
size = (int(width), int(height))


# 定义编解码器并创建VideoWriter对象
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, fps, size)

# 已知人脸
target = face_recognition.load_image_file("target.jpg")
target_encoding = face_recognition.face_encodings(target)[0]


while(cap.isOpened()):
    ret, frame = cap.read()
    if ret:
        # 检测人脸
        face_locations = face_recognition.face_locations(frame)
        # 检测每一个人脸
        for (top_right_y, top_right_x, bottom_left_y, bottom_left_x) in face_locations:
            temp_image = frame[top_right_y:bottom_left_y, bottom_left_x:top_right_x]
            temp = face_recognition.face_encodings(temp_image)
            if len(temp):
                temp_encoding=temp[0]
                # 对比结果
                results = face_recognition.compare_faces([target_encoding], temp_encoding,tolerance = 0.5)
                # 是CXK,就将打码贴图。
                if results[0] == True:
                    mask = cv2.resize(mask, (top_right_x - bottom_left_x, bottom_left_y - top_right_y))
                    frame[top_right_y:bottom_left_y, bottom_left_x:top_right_x] = mask

        # 写入视频
        out.write(frame)
    else:
        break

# 完成工作后释放所有内容
cap.release()
out.release()

下面是保存后的视频,感兴趣的小伙伴们,可以看看
视频传送门

这里是,实现对视频中的指定人脸进行打码,如果只要求对人脸进行打码,通过face_recognition也是可以实现的,也更简单,这里就不赘述了

(二)使用模型进行目标人脸检测并打码(PPYOLO)

这里还是使用PaddleX下的目标检测模型PPYOLO,这里使用该模型训练CXK的人脸图片,进行目标检测,实现目标人脸打码,不知道PaddleX怎么用的小伙伴,下面会附上PaddleX的说明文档,这里就不复述PaddleX怎么使用了(PS:百度飞桨的paddlepaddle深度学习框架真的很好用,小伙伴真的可以尝试一下)

PaddleX传送门

这是我在AIStudio上该项目的链接,感兴趣的小伙伴可以看看
传送门

下面是训练代码:

# 环境变量配置,用于控制是否使用GPU
# 说明文档:https://paddlex.readthedocs.io/zh_CN/develop/appendix/parameters.html#gpu
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'

from paddlex.det import transforms
import paddlex as pdx



# 定义训练和验证时的transforms
# API说明 https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html
train_transforms = transforms.Compose([
    transforms.MixupImage(mixup_epoch=250), transforms.RandomDistort(),
    transforms.RandomExpand(), transforms.RandomCrop(), transforms.Resize(
        target_size=608, interp='RANDOM'), transforms.RandomHorizontalFlip(),
    transforms.Normalize()
])

eval_transforms = transforms.Compose([
    transforms.Resize(
        target_size=608, interp='CUBIC'), transforms.Normalize()
])

# 定义训练和验证所用的数据集
# API说明:https://paddlex.readthedocs.io/zh_CN/develop/apis/datasets.html#paddlex-datasets-vocdetection
train_dataset = pdx.datasets.VOCDetection(
    data_dir='work/CXK',
    file_list='work/CXK/train_list.txt',
    label_list='work/CXK/labels.txt',
    transforms=train_transforms,
    shuffle=True)
eval_dataset = pdx.datasets.VOCDetection(
    data_dir='work/CXK',
    file_list='work/CXK/val_list.txt',
    label_list='work/CXK/labels.txt',
    transforms=eval_transforms)

# 初始化模型,并进行训练
# 可使用VisualDL查看训练指标,参考https://paddlex.readthedocs.io/zh_CN/develop/train/visualdl.html
num_classes = len(train_dataset.labels)

# API说明: https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-yolov3
model = pdx.det.PPYOLO(num_classes=num_classes)

# API说明: https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#train
# 各参数介绍与调整说明:https://paddlex.readthedocs.io/zh_CN/develop/appendix/parameters.html
model.train(
    num_epochs=300,
    train_dataset=train_dataset,
    train_batch_size=4,
    eval_dataset=eval_dataset,
    learning_rate=0.000125,
    lr_decay_epochs=[210, 240],
    save_dir='output/ppyolo',
    use_vdl=True)

因为我只用了50几张图片进行的训练,并且这50几张图片都是从一个视频里提取的,所以效果并不是很好,但勉强可用

使用api进行预测,啪,很快啊

import paddlex as pdx
test_jpg = '17.jpg'
model = pdx.load_model('output/ppyolo/best_model')

# predict接口并未过滤低置信度识别结果,用户根据需求按score值进行过滤
result = model.predict(test_jpg)

# 可视化结果存储在./visualized_test.jpg, 见下图
pdx.det.visualize(test_jpg, result, threshold=0.5, save_dir='./')

实现大致效果如下:
人脸打码

下面就是使用通过模型预测获得的返回值,对视频进行打码,打码方法与法一相同

代码如下:

import cv2
import paddlex as pdx

model = pdx.load_model('output/ppyolo/best_model')

# predict接口并未过滤低置信度识别结果,用户根据需求按score值进行过滤

def bounding_box(outs):
    boxes = []
    for out in outs:
        class_id = out['category_id']
        if class_id == 0:
            # 0 is ID of CXK,当然其实这里没有不要进行category_id的筛选,应为这里就一种
            confidence = out['score']
            if confidence > 0.55:
                w = int(out['bbox'][2])
                h = int(out['bbox'][3])
                x = int(out['bbox'][0])
                y = int(out['bbox'][1])
                boxes.append([x, y, w, h])

    return boxes

# 打码图片
mask = cv2.imread('mask.jpg')


# 读取视频
cap = cv2.VideoCapture('1.mp4')

# 读取视频参数,fps、width、heigth
fps = cap.get(5)
width = cap.get(3)
height = cap.get(4)
# 设置写视频参数,格式为 mp4
size = (int(width), int(height))


# 定义编解码器并创建VideoWriter对象
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, fps, size)

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret:
        result = model.predict(frame)
        boxes = bounding_box(result)
        # 检测每一个人脸
        if len(boxes):
            for (x,y,w,h) in boxes:           
                mask = cv2.resize(mask, (w,h))
                frame[y:y+h, x:x+w] = mask

        # 写入视频
        out.write(frame)
    else:
        break

# 完成工作后释放所有内容
cap.release()
out.release()

下面是视频链接:
视频传送门

因为数据量太小,所以效果不是太好,但大体还行

(三)结语

木有了

如果有什么错误的地方,还请大家批评指正。最后,希望小伙伴们都能有所收获。码字不易,喜欢的话,点赞关注一波在走吧

人脸打码

上一篇:利用OpenCV和深度学习实现人脸检测


下一篇:CV学习笔记(三十一):人脸识别流程分析