计算两种人像之间的相似度

通过调研,目前存在几种能够计算两个人脸相似度的方法:

1.使用结构相似性计算人脸之间的相似度

  • 结构准确性生成的图片是否保留了原图足够多细节。

    • (1)结构准确性衡量指标:SSIM/MMSSIM

      • SSIM(结构相似性指标)、MMSIM(多尺度结构相似性指数):一种用于比较两张图像结构相似性的方法。与像PSNR和MSE这样基于差异的方法不同,SSIM/MMSIM试图模拟人类视觉系统的特性,更准确地反映图像的视觉质量。SSIM/MMSIM的通过比较两张图像在图像的亮度、对比度和结构三个方面的的相似性来计算它们的整体相似性,可以用于侧面衡量两张图片的结构相似性。

      • SSIM的计算公式如下:SSIM(x, y) = [l(x, y)*c(x, y)*s(x, y)]^β其中,x和y是两张图像,l(x, y)、c(x, y)和s(x, y)分别衡量了它们在亮度、对比度和结构上的相似性,β是一个调节三个部分相对重要性的参数。

    • (2)SSIM和MMSIM的取值范围都为:0~1

    • (3)取值意义:其中1表示两张图像结构层面完全相同,0表示它们结构完全不同

    • (4)不同生图类型的合格((SSIM+MMSSIM) /2)阈值参考

      • All >=0.4 ((SSIM+MMSSIM) /2)

由于ssim和mmsim都是基于对两张图片同一同一位置的像素点进行比较来判断 亮度、对比度和结构这三个方面最终得到结果,所以我们在调用方法之前必须将两张图片转化为同一大小,具体代码如下:
 

def calculate_mmssim(src,img):
    msssimValue = msssim(src, img).real
    return msssimValue
def calculate_psnr(src,img):
    psnrValue = psnr(src, img)
    return  psnrValue
# 打开图片并将图片转化为同一大小
src_image = Image.open(src_file_path_name)
make_image = Image.open(make_file_path_name)
srcimg = np.array(src_image.resize((268,372)))
makeimg = np.array(make_image.resize((268,372)))

但是如果那这样两张图片来比较人脸的相似度,显然是不够的,因为这种方法是总体上比较两张图片的相似度,想要实现人脸相似度的比较,则需要将人脸单独提取出来,并转化为同一大小,之后再比较人脸的相似度:

import cv2
from deepface import DeepFace
from PIL import Image
from tqdm import tqdm
import os
output_path = "./heads"
input_path = "./Newoutputimages_2"
if not os.path.isdir(output_path):
    os.mkdir(output_path)
# 读取origin里的所有图片
imgs = os.listdir(input_path)
for img in tqdm(imgs):
    if("_head_"in img):
        continue
    if not img.endswith((".png",".jpg",".jpeg")):
        continue
    # 组装所有的文件名
    path_fileName = os.path.join(input_path,img)
    print(path_fileName)
    #cv2读取其中的图片
    img_num = cv2.imread(path_fileName)
    results = DeepFace.extract_faces(path_fileName,detector_backend="retinaface",enforce_detection=False,align=False)
    for result in results:
        face_area = result['facial_area']
        img_new = Image.open(path_fileName)
        #result_file_num = Image.fromarray(img_num[face_area['y']:face_area['y']+face_area['h'],face_area['x']:face_area['x']+face_area['w']])
        print("imgimgigmgi",os.path.splitext(img))
        # cv2.imshow("face",img_num)
        # cv2.waitKey(0)
        img_crop = img_new.crop((face_area['x'],face_area['y'],face_area['x']+face_area['w'],face_area['y']+face_area['h']))
        path_real = os.path.join(output_path, "{}_head_.png".format(os.path.splitext(img)[0]))
        img_crop.save(path_real)
        #result_file_num.save(os.path.join(output_path,"{}_head_.png".format(os.path.splitext(img)[0])))

2.使用dlib算法标识68个人脸的特征位,然后根据68个特征点的位置,使用欧式距离算法,计算两张图片同一特征点之间的距离,最终通过不同特征点位赋予不同的比重计算最终的结果(结果越小说明越相似)

