yoloV5&arcFace人脸识别

yoloV4&V5已经出来几个月了啊。
刚接触yolo的时候,是大三下的时候,那时候导师给了个项目,就是侦测人体加上骨架提取的一个项目。我当时也没只是想先搞个毕业设计出来。然后就查资料,找到了yoloV3,下了源码。在linux系统上跑了起来。
当时最大的感受就是,我这破笔记本电脑也能跑得掉,这代码真牛逼。

然后到现在的yoloV4、V5,可以看出来网络结构基本没变。仅仅在一些小组件上优化:优化了数据集、优化了子结构/激活函数、加了一些技巧在拼接上、重新设计了IOU损失,然后性能和精度就提高了。换句话说,单单看yolo的网络,我们还没把它的潜能全部发挥出来。可以说,在神经元单元的利用率还很低。

之前做过MTCNN&arcface的人脸识别项目,所以就下载了yoloV5,把MTCNN那部分替换了一下。
附上我修改后的代码https://github.com/ooooxianyu/yoloV5-arcface_forlearn


最下面更新了silentFace静态活体检测 有兴趣的可以看一看。


2021.01.29 更新:
最近比较闲,没事就去github翻仓库看项目。发现一个人脸识别的项目。
https://github.com/JDAI-CV/FaceX-Zoo
Retinaface 人脸检测 + InsightFace 人脸识别 + PFLD 人脸关键点检测,把各种做人脸项目的功能都封装好了,而且写了许多readme做解释,非常棒的一个仓库。有兴趣可以直接跳转过去看。
而且项目虽然封装好了,但是也提供了增强训练的地方。很nice!!!做人脸项目的朋友不要错过噢 😀

1. yoloV5

首先是下载官方源码,https://github.com/ultralytics/yolov5;
使用官方源码和它的权重做预训练模型,训练人脸侦测。
我这里使用celebA的数据集,就找了1500张照片。
然后要自己做标签。

主要注意一下几点:
① 标签和照片在一个目录下新建新目录,分别为“/labels”,“/images”,用来存放图片数据和标签数据。
② 标签和图片同名,一张图片一个标签。
③ 修改yaml配置文件;

train: D:/AIstudyCode/data/CelebA/images/train/
val: D:/AIstudyCode/data/CelebA/images/test/
# number of classes
nc: 1
# class names
names: ['face']

④ 标签的格式为: 类别 中心点偏移量 x y 宽高 w h;(下面为标签制作的代码)

# 制作标签
from PIL import Image,ImageDraw

anno_box_path = r"D:/AIstudyCode/data/CelebA/Anno/list_bbox_celeba.txt"
label_dir = "D:/AIstudyCode/data/CelebA/labels"
img_dir = "D:/AIstudyCode/data/CelebA/Img/img_celeba.7z/img_celeba.7z/img_celeba"
count = 0
epoch = 1
box_file = open(anno_box_path,"r")

i = 0


for line in box_file:
    if i < 2:
        i += 1
        continue
    i += 1
    print(line)

    imgname = line[0:6]
    #print(imgname)

    img_strs = line.split()
    x1, y1, w, h = int(img_strs[1]), int(img_strs[2]), int(img_strs[3]), int(img_strs[4])
    x2, y2 = x1+w, y1+h

    img = Image.open(f"{img_dir}/{img_strs[0]}")
    img_w, img_h = img.size

    # ****************************
    dw = 1. / (int(img_w))
    dh = 1. / (int(img_h))
    x = ((x1 + x2) / 2.0 - 1)*dw
    y = ((y1 + y2) / 2.0 - 1)*dh
    w = (x2 - x1)*dw
    h = (y2 - y1)*dh
    # x = x * dw
    # w = w * dw
    # y = y * dh
    # h = h * dh
    # ****************************
    label_txt = open(f"{label_dir}/{imgname}.txt", "w")

    label_txt.write(f"0 {x} {y} {w} {h}\n")
    label_txt.flush()
    label_txt.close()

    if i == 1562:
        exit()

训练速度还是很快的哈,我用渣渣的1050Ti,训练了一个多小时,效果已经很好了。需要更好的效果,可以加大样本,训练时间再长一点。

2. arcface

arcface前面说过了一些,也用的官方代码和权重包,所以也没什么好说的。
主要要说的就是,跟yoloV5结合一起使用的部分。
先是要从数据库中,获取已有照片的特征表。(用来做识别)
model 为Arcface模型,dir为数据库的目录。
输出字典,(图片名:特征图1024)

