07_人脸识别实战(深度学习)-使用模型进行人脸图片对比

经过上一篇博客,我们已经获得了人脸分类的模型,这次我们只需要简单的调整,就可以获得提取人脸特征的模型,然后对比人脸之间的特征,就可以知道2张图片是否是同一个人了

代码步骤如下
  1. 从“olivettifaces.jpg”中截取人脸,将同一个人的人脸放在同一文件夹下
  2. 读取上一个博客的训练好的模型
  3. 修改模型为提取特征的模型
  4. 从同一个头像文件夹下读取图片,将第一张图片与其他图片的特征做对比,查看对比结果
代码如下

1.截取人脸,同一个人脸放在同一文件夹下

import cv2
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
import os

# 将同一个人的头像放在一个文件中
def split_to_dataset(img_path, save_path):
    olive = cv2.imread(img_path)
    lable = 0
    if not os.path.exists(save_path):
        os.mkdir(save_path)# 新建/data/verify文件夹 放人脸测试的图片
    if olive is None:
        raise Exception("can not open the olivettifaces dataset file.")
    for row in range(20):
        for column in range(20):
            img = olive[row * 57:(row + 1) * 57, column * 47:(column + 1) * 47]
            if column == 10 or column == 0:
                lable = lable + 1
                tmp_path = save_path + "/" +str(lable -1) + "/"
                if not os.path.exists(tmp_path):
                    os.mkdir(tmp_path)
            cv2.imwrite(img=img, filename=tmp_path + str(column) +".jpg")
            
split_to_dataset("./data/olivettifaces.jpg","./data/verify")

2.加载模型

from keras import backend as K
def load_model(filepath):
    import keras.models
    model = keras.models.load_model(filepath, custom_objects={"AMSoftmax": AMSoftmax, "amsoftmax_loss": amsoftmax_loss})
    return model
    
model = load_model("./trained_models/best_face_recognition_model.hdf5")

3.修改模型

def rebuild_model(model, input_layer="input", output_layer="feature"):
    # if model is not an instance of Model, then try to load_model it by filepath.
    print("model", model)
    if isinstance(model, str):
        from model.amsoftmax import load_model
        model = load_model(model)

    __input_layer = model.get_layer(name=input_layer)
    __output_layer = model.get_layer(name=output_layer)
    func = K.function([__input_layer.input],
                      [__output_layer.output])
    input_shape = __input_layer.input_shape[1:]
    output_shape = __output_layer.output_shape[1:]
    return func
    
model = rebuild_model(model)

4.加载图片,用模型提取特征,并用余弦距离对比

# 返回2个向量的余弦距离
def cosine_similarity(vector1, vector2):
    # if vector1 and vector2 are column vector, we can use:
    # vector1.T * vector2
    val = np.dot(vector1, vector2)
    # or:
    # val = vector1.dot(vector2.T)
    norm = linalg.norm(vector1) * linalg.norm(vector2) #矩阵或向量范数
    cos = val / norm
    sim = 0.5 + 0.5 * cos  # normalization
    return sim

用第一张图片和同一个文件夹下的其他文件做对比

from numpy import linalg
for j in range(0,40):
    verify = load_img("./data/verify/" + str(j))
    vector_verify = model([verify])[0]
    for i in range(0,len(verify)):
        score = cosine_similarity(vector_verify[0], vector_verify[i])
        print(score)
print(mix_score)

结果如下:
在这里插入图片描述

其他代码(之前博客已经编写的代码,这里还要用,就不详细说了)
from keras.utils import to_categorical
def preprocess_image(input_shape, image):
    assert len(input_shape) == 3
    if input_shape[-1] == 1:
        image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    input_shape = input_shape[:2]
    image = cv2.resize(image, input_shape)
    image = np.asarray(image, dtype='float64')/256
    if len(image.shape) < 3:
        image = np.expand_dims(image, -1)
    return image

# 加载所有的图片,并处理为模型能识别的
def load_img(img_path):
    input_shape = (224,224,1)
    img_dirs = os.listdir(img_path)
    X = []
    for img_name in img_dirs:  
        img = cv2.imread(img_path + "/" + img_name)
        img = preprocess_image(input_shape,img)
        X.append(img)
    X = np.array(X)
    return X

AMSoftmax类

import tensorflow as tf
from keras import backend as K
from keras.layers import Dropout
from keras.engine.topology import Layer
from keras.models import Model


class AMSoftmax(Layer):
    def __init__(self, units, **kwargs):
        self.units = units
        self.kernel = None
        super(AMSoftmax, self).__init__(**kwargs)

    def build(self, input_shape):
        assert len(input_shape) >= 2

        self.kernel = self.add_weight(name='kernel',
                                      shape=(input_shape[1], self.units),
                                      initializer='uniform',
                                      trainable=True)
        super(AMSoftmax, self).build(input_shape)

    def call(self, inputs, **kwargs):
        # get cosine similarity
        # cosine = x * w / (||x|| * ||w||)
        inputs = K.l2_normalize(inputs, axis=1)
        kernel = K.l2_normalize(self.kernel, axis=0)
        cosine = K.dot(inputs, kernel)
        return cosine

    def compute_output_shape(self, input_shape):
        return input_shape[0], self.units


    def get_config(self):
        config = {'units': self.units}
        base_config = super(AMSoftmax, self).get_config()

        return dict(list(base_config.items()) + list(config.items()))

    

def amsoftmax_loss(y_true, y_pred, scale=30.0, margin=0.35):
    # make two constant tensors.
    m = K.constant(margin, name='m') # 边缘
    s = K.constant(scale, name='s')  # 比例
    # reshape the label
    label = K.reshape(K.argmax(y_true, axis=-1), shape=(-1, 1))
    label = K.cast(label, dtype=tf.int32)

    pred_batch = K.reshape(tf.range(K.shape(y_pred)[0]), shape=(-1, 1))
    # concat the two column vectors, one is the pred_batch, the other is label.
    ground_truth_indices = tf.concat([pred_batch,
                                      K.reshape(label, shape=(-1, 1))], axis=1)
    # get ground truth scores by indices
    ground_truth_scores = tf.gather_nd(y_pred, ground_truth_indices)

    # if ground_truth_score > m, group_truth_score = group_truth_score - m
    added_margin = K.cast(K.greater(ground_truth_scores, m),
                          dtype=tf.float32) * m
    added_margin = K.reshape(added_margin, shape=(-1, 1))
    added_embedding_feature = tf.subtract(y_pred, y_true * added_margin) * s

    cross_entropy = tf.compat.v1.nn.softmax_cross_entropy_with_logits_v2(labels=y_true,
                                                                         logits=added_embedding_feature)
    loss = tf.reduce_mean(cross_entropy)
    return loss

总结

  • 大部分图片的距离都非常小(接近于1),但是有非常少的几个是0.9以下的
  • 你也尝试在同一文件夹下方另外一个人的,结果大约会在0.6左右
  • 结果证明:模型在olivettifaces数据集下,还是非常优秀的
  • 但是,我们目前只用在olivettifaces下训练和测试,我们的模型很可能过拟合,想了解如何解决过拟合,可以看我的延伸篇中的介绍
  • 这次我们的数据集都是截取的比较好的人脸,但现实生活中,会有很多背景等其他的影响,所以,我们在处理图片的时候,还需要截取出人脸呢?下一篇博客将向你介绍人脸的截取
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值