0、注文
0.1 MTCNNとは何ですか?
MTCNNは、深い畳み込みマルチタスクフレームワークです。このフレームワークは、検出とアライメントの固有の関係を利用して、パフォーマンスを向上させます。顔と顔のマーカーを予測する場合、粗いものから細かいものへのプロセスは、3つのカスケードされたCNNネットワークを介して完了します。このネットワークを使用する前に、画像をさまざまなサイズにトリミングおよびズームして画像ピラミッドを形成し、トレーニングのために次の3つのサブネットワークにさまざまなサイズの画像を配置する必要があります。
第1段階ではP-Netを使用します
。1)段階1:P-Netネットワークを使用する場合、12×12×3 RGB画像を入力し、10個の3×3畳み込みカーネルを渡し、2×2最大プーリングプール操作を実行します。 .10は5×5で形成されます;
2)ステージII:畳み込みカーネルによって16 3×3×10は図3×3の特徴16を生成します;
3)ステージIII:3から32×3×16畳み込みカーネルは16個の3×3特徴マップを入力して、32個の1×1特徴マップを生成します。
出力:
1)顔ではない確率と顔である確率を表す1×1×2の二項分類スコア;
2)4つの境界ボックスの座標オフセット;
3)5つの顔の特徴点の座標。
第2段階では、R-Netを使用し
ます。P-Netによって生成されたバウディングボックスのさらなる最適化と調整です。入力は24×24×3RGB画像に置き換えられ、フルリンク層が追加されます。
3番目のステージはO-Netを使用します
。2番目のステージと同様に、最終的なフェースフレームと特徴点の位置が出力されますが、5つの特徴点の位置がここに出力されます。
MTCNNペーパーポータル:https:
//arxiv.org/ftp/arxiv/papers/1604/1604.02878.pdf githubのMTCNNプロジェクトソースコード:https://github.com/kpzhang93/MTCNN_face_detection_alignment
FaceNetの導入は繰り返されません。詳細については、以前のブログ投稿Jetson nanoの実際の戦闘シリーズ:dlib + FaceNetに基づく顔認識を参照してください。
1.基本的な実現
デモは、顔認識を実現するためにMTCNNとFaceNetに基づいており、機能の観点から、顔検出と顔認識の2つの部分に分けることができます。MTCNNを使用した顔検出部分は、深い畳み込みマルチタスクフレームワークです。FaceNet顔認識の後半の入力としてMTCNNから返される顔領域ブロック図によると、上記の2つの部分を組み合わせてリアルタイムの顔認識を実現します。 。
2、コーディング
2.1。新しいFaceNetモデルクラスを作成し、関連するコンストラクタ、推論関数、およびデストラクタを記述します
import tensorflow.compat.v1 as tf
from scipy import misc
import facenet
import numpy as np
#facenet network class
class FaceNet_Model():
def __init__(self, model_file):
tf.Graph().as_default()
self.sess = tf.Session()
with self.sess.as_default():
facenet.load_model('20180402-114759.pb')
self.image_placeholder = tf.get_default_graph().get_tensor_by_name("input:0")
self.phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0")
self.embeddings_op = tf.get_default_graph().get_tensor_by_name("embeddings:0")
def get_descriptor(self, image):
image = misc.imresize(image, (160,160), interp = "bilinear")
image = facenet.prewhiten(image)
images = np.stack([image])
feed_dict = {
self.image_placeholder:images, self.phase_train_placeholder:False}
emb = self.sess.run(self.embeddings_op, feed_dict = feed_dict)
return emb[0,:]
def __del__(self):
self.sess.close()
def g_FaceNetModel(model_file):
return FaceNet_Model(model_file)
2.2。新しいMTCNN_modelクラスを作成し、関連するコンストラクターと関数関数を記述します
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from scipy import misc
import tensorflow.compat.v1 as tf
import numpy as np
import sys
import os
import copy
import argparse
import facenet
import align.detect_face
class MTCNN_Model():
def __init__(self):
# Setup P-Net R-Net O-Net
self.minsize = 20 # minimum size of face
self.threshold = [ 0.6, 0.7, 0.7 ] # three steps's threshold
self.factor = 0.709 # scale factor
self.gpu_memory_fraction = 0.7
self.face_crop_size = 160
self.face_crop_margin = 32
self.pnet, self.rnet, self.onet = self.__mtcnn_setup() #mtcnn setup
def __mtcnn_setup(self):
with tf.Graph().as_default():
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=self.gpu_memory_fraction)
sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, log_device_placement=False))
with sess.as_default():
return align.detect_face.create_mtcnn(sess, None)
# func face_detect for face catch and alignment
def face_detector(self, image):
bounding_boxes, _ = align.detect_face.detect_face(image, self.minsize,
self.pnet, self.rnet, self.onet,
self.threshold, self.factor)
return bounding_boxes
#face alignment
def face_aligner(self, image, bb):
bounding_box = np.zeros(4, dtype=np.int32)
img_size = np.asarray(image.shape)[0:2]
bounding_box[0] = np.maximum(bb[0] - self.face_crop_margin / 2, 0)
bounding_box[1] = np.maximum(bb[1] - self.face_crop_margin / 2, 0)
bounding_box[2] = np.minimum(bb[2] + self.face_crop_margin / 2, img_size[1])
bounding_box[3] = np.minimum(bb[3] + self.face_crop_margin / 2, img_size[0])
cropped = image[bounding_box[1]:bounding_box[3], bounding_box[0]:bounding_box[2], :]
face_aligned = misc.imresize(cropped, (self.face_crop_size, self.face_crop_size), interp='bilinear')
return face_aligned
def __del__(self):
self.sess.close()
def g_mtcnn_model():
return MTCNN_Model()
2.3。顔データをローカルに登録して保存する
顔の特徴ベクトルの取得では、引き続きdlibを使用して顔領域の画像を取得します。これは、顔の特徴ベクトル表現を取得するためのFaceNetへの入力として使用されます。
import dlib
import cv2
import os
import facenet_model
import pickle
font = cv2.FONT_HERSHEY_SIMPLEX
detector = dlib.get_frontal_face_detector()
face_net = facenet_model.g_FaceNetModel('20180402-114759.pb')
imagePATH = '/home/colin/works/face_dataset/processed/'
def create_known(path):
global font
person_names = []
face_features = []
print("creating known face lib...")
for root, dirs, files in os.walk(path):
if len(files) != 0:
print(files)
for file in files:
if '.jpg' in file or '.png' in file:
path=os.path.join(root,file)
name=os.path.splitext(file)[0]
print(file)
image = cv2.imread(path)
rgb_img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
dets = detector(rgb_img)
if(len(dets) == 0):
continue
det = dets[0]
face_img = rgb_img[det.top():det.bottom(), det.left():det.right()]
descriptor = face_net.get_descriptor(face_img)
person_name = file[:file.rfind('_')]
person_names.append(person_name)
face_features.append(descriptor)
print('Appending + '+person_name+'...')
with open('gtk_dataset.pkl', 'wb') as f:
pickle.dump(person_names, f)
pickle.dump(face_features, f)
print('Face Library Created!')
if __name__ == "__main__":
create_known(imagePATH)
2.4、顔の検出と認識
import cv2
import os
import time
import numpy as np
import dlib
import align.detect_face
import facenet_model
import mtcnn_model
import pickle
import image_shop
################################ Global variable ######################################
person_names = []
face_features = []
imagePATH = '/home/colin/works/face_recognition_mtcnn_facenet/dataset/processed/Colin/'
face_net = None
mtcnn_det = None
########################################################################################
# 640 480 320 240
def gstreamer_pipeline(
capture_width=320,
capture_height=240,
display_width=320,
display_height=240,
framerate=15,
flip_method=0,
):
return (
"nvarguscamerasrc ! "
"video/x-raw(memory:NVMM), "
"width=(int)%d, height=(int)%d, "
"format=(string)NV12, framerate=(fraction)%d/1 ! "
"nvvidconv flip-method=%d ! "
"video/x-raw, width=(int)%d, height=(int)%d, format=(string)BGRx ! "
"videoconvert ! "
"video/x-raw, format=(string)BGR ! appsink"
% (
capture_width,
capture_height,
framerate,
flip_method,
display_width,
display_height,
)
)
def train_data_load():
global person_names, face_features
with open('gtk_dataset.pkl','rb') as f:
person_names=pickle.load(f)
face_features=pickle.load(f)
def facenet_recognition(image):
faces = []
face_names = []
rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
bounding_boxes = mtcnn_det.face_detector(rgb_image)
for bb in bounding_boxes:
person_name = 'unknown'
#face aligment
face_img= mtcnn_det.face_aligner(rgb_image, bb)
#get the face descriptor
descriptor = face_net.get_descriptor(face_img)
min_dist = 0.7 #1
for i in range(len(face_features)):
dist = np.linalg.norm(descriptor-face_features[i])
print('dist:', dist)
if dist < min_dist:
min_dist = dist
person_name = person_names[i]
face_names.append(person_name)
#Fix the rectangle error by colin.tan 2020-11-25
bounding_boxes = bounding_boxes[:,0:4].astype(int)
for name ,box in zip(face_names,bounding_boxes):
cv2.rectangle(image, (box[0],box[1]),(box[2],box[3]), (0, 255, 0), 2)
cv2.putText(image,name, (box[0],box[1]), cv2.FONT_HERSHEY_COMPLEX_SMALL, 0.7, (0, 0, 255), thickness=2)
face_names = None
return image
def face_recognition_livevideo(window_name, camera_idx):
cv2.namedWindow(window_name)
#CSI Camera for get pipeline
cap = cv2.VideoCapture(gstreamer_pipeline(flip_method=camera_idx), cv2.CAP_GSTREAMER)
while cap.isOpened():
ok, frame = cap.read() #read 1 frame
if not ok:
break
resImage= facenet_recognition(frame)
#display
cv2.imshow(window_name, resImage)
c = cv2.waitKey(1)
if c & 0xFF == ord('q'):
break
#close
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
train_data_load()
mtcnn_det = mtcnn_model.g_mtcnn_model()
face_net = facenet_model.g_FaceNetModel('20180402-114759.pb')
face_recognition_livevideo('Find Face', 0)