人脸识别相似度计算方法

本文探讨了人脸识别中使用欧氏距离和余弦距离衡量特征相似度的方法,以及如何通过阈值选择来优化识别精度。代码示例展示了在Facenet和Arcface模型下如何确定最佳阈值,并介绍了将欧氏距离转换为百分比的思路。
摘要由CSDN通过智能技术生成

在人脸识别中,我们通常采用欧氏距离和余弦距离来衡量人脸特征的相似度,判别是否为同一个人。

欧氏距离
欧氏距离比较简单,采用欧氏公式直接计算两个点之间的距离,如下:

代码:

diff = np.subtract(feature1, feature2)
dist = np.sqrt(np.sum(np.square(diff)))
feature1.shape 和feature2.shape 为(n, )

余弦距离


余弦距离,也称为余弦相似度,是用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小的度量。

当两个向量直接的夹角趋向0时,两个向量越接近,差异就越小。此时 = 1,即越接近1值时,说明人脸越相似。

代码:

dot = np.sum(np.multiply(feature1, feature2), axis=1)
norm = np.linalg.norm(feature1, axis=1) * np.linalg.norm(feature2, axis=1)
dist = dot / norm
 

区别
欧氏距离计算的是空间中两个点的绝对距离,距离dist越小,特征越相似;

余弦距离衡量的是空间中两个向量的夹角,夹角越靠近0,即dist越接近1,特征越相似。

阈值选取
以下是一段摘自facenet 的代码:

def distance(embeddings1, embeddings2, distance_metric=0):
    if distance_metric==0:
        # Euclidian distance
        diff = np.subtract(embeddings1, embeddings2)
        dist = np.sum(np.square(diff),1)
    elif distance_metric==1:
        # Distance based on cosine similarity
        dot = np.sum(np.multiply(embeddings1, embeddings2), axis=1)
        norm = np.linalg.norm(embeddings1, axis=1) * np.linalg.norm(embeddings2, axis=1)
        similarity = dot / norm
        dist = np.arccos(similarity) / math.pi
    else:
        raise 'Undefined distance metric %d' % distance_metric 
        
    return dist
 
def calculate_roc(thresholds, embeddings1, embeddings2, actual_issame, nrof_folds=10, distance_metric=0, subtract_mean=False):
    assert(embeddings1.shape[0] == embeddings2.shape[0])
    assert(embeddings1.shape[1] == embeddings2.shape[1])
    nrof_pairs = min(len(actual_issame), embeddings1.shape[0])
    nrof_thresholds = len(thresholds)
    k_fold = KFold(n_splits=nrof_folds, shuffle=False)
    
    tprs = np.zeros((nrof_folds,nrof_thresholds))
    fprs = np.zeros((nrof_folds,nrof_thresholds))
    accuracy = np.zeros((nrof_folds))
    
    indices = np.arange(nrof_pairs)
    
    for fold_idx, (train_set, test_set) in enumerate(k_fold.split(indices)):
        if subtract_mean:
            mean = np.mean(np.concatenate([embeddings1[train_set], embeddings2[train_set]]), axis=0)
        else:
          mean = 0.0
        dist = distance(embeddings1-mean, embeddings2-mean, distance_metric)
        
        # Find the best threshold for the fold
        acc_train = np.zeros((nrof_thresholds))
        for threshold_idx, threshold in enumerate(thresholds):
            _, _, acc_train[threshold_idx] = calculate_accuracy(threshold, dist[train_set], actual_issame[train_set])
        best_threshold_index = np.argmax(acc_train)
        for threshold_idx, threshold in enumerate(thresholds):
            tprs[fold_idx,threshold_idx], fprs[fold_idx,threshold_idx], _ = calculate_accuracy(threshold, dist[test_set], actual_issame[test_set])
        _, _, accuracy[fold_idx] = calculate_accuracy(thresholds[best_threshold_index], dist[test_set], actual_issame[test_set])
          
        tpr = np.mean(tprs,0)
        fpr = np.mean(fprs,0)
    return tpr, fpr, accuracy
 