欧式距离(Euclidean distance)是最常用的距离测量方式之一,用于衡量多维空间中两点之间的直线距离。它的计算原理基于勾股定理,适用于二维、三维乃至更高维的空间。欧式距离的计算公式如下:

因此,欧式算法最终的结果主要与两个因素有关:1.两张图片不同特征点之间的距离2.识别的特征点在人脸中的位置(所以为了增加最终结果的准确性,必须对两张图片的人脸进行对齐)

from deepface import DeepFace
import os
import openpyxl
import time
from tqdm import tqdm
import re
import dlib
import numpy as np
import cv2
from scipy.spatial import distance
pypath = os.path.dirname(__file__)
def get_landmarks(image):
    faces = detector(image, 1)
    if len(faces) > 0:
        landmarks = predictor(image, faces[0])
        return np.array([[p.x, p.y] for p in landmarks.parts()])
    return None
def get_results(img1,img2):
    image1 = dlib.load_rgb_image(img1)
    image2 = dlib.load_rgb_image(img2)
    image1_gray = dlib.as_grayscale(image1)
    image2_gray = dlib.as_grayscale(image2)
    image1_gray_np = np.array(image1_gray).astype(np.uint8)
    image2_gray_np = np.array(image2_gray).astype(np.uint8)
    # 调整图像大小到新的尺寸
    resized_image1 = cv2.resize(image1_gray_np, (268, 372), interpolation=cv2.INTER_AREA)
    resized_image2 = cv2.resize(image2_gray_np, (268, 372), interpolation=cv2.INTER_AREA)

    # 如果你需要将调整大小后的图像转换回dlib的array2d类型
    # resized_image_dlib1 = dlib.array(resized_image1)
    # resized_image_dlib2 = dlib.array(resized_image2)
    # 提取两个图像的特征点
    landmarks1 = get_landmarks(resized_image1)
    landmarks2 = get_landmarks(resized_image2)

    # 如果两张图片中都检测到了面部,那么计算相似度
    if landmarks1 is not None and landmarks2 is not None:
        # 分别定义眼睛、鼻子、嘴巴和其他特征点的索引
        eyes_indices = list(range(36, 48))
        nose_indices = list(range(27, 36))
        mouth_indices = list(range(48, 68))
        # other_indices = list(range(0, 27)) + list(range(68, 68))
        other_indices = list(range(0, 36)) + list(range(48, 68))

        # 计算每个部分的相似度
        eyes_similarity = np.mean([distance.euclidean(landmarks1[i], landmarks2[i]) for i in eyes_indices])
        nose_similarity = np.mean([distance.euclidean(landmarks1[i], landmarks2[i]) for i in nose_indices])
        mouth_similarity = np.mean([distance.euclidean(landmarks1[i], landmarks2[i]) for i in mouth_indices])
        other_similarity = np.mean([distance.euclidean(landmarks1[i], landmarks2[i]) for i in other_indices])

        # 应用权重
        weighted_similarity = (
                0.6 * eyes_similarity +0.4*other_similarity
                # 0.2 * nose_similarity +
                # 0.2 * mouth_similarity +
                # 0.2 * other_similarity
        )
        return weighted_similarity
excel_output_file = os.path.join(pypath, "calculte_model_simi_dlib{}.xlsx".format(
    time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))))

img_path1 = ""
img_path2 = ""
input_file_path = "/Users/liujianlei/pycharmProjects/day1/AITest/dlibtest/testHeads"
# 初始化dlib的面部检测器和特征点预测器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
wb = openpyxl.Workbook()
ws =wb.active
ws.append(["img_name","simi_value"])
#wb.save(excel_output_file)
imgs_names = os.listdir(input_file_path)
for img_name in tqdm(imgs_names):
    real_file_path = os.path.join(input_file_path,img_name)
    pattern = re.compile(r"^\d+")
    src_file_path = pattern.match(img_name)
    print("imgde name wei ", img_name)
    src_file_name = src_file_path.group()
    src_file_path_name = os.path.join(input_file_path, src_file_name + ".png")
    # 提取当前的图片名
    make_file_path_name = os.path.join(input_file_path, img_name)
    # 判断是否是原图
    if src_file_path_name == make_file_path_name:
        continue
    result = get_results(src_file_path_name,make_file_path_name)
    # results = DeepFace.verify(src_file_path_name,make_file_path_name,model_name="ArcFace",enforce_detection=False,align=True)
    ws.append([img_name,result])
    #wb.save(excel_output_file)
