簡單來說,人臉識別這個問題,就是給定兩我的臉,而後斷定他們是否是同一我的,這是它最原始的定義。它有不少應用場景,好比銀行櫃檯、海關、手機解鎖、酒店入住、網吧認證,會查身份證跟你是否是同一我的。html
關於人臉識別的內容,網上資料不少,這裏推薦一篇綜述,詳細介紹了一些人臉識別的背景和目前的相關研究,以及經常使用的人臉識別模型:python
http://www.elecfans.com/d/709424.htmlgit
好了,直接進入主題,今天的重點:github
insightface論文:https://arxiv.org/abs/1801.07698算法
insightface github項目:https://github.com/deepinsight/insightfacevim
官方提供的項目是基於mxnet框架的服務器
所以首先須要配置好這些環境,這裏假設已經安裝好cuda等app
mxnet的安裝相對來講比較簡單(相對於caffe)框架
(1)查詢本身cuda的版本dom
# 輸入
nvcc -V
# 輸出結果
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2017 NVIDIA Corporation
Built on Fri_Sep__1_21:08:03_CDT_2017
Cuda compilation tools, release 9.0, V9.0.176複製代碼
(2)用pip安裝mxnet(GPU版本)
pip install mxnet-cu90
# 根據自身狀況查詢對應的安裝命令,例如我服務器的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)。
將lfw數據集下載好並放置在datasets下(這裏以lfwdata命名的文件夾),而後新建一個文件夾並命名爲output保存對齊後的人臉圖片,新建一個文件夾命名爲train用於保存輸出結果
運行insightface項目下 src/align下的align_lfw.py文件
python align_lfw.py --input-dir ../../datasets/lfwdata --output-dir ../../datasets/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文件下)
終端下,移動和重命名的操做
# 重命名 mv [原始文件名] [改變後的文件名]
mv lst train.lst
# 移動 mv [起始文件路徑] [目標文件路徑]
mv train.lst ../train/複製代碼
觀察生成的 lst 文件內容:
1 ../../datasets/train/Abbas_Kiarostami/Abbas_Kiarostami_0001.jpg 0
1 ../../datasets/train/Abdel_Aziz_Al-Hakim/Abdel_Aziz_Al-Hakim_0001.jpg 1
# 其中1表明對齊,最後的數字0,1表明class label 中間是地址;須要用\t表示tab鍵,不能用空格間隔。複製代碼
在datasets/train下建立property,沒有後綴
寫入下面內容,含義1000,112,112表明ID數量,尺寸,尺寸
1000,112,112複製代碼
運行src/data face2rec2.py
python face2rec2.py ../../datasets/train/複製代碼
運行可能會報錯,須要修改,可能緣由是源代碼是基於python2的
在python3下運行,修改第105行成以下所示:
s = mx.recordio.pack(header, b'')複製代碼
運行成功後會出現兩個文件
train.idx和train.rec複製代碼
爲了作測試咱們須要生成驗證集用的bin文件,bin文件生成前須要作pair文件,就是一對一對的數據,每一行分別是
圖A的目錄 空格 圖B的目錄 空格 標誌0/1(表明兩張圖類別一致否)
在src/data下新建一個代碼generate_image_pairs.py用於生成pairs複製代碼
代碼來源:https://blog.csdn.net/CLOUD_J/article/details/100672392
# coding:utf-8
import sys
import os
import random
import time
import itertools
import pdb
import argparse
#src = '../../datasets/lfw2'
#dst = open('../../datasets/lfw/train.txt', 'a')
parser = argparse.ArgumentParser(description='generate image pairs')
# general
parser.add_argument('--data-dir', default='', help='')
parser.add_argument('--outputtxt', default='', help='path to save.')
parser.add_argument('--num-samepairs',default=100)
args = parser.parse_args()
cnt = 0
same_list = []
diff_list = []
list1 = []
list2 = []
folders_1 = os.listdir(args.data_dir)
dst = open(args.outputtxt, 'a')
count = 0
dst.writelines('\n')
# 產生相同的圖像對
for folder in folders_1:
sublist = []
same_list = []
imgs = os.listdir(os.path.join(args.data_dir, folder))
for img in imgs:
img_root_path = os.path.join(args.data_dir, folder, img)
sublist.append(img_root_path)
list1.append(img_root_path)
for item in itertools.combinations(sublist, 2):
for name in item:
same_list.append(name)
if len(same_list) > 10 and len(same_list) < 13:
for j in range(0, len(same_list), 2):
if count < int(args.num_samepairs):#數量能夠修改
dst.writelines(same_list[j] + ' ' + same_list[j+1]+ ' ' + '1' + '\n')
count += 1
if count >= int(args.num_samepairs):
break
list2 = list1.copy()
# 產生不一樣的圖像對
diff = 0
print(count)
# 若是不一樣的圖像對遠遠小於相同的圖像對,則繼續重複產生,直到二者相差很小
while True:
random.seed(time.time() * 100000 % 10000)
random.shuffle(list2)
for p in range(0, len(list2) - 1, 2):
if list2[p] != list2[p + 1]:
dst.writelines(list2[p] + ' ' + list2[p + 1] + ' ' + '0'+ '\n')
diff += 1
if diff >= count:
break
#print(diff)
if diff < count:
#print('--')
continue
else:
break複製代碼
運行generateimagepairs.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文件
內容:
../../datasets/output/Abdullah/Abdullah_0002.jpg ../../datasets/output/Abdullah/Abdullah_0004.jpg 1
# 前面兩個分佈是生成的pairs的路徑,後面的0/1表明是否同一我的或類複製代碼
成功後利用/src/data/下的 lfw2pack.py生成bin文件
可是存在點問題,對lfw2pack.py進行稍微的修改,修改lfw2pack.py中19行,打#的爲更改的,改成兩個參數,一個是txt讀出來的列表,另外一個是總數量。
import mxnet as mx
from mxnet import ndarray as nd
import argparse
import pickle
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'eval'))
import lfw
parser = argparse.ArgumentParser(description='Package LFW images')
# general
parser.add_argument('--data-dir', default='', help='')
# 修改1:圖像大小修改成112,112
parser.add_argument('--image-size', type=str, default='112,112', help='')
parser.add_argument('--output', default='', help='path to save.')
# 修改2:添加解析參數
parser.add_argument('--num-samepairs',default=100)
args = parser.parse_args()
lfw_dir = args.data_dir
image_size = [int(x) for x in args.image_size.split(',')]
# 修改3:將文件名pairs.txt修改爲train.txt
lfw_pairs = lfw.read_pairs(os.path.join(lfw_dir, 'train.txt'))
print(lfw_pairs)
# 修改4:下一行進行修改爲須要的格式
# lfw_paths, issame_list = lfw.get_paths(lfw_dir, lfw_pairs, 'jpg')
lfw_paths, issame_list = lfw.get_paths(lfw_pairs,int(args.num_samepairs)+1)#, 'jpg')
lfw_bins = []
#lfw_data = nd.empty((len(lfw_paths), 3, image_size[0], image_size[1]))
print(len(issame_list))
i = 0
for path in lfw_paths:
with open(path, 'rb') as fin:
_bin = fin.read()
lfw_bins.append(_bin)
#img = mx.image.imdecode(_bin)
#img = nd.transpose(img, axes=(2, 0, 1))
#lfw_data[i][:] = img
i+=1
if i%1000==0:
print('loading lfw', i)
with open(args.output, 'wb') as f:
pickle.dump((lfw_bins, issame_list), f, protocol=pickle.HIGHEST_PROTOCOL)複製代碼
對應的get_paths這個文件存在src/eval/lfw.py下,把它也改了
def get_paths(pairs, same_pairs):
nrof_skipped_pairs = 0
path_list = []
issame_list = []
cnt = 1
for pair in pairs:
path0 = pair[0]
path1 = pair[1]
if cnt < same_pairs:
issame = True
else:
issame = False
if os.path.exists(path0) and os.path.exists(path1): # Only add the pair if both paths exist
path_list += (path0,path1)
issame_list.append(issame)
else:
print('not exists', path0, path1)
nrof_skipped_pairs += 1
cnt += 1
if nrof_skipped_pairs>0:
print('Skipped %d image pairs' % nrof_skipped_pairs)
return path_list, issame_list複製代碼
vim中多行註釋方法:
多行註釋:
1. 進入命令行模式,按ctrl + v進入 visual block模式,而後按j, 或者k選中多行,把須要註釋的行標記起來
2. 按大寫字母I,再插入註釋符,例如 #
3. 按esc鍵就會所有註釋了
取消多行註釋:
1. 進入命令行模式,按ctrl + v進入 visual block模式,按字母l橫向選中列的個數,例如 # 須要選中2列
2. 按字母j,或者k選中註釋符號
3. 按d鍵就可所有取消註釋複製代碼
以後再運行
python3 lfw2pack.py --data-dir ../../datasets/train --output ../../datasets/train/lfw.bin --num-samepairs 2複製代碼
注意:我這裏報錯了(沒有報錯的小夥伴能夠忽略)`path0 = pair[0]IndexError: list index out of range`
仔細分析以後,是由於在train.txt中存在空白行致使,直接刪除便可,若是沒有報錯能夠直接忽略
至此,咱們已經完成了數據集的製做,後續會更新如何訓練,以及使用。
這部份內容,是本人摸索了好久才搞定的,本文儘量的寫的詳細,但願能幫到你們,寫這篇的時候又從新操做了一遍,若是能夠懇請小夥伴們能點個「在看」或分享到朋友圈。謝謝啦!
歡迎關注我,wx公主號:AI算法與圖像處理