def get_featuresdict(model, dir):
    list = os.listdir(dir)
    person_dict = {}
    for i,each in enumerate(list):
        image = load_image(f"pic/{each}")
        data = torch.from_numpy(image)
        data = data.to(torch.device("cuda"))
        output = model(data)  # 获取特征
        output = output.data.cpu().numpy()

        fe_1 = output[0]
        fe_2 = output[1]
        feature = np.hstack((fe_1, fe_2))
        person_dict[each] = feature
    return person_dict

然后,修改yoloV5里面detect部分代码。

for *xyxy, conf, cls in det: # x1 y1 x2 y2 cls class

    face_img = im0[int(xyxy[1]):int(xyxy[3]),int(xyxy[0]):int(xyxy[2])] # 裁剪侦测到的人脸部分
    face_img = cv2.resize(face_img,(128, 128)) # 缩放至128*128
    face_img = cv2.cvtColor(face_img,cv2.COLOR_BGR2GRAY)
    face_img = np.dstack((face_img, np.fliplr(face_img)))

    face_img = face_img.transpose((2, 0, 1))
    face_img = face_img[:, np.newaxis, :, :]

    face_img = face_img.astype(np.float32, copy=False)
    face_img -= 127.5
    face_img /= 127.5

    face_data = torch.from_numpy(face_img)
    face_data = face_data.to(torch.device("cuda"))
	# 获取特征
    _output = arcface_model(face_data)  
    _output = _output.data.cpu().numpy()

    fe_1 = _output[0]
    fe_2 = _output[1]

    _feature = np.hstack((fe_1, fe_2)) 

    # label = '%s %.2f' % (names[int(cls)], conf)
    label = "none"
    list = os.listdir(dir)
    max_f = 0
    t = 0
    # 比较数据库中每一张图片的余弦相似度
    for i, each in enumerate(list):
        t = cosin_metric(features[each],_feature)
        # print(each, t)
        if t>max_f:
            max_f = t
            max_n = each
        # print(max_n,max_f)
        if (max_f>0.5):
            label = max_n[:-4]
    plot_one_box(xyxy, im0, label=label, color=colors[int(cls)], line_thickness=3)

3. 测试(我的娜娜女神)

测试视频都是在B站找的,欧阳娜娜的视频。

测试在我这渣渣电脑上跑是0.05秒左右/每帧。效果也还可以。

存在几个问题,因为我数据库每个人只准备一张图片。(网上找的正脸照片)所以视频中很多侧脸照有时候不能够识别出来。

第二个问题就是余弦相似度的阈值问题,正常来讲两个不一样的人余弦相似度都不会太高(例如下图欧阳娜娜和陈立农)但是我后面找了欧阳娜娜姐妹三个人的volg来测试,发现有的时候,阈值设置高了容易识别不出来,阈值设置低了就容易识别错误。

所以数据库实际上可以准备多角度多张照片,准备单人的数据库目录。
结合单个人多张照片余弦相似度,求平均或者制定其他规则,可以得到更加准确的识别。我这边只准备了四张图片如下。
数据库
效果1
结果2
结果3

==============================================================================================

4. silentFace活体检测

更新:silentFace活体检测:https://github.com/smisthzhu/Silent-Face-Anti-Spoofing直接参考这篇。

做完人脸识别,我还不满足哈,我想。要是我家安防门有人直接那我照片不就解锁了。这可不行。于是乎,查资料。这个咋解决。
❗❗❗❗❗做个活体检测不就行了吗。然后就查了很多活体检测,什么张张嘴,摇摇头,不不不,这都不是我想要的。总不能我过个人脸识别门禁还得规定动作吧。

刚好前几天在机器之心公众号上看到这个。静默活体检测:https://mp.weixin.qq.com/s/01X6UyoPGwASTDWgC6X6qQ,于是找了找代码跑了跑,觉得效果还行。于是拼装进我原来的代码里。具体的我修改后也上传到GitHub上。(就是简单的拼装一下)

github下载下来可以通过配置open_rf控制是否开启真假脸检测。

效果:(没剪头发,没刮胡子,献丑了)
效果
说下感受哈:检测的速度非常慢,效果的话实际来看其实预测会预测错误。所以我设置只有预测为真脸且预测率大于0.9才判定为真脸。

静默识别原文说明:RGB静默活体对摄像头型号和使用场景鲁棒性受限,所以实际使用体验会有一定差异。
所以效果看看就好吧我觉得。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