insightface人脸识别代码记录(一)(数据前期准备)

一、前言

这部分主要讲训练数据的制作。一是我们直接采用作者提供好的数据集,二就是制作我们自己所需要的数据集。
目录地址:insightface人脸识别代码记录(总)(基于MXNet)

二、主要内容

1、首先,我们来提供作者的数据集。
这是作者提供的地址:https://github.com/deepinsight/insightface/wiki/Dataset-Zoo
比较推荐的是MS1M-ArcFace (85K ids/5.8M images) [5,7]
下面简单介绍下常用的人脸识别数据集:

MS-Celeb-1M

MS1M数据集包含有大约10万个人的脸(大约有1千万张人脸),但是数据集中包含有很多的“噪声”。Arcface论文作者对MS1M做了数据清洗,最终作者清洗得到的干净的数据包含有8.5万个人的脸(包含有380万张人脸)。

LFW

全名是Labeled Faces in the Wild.这个数据集是人脸评估一定会用到的一个数据集,包含了来自1680的13000张人脸图,数据是从网上搜索来的。基本都是正脸。这个数据集也是最简单的,基本主流算法都能跑到99%以上,貌似有6对label错了,所以最高正确率应该是99.9%左右。这个都跑不到99%的话别的数据集表现效果会更差。一般来说这个数据集是用来做人脸识别验证的。

CelebFaces

总共包含10177个人的202599张图片,也是从搜索引擎上爬过来的,噪声不算多,适合作为训练集。同时这个数据对人脸有一些二元标签,比如是否微笑,是否戴帽子等。

CASIA-WebFace

该数据集是从IMBb网站上搜集来的,含10K个人的500K张图片。同时做了相似度聚类来去掉一部分噪声。CAISA-WebFace的数据集源和IMDb-Face是一样的,不过因为数据清洗的原因,会比IMDb-Face少一些图片。噪声不算特别多,适合作为训练数据。

MegaFace

MegaFace数据集包含有69万个人的脸(包含大约有100万张人脸),所有数据由华盛顿大学从Flickr上组织收集。MegaFace是第一个在百万规模级别的面部识别算法的测试基准,这个项目旨在研究当数据库规模提升数个量级时,现有的脸部识别系统能否维持可靠的准确率。MegaFace是目前最为权威、最热门的评价人脸识别性能,特别是海量人脸识别检索性能的基准参照之一。

CFP

CFP(Celebrities in Frontal Profile )数据集是美国名人的人脸数据集,其中包含有500个人物对象,有他们的10张正面照以及4张形象照,因此在作为人物比对验证的时候,作者选用了最有挑战的正面照与形象照作为验证集(CFP,Frontal-Profile,CFP-FP )。

AgeDB

AgeDB(Age Database )数据集包含有440个人的脸(包含有12240张人脸),但其中包含有不同人的不同年龄阶段的照片,最小从3岁到最大101岁时期的照片,每个对象的平均年龄范围为49年。作者采用和LFW一样的对比验证方式。

2、接下来,介绍如何制作自己的数据集。
MXNet读取数据有两种方式:
①直接读取原图像,即采用.lst文件和原图像方式
②采用MXNet特有的数据读取方式,RecordIO文件,即.rec文件
这里我们采用第二种方式,基于.rec文件文件。这种方式优点是读取速度快,数据文件稳定。

首先,人脸的裁剪和校正。
因为之前我学习的是Retinaface,所以采用此人脸检测模型。下面结合代码进行记录。下面align.py是我参考insightfacedeploy/face_model.pysrc/common/face_preprocess.py整合起来的代码。具体一些细节在代码记录。

align.py:

import cv2
import os
import numpy as np
from skimage import transform as trans
from PIL import Image
#test_fddb.py这个脚本,见我的整理的项目地址。位于insightface人脸识别代码记录(总)(基于MXNet)中。
from test_fddb import detect

#这里是一个简单的由路径读取图片的方法
def read_image(img_path, **kwargs):
  mode = kwargs.get('mode', 'rgb')
  layout = kwargs.get('layout', 'HWC')
  if mode=='gray':
    img = cv2.imread(img_path, cv2.CV_LOAD_IMAGE_GRAYSCALE)
  else:
    img = cv2.imread(img_path, cv2.CV_LOAD_IMAGE_COLOR)
    if mode=='rgb':
      #print('to rgb')
      img = img[...,::-1]
    if layout=='CHW':
      img = np.transpose(img, (2,0,1))
  return img