def calculate_accuracy(threshold, dist, actual_issame):
    predict_issame = np.less(dist, threshold)
    tp = np.sum(np.logical_and(predict_issame, actual_issame))
    fp = np.sum(np.logical_and(predict_issame, np.logical_not(actual_issame)))
    tn = np.sum(np.logical_and(np.logical_not(predict_issame), np.logical_not(actual_issame)))
    fn = np.sum(np.logical_and(np.logical_not(predict_issame), actual_issame))
  
    tpr = 0 if (tp+fn==0) else float(tp) / float(tp+fn)
    fpr = 0 if (fp+tn==0) else float(fp) / float(fp+tn)
    acc = float(tp+tn)/dist.size
    return tpr, fpr, acc
def evaluate(embeddings, actual_issame, nrof_folds=10, distance_metric=0, subtract_mean=False):
    # Calculate evaluation metrics
    thresholds = np.arange(0, 4, 0.01)
    embeddings1 = embeddings[0::2]
    embeddings2 = embeddings[1::2]
    tpr, fpr, accuracy = facenet.calculate_roc(thresholds, embeddings1, embeddings2,
        np.asarray(actual_issame), nrof_folds=nrof_folds, distance_metric=distance_metric, subtract_mean=subtract_mean)
    thresholds = np.arange(0, 4, 0.001)
    val, val_std, far = facenet.calculate_val(thresholds, embeddings1, embeddings2,
        np.asarray(actual_issame), 1e-3, nrof_folds=nrof_folds, distance_metric=distance_metric, subtract_mean=subtract_mean)
    return tpr, fpr, accuracy, val, val_std, far
从上面的代码,可以看到其实我们在实际的人脸识别中,可以对标准的欧氏距离和余弦距离做适当的放大,这样在更有利于阈值的比较,更精准。那么阈值我们怎么选值呢?在上面第二段代码中可以找到答案,可以看到最佳阈值是可以算出来的,代码 thresholds = np.arange(0, 4, 0.001) ,最佳阈值在(0, 4)之间进行查找,在acc_train 最高时的threshold来当中最佳阈值。

diff = np.subtract(embeddings1, embeddings2)
dist = np.sum(np.square(diff),1)
通过跑LFW数据集测试,facenet算法下,欧氏距离经过上面两个语句变形后的最佳阈值为1.21;在arcface算法,mobilefacenet模型下自己阈值为1.45,可见在选取阈值的时候要根据自己的model来计算一下才合适。

更新:2020.11.6

关于欧氏距离怎么转换为百分比的问题
我们在百度等AI开放平台会看到人脸相似度是一个百分比,我们要怎么把欧氏转换为百分比呢,今天就说一下自己的思路。

首先我们想到的是sigmoid函数,这个函数y的范围是(0, 1),对应的百分比范围0%~100%,我们同样可以通过sigmoid函数的变形来实现映射。

通过上面的式子实现百分比的计算,我们只需要计算参数,就可以计算百分比了。

计算方法:我们在验证集里面跑一下,把欧氏距离最大的值x1记录下来,此时设定一个该值对应最大百分比(比如95%),然后在把欧氏距离最小的值x2也记录下来,对应最小百分比(比如5%),然后把x1, x2代入上式子,就可以算出, 的值。

参考:

https://blog.csdn.net/liunian920305/article/details/73456736

https://blog.csdn.net/u014657795/article/details/85850891

https://www.zhihu.com/question/312564645?rf=403423583
 

人脸识别相似度的计算可以使用Python和OpenCV库来实现。在使用OpenCV和Python进行人脸识别时,可以使用LBPH算法来进行相似度计算。根据引用的描述,该算法可以达到70%以上的相似度才能认为是识别成功。 另外,还可以使用百度人脸识别API进行人脸相似度识别对比,具体步骤如引用所述。首先,需要获取百度人脸识别API的API Key和Secret Key。然后,通过计算人脸的特征向量并将其存放到一个列表中,以便后续进行距离计算。具体实现可以参考引用的代码示例。 综上所述,使用Python和OpenCV可以实现人脸识别相似度的计算,而使用百度人脸识别API可以进行更为复杂的人脸相似度识别对比。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [基于opencv和python的人脸识别](https://download.csdn.net/download/GZM888888/87403576)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [python 人脸对比--百度API人脸相似度识别(超简单)](https://blog.csdn.net/swan_tang/article/details/88769612)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [用Python实现一个简单的——人脸相似度对比](https://blog.csdn.net/m0_38106923/article/details/83862334)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI周红伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值