比较二张图片相似度包括人脸识别,接口用fastapi

####引入requestments.txt:

face_recognition==1.3.0
fastapi==0.111.0
numpy==1.26.4
opencv_python==4.9.0.80
Pillow==10.3.0
Requests==2.32.1
uvicorn==0.29.0

####二张图片相似度:

# -*- coding: utf-8 -*-
import os
import uuid
from PIL import Image
import requests
from io import BytesIO


# 对图片进行统一化处理
def get_thum(image, size=(64, 64), greyscale=False):
    if image is None:
        raise ValueError("Cannot process None image")
    image = image.resize(size, Image.ANTIALIAS)
    if greyscale:
        image = image.convert('L')
    return image


def getpic(image_url):
    random_filename = str(uuid.uuid4()) + '.jpg'
    try:
        response = requests.get(image_url)
        if response.status_code == 200:
            image_content = response.content
            image_stream = BytesIO(image_content)
            image = Image.open(image_stream)
            save_path = random_filename
            image.save(save_path)
            print(f'图片已保存到:{os.path.abspath(save_path)}')
            # 这里应该返回 Image 对象,而不是文件路径
            # 但是由于我们稍后要关闭文件,所以返回文件路径,并在需要时重新打开
            return save_path
        else:
            print('无法获取图片,服务器响应码:', response.status_code)
    except requests.exceptions.InvalidURL as e:
        print(f"Invalid URL: {e}")
    except requests.exceptions.RequestException as e:
        print(f"An error occurred while making the request: {e}")

    # 计算图片的余弦距离(实际上计算的是余弦相似度)


def similarity_pics(image_path1, image_path2):
    # 打开图像文件并获取 Image 对象
    image1 = Image.open(image_path1).convert('L')
    image2 = Image.open(image_path2).convert('L')

    # 确保图像是相同的大小和模式(例如,都是 RGB 或都是 L(灰度))
    # 这里我们假设图像已经是相同的大小,因为它们都经过了 get_thum 的处理

    # 将图像转换为向量
    # 注意:这里的实现方式可能需要更改,因为直接将像素值平均可能不是最佳方式
    # 通常,您可能会将图像转换为特征向量,使用例如 SIFT、SURF 或其他图像特征提取方法
    vectors = [list(map(int, image1.getdata())), list(map(int, image2.getdata()))]

    # 计算向量的余弦相似度
    a, b = vectors
    a_norm = sum([x ** 2 for x in a]) ** 0.5
    b_norm = sum([x ** 2 for x in b]) ** 0.5
    dot_product = sum(a_i * b_i for a_i, b_i in zip(a, b))
    similarity = dot_product / (a_norm * b_norm)

    return similarity

这里getpic将网上的图片下载到服务器进行比对:

人脸比对代码:
import cv2
import face_recognition


def face_comparison(pic1, pic2):
    """
    比较两张图片中的人脸是否相同,并返回相似度结果和欧氏距离。

    参数:
        pic1 (str): 第一张图片的路径。
        pic2 (str): 第二张图片的路径。

    返回:
        dict: 包含比较结果的字典,包含code、same和re键。
    """
    # 加载图片并转换为RGB格式
    reference_image = face_recognition.load_image_file(pic1)
    reference_image = cv2.cvtColor(reference_image, cv2.COLOR_BGR2RGB)

    test_image = face_recognition.load_image_file(pic2)
    test_image = cv2.cvtColor(test_image, cv2.COLOR_BGR2RGB)

    # 尝试定位人脸并提取特征编码
    try:
        reference_face_locations = face_recognition.face_locations(reference_image)
        if not reference_face_locations:
            raise ValueError("No face found in the reference image.")
        reference_face_encoding = face_recognition.face_encodings(reference_image)[0]

        test_face_locations = face_recognition.face_locations(test_image)
        if not test_face_locations:
            raise ValueError("No face found in the test image.")
        test_face_encoding = face_recognition.face_encodings(test_image)[0]

    except IndexError as e:
        raise ValueError("An error occurred while processing the images.") from e

        # 比较人脸并计算欧氏距离
    is_same_person = face_recognition.compare_faces([reference_face_encoding], test_face_encoding)[0]
    euclidean_distance = face_recognition.face_distance([reference_face_encoding], test_face_encoding)[0]

    # 返回结果字典
    return {
        "code": 200,
        "same": str(is_same_person),  # 将布尔值转换为字符串以便在JSON中传输
        "re": euclidean_distance
    }

# 注意:在实际应用中,您可能还想添加代码来显示或保存带有矩形框的图片。
# 但这通常不是此函数的核心职责,因此我将其省略。
FASTAPI代码:
import os
import uvicorn
from fastapi import FastAPI, Form, HTTPException
from getpic import similarity_pics, getpic
from sameface import face_comparison

app = FastAPI()


@app.get("/")
async def index():
    """  
    根路径,返回自定义消息。  
    """
    return {"message": "自定义请求"}


@app.post("/")
async def compare_topics(type: str = Form(...), pic1: str = Form(...), pic2: str = Form(...)):
    """  
    比较两张图片,根据类型返回相似度或人脸识别结果。  
    """
    try:
        image1_path = getpic(pic1)  # 获取图片1的路径  
        image2_path = getpic(pic2)  # 获取图片2的路径  

        # 验证图片路径是否有效  
        if not (os.path.exists(image1_path) and os.path.exists(image2_path)):
            raise HTTPException(status_code=400, detail="图片获取失败或路径无效")

            # 根据类型进行比较  
        if type == "face":
            result = face_comparison(image1_path, image2_path)  # 人脸识别比较  
        else:
            result = similarity_pics(image1_path, image2_path)  # 图片相似度比较  

        # 删除临时图片文件(假设不再需要)  
        os.remove(image1_path)
        os.remove(image2_path)

        # 返回结果  
        return result

    except Exception as e:
        # 捕获并处理任何异常  
        print(f"发生错误: {e}")
        raise HTTPException(status_code=500, detail="服务器内部错误")


@app.get("/about")
async def about():
    """  
    返回项目信息。  
    """
    return {
        "code": 200,
        "message": "人工智能识别",
        "version": "v0.0.1"
    }


if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=8333)
    #uvicorn main:app --host 127.0.0.1 --port 8333

预处理:读取图片 第一步,缩小尺寸。 将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。 第二步,简化色彩。 将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。 第三步,计算平均值。 计算所有64个像素的灰度平均值。 第四步,比较像素的灰度。 将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。 第五步,计算哈希值。 将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。 得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算"汉明距离"(Hammingdistance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。 你可以将几张图片放在一起,也计算出他们的汉明距离对比,就可以看看两张图片是否相似。 这种算法的优点是简单快速,不受图片大小缩放的影响,缺点是图片的内容不能变更。如果在图片上加几个文字,它就认不出来了。所以,它的最佳用途是根据缩略图,找出原图。 实际应用中,往往采用更强大的pHash算法和SIFT算法,它们能够识别图片的变形。只要变形程度不超过25%,它们就能匹配原图。这些算法虽然更复杂,但是原理与上面的简便算法是一样的,就是先将图片转化成Hash字符串,然后再进行比较。 以上内容大部分直接从阮一峰的网站上复制过来,想看原著的童鞋可以去在最上面的链接点击进去看。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

老大白菜

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

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

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

打赏作者

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

抵扣说明:

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

余额充值