2.使用insightface讀取視頻進行人臉識別

1.人臉特徵持久化

輸入數據集的人臉並得到特徵向量之後,首先要持久化下來。

import numpy as np
'''
前面的忽略,就是加載模型,獲取數據集,跑模型得到向量f
'''
'''關鍵代碼'''
f = model.get_feature(img)
f.tofile('/myfeature/rep.bin')

# 讀取
f_ = np.fromfile('/myfeature/rep.bin', dtype=np.float32)
print(f_)

2.人臉識別

思路:

  1. 使用opencv讀取視頻流。
  2. 獲取每一幀並進行人臉檢測,進一步特徵提取。
  3. 與特徵庫的特徵進行比對。
  4. 設置閾值,求當前特徵與特徵庫特徵的距離,提取出最小的距離與閾值比對,如果小於閾值則返回特徵所對應的姓名。
  5. 輸出姓名到視頻流中並用矩形框出識別出的人臉。
import face_model_v2 as face_model
import argparse
import cv2
import sys
import numpy as np
import pandas as pd
import os
parser = argparse.ArgumentParser(description='face model test')
# general
parser.add_argument('--image-size', default='112,112', help='')
parser.add_argument('--model', default='/models/model-r100-ii/model,0', help='path to load model.')
parser.add_argument('--ga-model', default='/models/gamodel-r50/model,0', help='path to load model.')
parser.add_argument('--gpu', default=0, type=int, help='gpu id')
parser.add_argument('--det', default=0, type=int, help='mtcnn option, 1 means using R+O, 0 means detect from begining')
parser.add_argument('--flip', default=0, type=int, help='whether do lr flip aug')
parser.add_argument('--threshold', default=1.24, type=float, help='ver dist threshold')
parser.add_argument('--videoPath', default=0)
parser.add_argument('--binPath', default=0)
args = parser.parse_args()
model = face_model.FaceModel(args)
# 獲得持久化的特徵庫與對應的label
threshold = float(args.threshold)
#print(threshold)
videoPath = args.videoPath
binPath = args.binPath
feature = []
label = []
# 遍歷目錄獲得目錄中文件名字作爲label,文件內容加入feature
for bin_ in os.listdir(binPath):
    # 注意要指定dtype
    feature.append(np.fromfile(binPath+'/' + bin_, dtype=np.float32))
    label.append(bin_.split('.')[0])


# 查找當前特徵最接近的特徵
def findNear(feature, f, threshold, label):
    dist_list = []
    # 遍歷特徵庫
    for feature_unit in feature:
        # 距離的定義是(特徵1-特徵2)開根號並求和
        dist = np.sum(np.square(feature_unit - f))
        # dist_list作用是將所有距離都保存下來,以便獲得最小距離
        dist_list.append(dist)
        # 尋找到最小距離
        minDist = np.min(dist_list)
        # 如果最小距離小於等於閾值
        if minDist <= threshold:
            # 求出最小距離對應的索引
            minIdx = np.argmin(dist_list)
            # 找到姓名
            return label[minIdx]
        else:
            # 如果沒有滿足條件的,就返回'none'
            return 'none'
print('*'*8, 'into video')
# read video
try:
    # 按路徑讀取視頻
    cap = cv2.VideoCapture(videoPath)
    # 將視頻縮小,目的是加快程序運行速度。
    cap.set(3, 240)
    cap.set(4, 180)
    print('get video')
    # 獲得當前圖像長寬
    width = int(cap.get(3))
    height = int(cap.get(4))
    # 不光讀取圖像,還要講識別結果寫入視頻並返回,所以這一步是指定視頻編碼
    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    # 指定視頻輸出對象,視頻輸出路徑、編碼、幀數、視頻大小
    out = cv2.VideoWriter('./video/output.avi', fourcc, 25, (width,height))
    # 開始讀取視頻並做識別
    while True:
        # 讀取視頻,ret-是否讀取成功, frame-圖像
        ret, frame = cap.read()
        if ret:
            try:
                # 這裏修改了一下face_model,使其返回的多個人臉和對應座標
                imgs,bbox = model.get_input(frame)
                # 遍歷人臉和座標
                for img_unit,bbox_unit in zip(imgs, bbox):
                    # 因爲有可能沒有人臉,所以如果img_unit有shape值,那就是有人臉
                    if img_unit.shape:
                        # 獲得特徵
                        f = model.get_feature(img_unit)
                        # 找到匹配信息
                        res = findNear(feature, f, threshold, label)
                        # 如果匹配到了姓名
                        if res != 'none':
                            # 用方框標註,bbox_unit中的值爲(左,上,右,下)
                            # 按照cv2.rectangle的參數寫入
                            cv2.rectangle(frame, (int(bbox_unit[0]), int(bbox_unit[1])),(int(bbox_unit[2]), int(bbox_unit[3])), (0,0,255))
                            # 標記文字到圖像中,參數:圖像,文字,位置,字體,大小,顏色,寬度
                            frame = cv2.putText(frame, res, (int(bbox_unit[2]), int(bbox_unit[3])+2), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,255), 1)
                # 寫出視頻
                out.write(frame)
            except Exception as e:
                # 如果圖像沒有shape代表着沒有人臉,img.shape就會報NoneType錯誤,捕獲錯誤,並直接寫出視頻
                out.write(frame)
            # 每幀遍歷
            if cv2.waitKey(1) & 0xff == ord('q'):
                break
        # 視頻讀取完畢,ret返回false那麼退出循環
        else:
            break
    # 釋放資源
    cap.release()
    out.release()
    cv2.destroyAllWindows()
# 程序就算報錯也要正常釋放資源,所以要捕獲這個視頻識別流程
except Exception as e:
    print(e)
# 最終釋放資源
finally:
    cap.release()
    out.release()
    cv2.destroyAllWindows()
print('final')

3.源碼改動

因爲,源碼指定了只檢測一個人臉,所以需要更改源碼以獲得多個人臉進行識別。

進入insightface/deploy路徑找到face_model.py,複製一份更名face_model_v2.py並編輯。

# 主要修改get_input方法
def get_input(self, face_img):
    #print('into face_model_v2')
    ret = self.detector.detect_face(face_img, det_type = self.args.det)
    if ret is None:
        return None
    bbox, points = ret
    # 存放所有檢測的人臉圖像
    aligned_list = []
    # 存放所有人臉座標
    bbox_list = []    
    if bbox.shape[0]==0:
        return None
    for i in range(bbox.shape[0]):
        # 獲取每一個座標
        bbox_ = bbox[i,0:4]
        # 存放座標
        bbox_list.append(bbox_)
        # 獲取每一個特徵點
        points_ = points[i,:].reshape((2,5)).T
        nimg = face_preprocess.preprocess(face_img, bbox_, points_, image_size='112,112')
        nimg = cv2.cvtColor(nimg, cv2.COLOR_BGR2RGB)
        aligned = np.transpose(nimg, (2,0,1))
        # 存放座標
        aligned_list.append(aligned)
return aligned_list, bbox_list

4.接下來跑程序就行了,注意一下路徑

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章