# 遍历结束后保存
wb.save(excel_output_file)

MICROSOFT 基础类库: 人脸相似度检测MFC 项目概述 =============================================================================== 应用程序向导已为您创建了这个 人脸相似度检测MFC 应用程序。此应用程序不仅演示 Microsoft 基础类的基本使用方法,还可作为您编写应用程序的起点。 本文件概要介绍组成 人脸相似度检测MFC 应用程序的每个文件的内容。 人脸相似度检测MFC.vcproj 这是使用应用程序向导生成的 VC++ 项目的主项目文件。 它包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。 人脸相似度检测MFC.h 这是应用程序的主要头文件。它包括其他项目特定的头文件(包括 Resource.h),并声明 C人脸相似度检测MFCApp 应用程序类。 人脸相似度检测MFC.cpp 这是包含应用程序类 C人脸相似度检测MFCApp 的主要应用程序源文件。 人脸相似度检测MFC.rc 这是程序使用的所有 Microsoft Windows 资源的列表。它包括 RES 子目录中存储的图标、位图和光标。此文件可以直接在 Microsoft Visual C++ 中进行编辑。项目资源位于 2052 中。 res\人脸相似度检测MFC.ico 这是用作应用程序图标的图标文件。此图标包括在主要资源文件 人脸相似度检测MFC.rc 中。 res\MFC.rc2 此文件包含不在 Microsoft Visual C++ 中进行编辑的资源。您应该将不可由资源编辑器编辑的所有资源放在此文件中。 ///////////////////////////////////////////////////////////////////////////// 应用程序向导创建一个对话框类: 人脸相似度检测MFCDlg.h,人脸相似度检测MFCDlg.cpp - 对话框 这些文件包含 C人脸相似度检测MFCDlg 类。该类定义应用程序主对话框的行为。该对话框的模板位于 人脸相似度检测MFC.rc 中,该文件可以在 Microsoft Visual C++ 中进行编辑。 ///////////////////////////////////////////////////////////////////////////// 其他功能: ActiveX 控件 应用程序包括对使用 ActiveX 控件的支持。 ///////////////////////////////////////////////////////////////////////////// 其他标准文件: StdAfx.h,StdAfx.cpp 这些文件用于生成名为 人脸相似度检测MFC.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。 Resource.h 这是标准头文件,它定义新的资源 ID。 Microsoft Visual C++ 读取并更新此文件。 人脸相似度检测MFC.manifest 应用程序清单文件供 Windows XP 用来描述应用程序 对特定版本并行程序集的依赖性。加载程序使用此 信息从程序集缓存加载适当的程序集或 从应用程序加载私有信息。应用程序清单可能为了重新分发而作为 与应用程序可执行文件安装在相同文件夹中的外部 .manifest 文件包括, 也可能以资源的形式包括在该可执行文件中。 ///////////////////////////////////////////////////////////////////////////// 其他注释: 应用程序向导使用“TODO:”指示应添加或自定义的源代码部分。 如果应用程序在共享的 DLL 中使用 MFC,则需要重新发布这些 MFC DLL;如果应用程序所用的语言与操作系统的当前区域设置不同,则还需要重新发布对应的本地化资源 MFC90XXX.DLL。有关这两个主题的更多信息,请参见 MSDN 文档中有关 Redistributing Visual C++ applications (重新发布 Visual C++ 应用程序)的章节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

刘子干测开

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

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

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

打赏作者

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

抵扣说明:

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

余额充值