#这个方法是核心。就是根据检测
def preprocess(img, bbox_list=None, landmark_list=None, **kwargs):
    #这是存放校正后图像的一个列表
    warped_list = list()
    #一张图片上可能存在多个人脸,即有多个bbox和关键点信息,需要分别进行裁剪和校正
    for bbox,landmark in zip(bbox_list,landmark_list):
        
        if isinstance(img, str):
            img = read_image(img,bbox, **kwargs)
            
        M = None
        image_size = []
        #对裁剪后图像大小的控制112*112
        str_image_size = kwargs.get('image_size', '')
        if len(str_image_size)>0:
            image_size = [int(x) for x in str_image_size.split(',')]
            if len(image_size)==1:
                image_size = [image_size[0], image_size[0]]
            assert len(image_size)==2
            assert image_size[0]==112
            assert image_size[0]==112 or image_size[1]==96
         #src存放着标准关键点信息所在的位置
        if landmark is not None:
            assert len(image_size)==2
            src = np.array([
            [30.2946, 51.6963],
            [65.5318, 51.5014],
            [48.0252, 71.7366],
            [33.5493, 92.3655],
            [62.7299, 92.2041] ], dtype=np.float32 )
            #这里这个+8么太明白是什么原理...(有知道的小伙伴希望可以评论留言)
            if image_size[1]==112:
                src[:,0] += 8.0
            dst = landmark.astype(np.float32)
			#创建相似变换矩阵
            tform = trans.SimilarityTransform()
            #根据标准关键landmark和所得到的landmark来计算得到变换矩阵
            tform.estimate(dst, src)
            #提供给后面仿射变换函数使用。因为仿射变换只涉及旋转和平移,所以只需要矩阵中的前两个参数
            #dst(x,y)=src(M11x+M12x+M13,M21x+M22y+M23)
            M = tform.params[0:2,:]
		#这个是变换矩阵不存在的情况下,暂时不做讨论
        if M is None:
            if bbox is None: #use center crop
                det = np.zeros(4, dtype=np.int32)
                det[0] = int(img.shape[1]*0.0625)
                det[1] = int(img.shape[0]*0.0625)
                det[2] = img.shape[1] - det[0]
                det[3] = img.shape[0] - det[1]
            else:
                det = bbox
            margin = kwargs.get('margin', 44)
            bb = np.zeros(4, dtype=np.int32)
            bb[0] = np.maximum(det[0]-margin/2, 0)
            bb[1] = np.maximum(det[1]-margin/2, 0)
            bb[2] = np.minimum(det[2]+margin/2, img.shape[1])
            bb[3] = np.minimum(det[3]+margin/2, img.shape[0])
            ret = img[bb[1]:bb[3],bb[0]:bb[2],:]
            if len(image_size)>0:
                ret = cv2.resize(ret, (image_size[1], image_size[0]))
            return ret 
        else: #do align using landmark
            assert len(image_size)==2
 			#然后调用opencv中的放射变换得到校正后的人脸
            warped = cv2.warpAffine(img,M,(image_size[1],image_size[0]), borderValue = 0.0)
            warped_list.append(warped)

    return warped_list

def Align(img_path):
	#调用retinaface中的人脸检测器,得到bbox和landmark坐标信息
    _ret = detect(img_path)
    #因为上述得到的一个list,list[0]存放了人脸的信息,list[1]是其所在路径
    ret = _ret[0]

	#将人脸置信度抽取出来,进行一个筛选。因为在检测器中进行过sort,得到的
	#置信度高的人脸位于前面,所以当出现第一个小于阈值的情况,后面便均小于。
    scores = ret[:,4]
    index = list()
    for i in range(len(scores)):
        if scores[i]>0.5:
            index.append(i)
        else: 
            break
            
    bbox = ret[index,0:4]
    points_ = ret[index,5:15]
    points = points_.copy()
    #因为得到的landmark是(x1,y1,x2,y2....)这种形式,需要变换成(x1,x2,...y1,y2....)这种形式
    points[index,0:5:1] = points_[index,0::2]
    points[index,5:10:1] = points_[index,1::2] 

    if bbox.shape[0]==0:
      return None
    #将上述得到的bbox和landmark信息分别存放到如下list
    points_list = list()
    bbox_list = list()
    for i in range(len(index)):

        point = points[i,:].reshape((2,5)).T
        bbox_ = bbox[i]
        points_list.append(point)
        bbox_list.append(bbox_)
    #points = points.reshape((len(index),2,5)).transpose(0,2,1)
    
    face_img = cv2.imread(img_path)
    #调用此方法,得到裁剪和校正过的人脸
    nimg_list = preprocess(face_img, bbox_list, points_list, image_size='112,112')
    #一张图片存在多张人脸,分别裁剪校正
    aligned_list = list()
    for _,nimg in enumerate(nimg_list):
        nimg = cv2.cvtColor(nimg, cv2.COLOR_BGR2RGB)
        aligned = np.transpose(nimg, (2,0,1))
        aligned_list.append(aligned)
    return aligned_list

