• 人脸识别:insightface自定义数据集制作 | 附练手数据集


    人脸识别简介

    简单来讲,人脸识别这个问题,就是给定两个人脸,然后判定他们是不是同一个人,这是它最原始的定义。它有很多应用场景,比如银行柜台、海关、手机解锁、酒店入住、网吧认证,会查身份证跟你是不是同一个人。

    关于人脸识别的内容,网上资料很多,这里推荐一篇综述,详细介绍了一些人脸识别的背景和目前的相关研究,以及常用的人脸识别模型:

    http://www.elecfans.com/d/709424.html

    好了,直接进入主题,今天的重点:

    insightface论文:https://arxiv.org/abs/1801.07698

    insightface github项目:https://github.com/deepinsight/insightface

    02

    制作数据集

    一、环境配置

    官方提供的项目是基于mxnet框架的

    因此首先需要配置好这些环境,这里假设已经安装好cuda等

    mxnet的安装相对来说比较简单(相对于caffe)

    (1)查询自己cuda的版本

     
    
    1. # 输入

    2. nvcc -V

    3. # 输出结果

    4. nvcc: NVIDIA (R) Cuda compiler driver

    5. Copyright (c) 2005-2017 NVIDIA Corporation

    6. Built on Fri_Sep__1_21:08:03_CDT_2017

    7. Cuda compilation tools, release 9.0, V9.0.176

    (2)用pip安装mxnet(GPU版本)

     
    
    1. pip install mxnet-cu90

    2. # 根据自身情况查询对应的安装命令,例如我服务器的cuda版本是10.0的,安装命令为 pip install mxnet-cu100

    二、克隆项目和数据集下载

    将insight项目克隆到本地

    git clone --recursive https://github.com/deepinsight/insightface.git
    

    下载lfw数据集

    链接:http://vis-www.cs.umass.edu/lfw/index.html#download

    这里为了方便,提供了lfw的部分用于练手

    练手数据集https://www.lanzous.com/i7gdxva,仅用于制作数据集练手

    观察数据集:

    这里提供了20个用于练手,完整数据集可以去上面的链接或自行查找下载。

    说明:每个文件夹名为人的姓名,文件夹内包含多张人脸(>=1)。

    三、开始制作所需要格式的数据集

    (1)数据对齐并生成lst文件

    将lfw数据集下载好并放置在datasets下(这里以lfwdata命名的文件夹),然后新建一个文件夹并命名为output保存对齐后的人脸图片,新建一个文件夹命名为train用于保存输出结果

    运行insightface项目下 src/align下的align_lfw.py文件

    python align_lfw.py --input-dir ../../datasets/lfwdata --output-dir ../../datasets/output
    

    --input :输入需要对齐的数据的路径

    --output:输出对齐后的数据保存路径

    对齐后的图片

    遇到问题1:

    ValueError: Object arrays cannot be loaded when allow_pickle=False

    解决方案:

    pip3 install numpy==1.16.1 

    如果已安装了多个numpy版本,需要先将其卸载后在运行

    遇到问题2:

    AttributeError: module 'scipy.misc' has no attribute 'imread'

    解决方案:

    pip install scipy==1.1.0

    如果成功运行,output文件夹下会产生对齐后的人脸以及一个lst文件(将lst文件改名为 train.lst,并移动到train文件下

    终端下,移动和重命名的操作

     
    
    1. # 重命名 mv [原始文件名] [改变后的文件名]

    2. mv lst train.lst

    3. # 移动 mv [起始文件路径] [目标文件路径]

    4. mv train.lst ../train/

    观察生成的 lst 文件内容:

     
    
    1. 1 ../../datasets/train/Abbas_Kiarostami/Abbas_Kiarostami_0001.jpg 0

    2. 1 ../../datasets/train/Abdel_Aziz_Al-Hakim/Abdel_Aziz_Al-Hakim_0001.jpg 1

    3. # 其中1代表对齐,最后的数字0,1代表class label 中间是地址;需要用\t表示tab键,不能用空格间隔。

    (2)创建property配置文件

    在datasets/train下创建property,没有后缀

    写入下面内容,含义1000,112,112代表ID数量,尺寸,尺寸

    1000,112,112
    

    (3)生成rec&idx文件(依托于lst文件)

    运行src/data face2rec2.py

    python face2rec2.py ../../datasets/train/
    

    运行可能会报错,需要修改,可能原因是源代码是基于python2的

    在python3下运行,修改第105行成如下所示:

    s = mx.recordio.pack(header, b'')
    

    运行成功后会出现两个文件

    train.idx和train.rec
    

    将train.idx, train.rec是放置在train文件夹中,用于后续训练使用,不然后续创建pair会报错

    (4)创建pair文件


    为了做测试我们需要生成验证集用的bin文件,bin文件生成前需要做pair文件,就是一对一对的数据,每一行分别是

    图A的目录 空格 图B的目录 空格 标志0/1(代表两张图类别一致否)
    

    在src/data下新建一个代码generate_image_pairs.py用于生成pairs

    代码来源:https://blog.csdn.net/CLOUD_J/article/details/100672392

     
    
    1. # coding:utf-8

    2. import sys

    3. import os

    4. import random

    5. import time

    6. import itertools

    7. import pdb

    8. import argparse

    9. #src = '../../datasets/lfw2'

    10. #dst = open('../../datasets/lfw/train.txt', 'a')

    11. parser = argparse.ArgumentParser(description='generate image pairs')

    12. # general

    13. parser.add_argument('--data-dir', default='', help='')

    14. parser.add_argument('--outputtxt', default='', help='path to save.')

    15. parser.add_argument('--num-samepairs',default=100)

    16. args = parser.parse_args()

    17. cnt = 0

    18. same_list = []

    19. diff_list = []

    20. list1 = []

    21. list2 = []

    22. folders_1 = os.listdir(args.data_dir)

    23. dst = open(args.outputtxt, 'a')

    24. count = 0

    25. dst.writelines('\n')

    26. # 产生相同的图像对

    27. for folder in folders_1:

    28. sublist = []

    29. same_list = []

    30. imgs = os.listdir(os.path.join(args.data_dir, folder))

    31. for img in imgs:

    32. img_root_path = os.path.join(args.data_dir, folder, img)

    33. sublist.append(img_root_path)

    34. list1.append(img_root_path)

    35. for item in itertools.combinations(sublist, 2):

    36. for name in item:

    37. same_list.append(name)

    38. if len(same_list) > 10 and len(same_list) < 13:

    39. for j in range(0, len(same_list), 2):

    40. if count < int(args.num_samepairs):#数量可以修改

    41. dst.writelines(same_list[j] + ' ' + same_list[j+1]+ ' ' + '1' + '\n')

    42. count += 1

    43. if count >= int(args.num_samepairs):

    44. break

    45. list2 = list1.copy()

    46. # 产生不同的图像对

    47. diff = 0

    48. print(count)

    49. # 如果不同的图像对远远小于相同的图像对,则继续重复产生,直到两者相差很小

    50. while True:

    51. random.seed(time.time() * 100000 % 10000)

    52. random.shuffle(list2)

    53. for p in range(0, len(list2) - 1, 2):

    54. if list2[p] != list2[p + 1]:

    55. dst.writelines(list2[p] + ' ' + list2[p + 1] + ' ' + '0'+ '\n')

    56. diff += 1

    57. if diff >= count:

    58. break

    59. #print(diff)

    60. if diff < count:

    61. #print('--')

    62. continue

    63. else:

    64. break

    运行generate_image_pairs.py

    python3 generate_image_pairs.py --data-dir ../../datasets/output --outputtxt ../../datasets/train/train.txt --num-samepairs 5
    

    --data-dir 后接对齐后的人脸

    --outputtxt 用于保存train.txt文件

    --num-samepairs  生成多少对(具体如何设置,还需要好好研究一下)

    运行成功后在datasets/train下会生成一个train.txt文件

    内容:

     
    
    1. ../../datasets/output/Abdullah/Abdullah_0002.jpg ../../datasets/output/Abdullah/Abdullah_0004.jpg 1

    2. # 前面两个分布是生成的pairs的路径,后面的0/1代表是否同一个人或类

    (5)生成验证集bin文件

    成功后利用/src/data/下的 lfw2pack.py生成bin文件

    但是存在点问题,对lfw2pack.py进行稍微的修改,修改lfw2pack.py中19行,打#的为更改的,改为两个参数,一个是txt读出来的列表,另一个是总数量。

     
    
    1. import mxnet as mx

    2. from mxnet import ndarray as nd

    3. import argparse

    4. import pickle

    5. import sys

    6. import os

    7. sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'eval'))

    8. import lfw

    9. parser = argparse.ArgumentParser(description='Package LFW images')

    10. # general

    11. parser.add_argument('--data-dir', default='', help='')

    12. # 修改1:图像大小修改为112,112

    13. parser.add_argument('--image-size', type=str, default='112,112', help='')

    14. parser.add_argument('--output', default='', help='path to save.')

    15. # 修改2:添加解析参数 

    16. parser.add_argument('--num-samepairs',default=100)

    17. args = parser.parse_args()

    18. lfw_dir = args.data_dir

    19. image_size = [int(x) for x in args.image_size.split(',')]

    20. # 修改3:将文件名pairs.txt修改成train.txt

    21. lfw_pairs = lfw.read_pairs(os.path.join(lfw_dir, 'train.txt'))

    22. print(lfw_pairs)

    23. # 修改4:下一行进行修改成需要的格式

    24. # lfw_paths, issame_list = lfw.get_paths(lfw_dir, lfw_pairs, 'jpg')

    25. lfw_paths, issame_list = lfw.get_paths(lfw_pairs,int(args.num_samepairs)+1)#, 'jpg')

    26. lfw_bins = []

    27. #lfw_data = nd.empty((len(lfw_paths), 3, image_size[0], image_size[1]))

    28. print(len(issame_list))

    29. i = 0

    30. for path in lfw_paths:

    31. with open(path, 'rb') as fin:

    32. _bin = fin.read()

    33. lfw_bins.append(_bin)

    34. #img = mx.image.imdecode(_bin)

    35. #img = nd.transpose(img, axes=(2, 0, 1))

    36. #lfw_data[i][:] = img

    37. i+=1

    38. if i%1000==0:

    39. print('loading lfw', i)

    40. with open(args.output, 'wb') as f:

    41. pickle.dump((lfw_bins, issame_list), f, protocol=pickle.HIGHEST_PROTOCOL)

    对应的get_paths这个文件存在src/eval/lfw.py下,把它也改了

     
    
    1. def get_paths(pairs, same_pairs):

    2. nrof_skipped_pairs = 0

    3. path_list = []

    4. issame_list = []

    5. cnt = 1

    6. for pair in pairs:

    7. path0 = pair[0]

    8. path1 = pair[1]

    9. if cnt < same_pairs:

    10. issame = True

    11. else:

    12. issame = False

    13. if os.path.exists(path0) and os.path.exists(path1): # Only add the pair if both paths exist

    14. path_list += (path0,path1)

    15. issame_list.append(issame)

    16. else:

    17. print('not exists', path0, path1)

    18. nrof_skipped_pairs += 1

    19. cnt += 1

    20. if nrof_skipped_pairs>0:

    21. print('Skipped %d image pairs' % nrof_skipped_pairs)

    22. return path_list, issame_list

    vim中多行注释方法:

     
    
    1. 多行注释:

    2. 1. 进入命令行模式,按ctrl + v进入 visual block模式,然后按j, 或者k选中多行,把需要注释的行标记起来

    3. 2. 按大写字母I,再插入注释符,例如 #

    4. 3. 按esc键就会全部注释了

    5. 取消多行注释:

    6. 1. 进入命令行模式,按ctrl + v进入 visual block模式,按字母l横向选中列的个数,例如 # 需要选中2列

    7. 2. 按字母j,或者k选中注释符号

    8. 3. 按d键就可全部取消注释

    之后再运行

    python3 lfw2pack.py --data-dir ../../datasets/train --output ../../datasets/train/lfw.bin --num-samepairs 2
    

    注意:我这里报错了(没有报错的小伙伴可以忽略)

     
    
    1. path0 = pair[0]

    2. IndexError: list index out of range

    仔细分析之后,是因为在train.txt中存在空白行导致,直接删除即可,如果没有报错可以直接忽略


    至此,我们已经完成了数据集的制作,后续会更新如何训练,以及使用。

    这部分内容,是本人摸索了很久才搞定的,本文尽可能的写的详细,希望能帮到大家,写这篇的时候又重新操作了一遍,如果可以恳请小伙伴们能点个“在看”或分享到朋友圈。谢谢啦!

    参考链接:

    https://blog.csdn.net/CLOUD_J/article/details/100672392

    https://blog.csdn.net/hanjiangxue_wei/article/details/86566497

  • 相关阅读:
    OA系统源码
    C++编程案例讲解-基于结构体的控制台通讯录管理系统
    win11恢复win10版鼠标右键菜单
    MySQL优化:从十几秒优化到三百毫秒
    Key Points Estimation and Point Instance
    【优化组合】基于遗传算法求解不同投资比例的收益附matlab代码
    C++中实现雪花算法来在秒级以及毫秒及时间内生成唯一id
    docker 镜像启动并完成服务部署
    每年AP考试报名时间是什么时候?
    01 计算机图形学概述
  • 原文地址:https://blog.csdn.net/starzhou/article/details/127111896