if __name__ == "__main__":
    # path = './data/widerface/train/images/7--Cheering/7_Cheering_Cheering_7_321.jpg'  #单人脸
    # path1 = './data/widerface/train/images/4--Dancing/4_Dancing_Dancing_4_317.jpg'   #多人脸
    path = 'F:\Project\insightface-master\deploy\img'

    #os.walk()返回三个参数:
    #	①root,所在路径,即输入path
    #	②dirs,所在路径下的文件夹
    #	③files,所在路径下的文件
    for root, dirs, files in os.walk(path):
        for dir in dirs:
            img_root = os.path.join(root, dir)
            images = os.listdir(img_root)
            for image in images:
                path = os.path.join(img_root,image)
                print(path)
                out_list = Align(path)
                for i,out in enumerate(out_list):
                    new_image = np.transpose(out, (1, 2, 0))[:, :, ::-1]
                    out = Image.fromarray(new_image)
                    out = out.resize((112, 112))
                    out = np.asarray(out)
					#对所得到的人脸进行和原所在文件夹和命名的区别
                    if not os.path.exists(os.path.join(root,'_'+dir)):
                        os.mkdir(os.path.join(root,'_'+dir))
                    #采用原图像名字和i命名,i表示这张图片中的第几个人脸
                   cv2.imwrite(os.path.join(root,'_'+dir,str(image[0:-4])+'_'+str(i)+'.jpg'),out)
                print('over!')
        # cv2.imshow("out",out)
        # cv2.waitKey()

以下是效果图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后,制作.rec文件

我们来到https://github.com/apache/incubator-mxnet/blob/master/tools/im2rec.py下载得到im2rec.py脚本。
首先制作.lst文件,输入以下命令:

python im2rec.py  /data/train  data/train  --list --recursive  

①第一个/data/train,这个路径是prefix的意思,代表会在data目录下生成一个train.lst的文件。
②第二个/data/train,是路径root的意思,代表图片所在路径。
③--list 代表生成lst文件的操作。因为默认生成RecordIO文件。
④-- recursive代表迭代搜索给定的目录因为此目录下可能存在多个类别的文件夹。

接着,输入以下命令,得到.rec文件

python im2rec2.py --num-thread 4   data/train.lst   data/train

①--num-thread用于设置线程数,加快生成.rec文件
② data/train.lst代表生成的.lst文件所在的位置
③ data/train代表原图像所在的位置
最后生成的.rec文件会默认保存在和.lst文件相同的目录下,同时会生成一个.idx的文件,对数据做随机排序有关。

最后,我们制作property配置文件
直接创建一个名为property的文件,没有后缀
写xxx,112,112代表ID数量,尺寸,尺寸。
例:
在这里插入图片描述

三、结尾

到这里就结束了。对MXNet的数据准备有了一些了解,同时学习了几个常用的人脸识别的数据集。上述一些数据集的介绍,来自于一些其他博主的博客作为记录,所以想在这里写下,下面附上参考链接。

参考链接:

人脸识别:《Arcface》论文详解
人脸识别常用数据集介绍(附下载链接)及常用评估指标

  • 7
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
抱歉,我是一个语言模型AI,无法编写和运行代码。不过,以下是用insightface实现人脸识别的一般步骤: 1. 安装insightface库 ``` pip install insightface ``` 2. 下载人脸检测模型和人脸识别模型 ``` import os import urllib model_urls = [ 'https://github.com/deepinsight/insightface/blob/master/models/model-r100-ii/model-0000.params?raw=true', 'https://github.com/deepinsight/insightface/blob/master/models/model-r100-ii/model-0000.params?raw=true', 'https://github.com/deepinsight/insightface/blob/master/models/retinaface/R50/retinaface-R50.zip?raw=true' ] model_names = [ 'model-r100-ii/model-0000.params', 'model-r100-ii/model-symbol.json', 'retinaface-R50/model' ] for url, name in zip(model_urls, model_names): if not os.path.exists(name): print('Downloading', name) urllib.request.urlretrieve(url, name) ``` 3. 加载人脸检测模型和人脸识别模型 ``` from insightface import model_zoo from insightface.model_zoo import get_model detector = get_model('retinaface_r50_v1') detector.prepare(ctx_id=-1, nms=0.4) recognition = get_model('arcface_r100_v1') recognition.prepare(ctx_id=-1) ``` 4. 加载人脸库 ``` import cv2 face_db = {} for file in os.listdir('faces'): name = os.path.splitext(file)[0] img = cv2.imread(os.path.join('faces', file)) embedding = recognition.get_embedding(img) face_db[name] = embedding ``` 5. 进行人脸识别 ``` img = cv2.imread('test.jpg') faces = detector.detect(img) for face in faces: embedding = recognition.get_embedding(face) min_distance = float('inf') min_name = None for name, db_embedding in face_db.items(): distance = recognition.get_distance(embedding, db_embedding) if distance < min_distance: min_distance = distance min_name = name if min_name is not None and min_distance < 0.8: cv2.rectangle(img, (face[0], face[1]), (face[2], face[3]), (0, 255, 0), 2) cv2.putText(img, min_name, (face[0], face[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2) else: cv2.rectangle(img, (face[0], face[1]), (face[2], face[3]), (0, 0, 255), 2) cv2.putText(img, 'Unknown', (face[0], face[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2) cv2.imshow('result', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 以上步骤仅供参考,实际使用时需要根据具体情况进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值