【Milvus的人脸检索】

news2024/11/29 20:42:01

0. 介绍

在上一篇文章中,介绍了milvus提供的以图搜图的样例,这篇文章就在以图搜图样例的基础上进行修改,实现人脸检索。

常见的人脸任务,分为人脸检测、人脸识别、人脸对比和人脸检索,其中人脸检索的含义是:对给定一张人脸照片,和已有人脸库中的N个人脸进行比对,找出最相似的一张脸或多张脸,并给出相似度排序,实现1 : N或M:N搜索。

现如今,大部分云平台都实现了人脸相关的算法应用,并提供相关的服务,如下图为腾讯云人脸页面相关介绍,可以通过点击链接,体验相关的功能。其他商家的链接如下:

  • 百度云:https://ai.baidu.com/tech/face/search
  • face++:人脸搜索 - 旷视Face⁺⁺人工智能开放平台 

 此外,人脸检索的应用场景也十分广泛,如旷视下图所描述的一样。

本文使用insightface库来实现对图像中人脸的定位和特征提取,基于insightface构建一个人脸特征提取类,然后修改相应的特征提取函数接口,最后将人脸特征插入到milvus和MySQL数据库中,以便后续进行人脸检索。好了,接下来就让我们看看如何基于milvus向量数据库和insightface实现百万级人脸检索。

1. insightface使用

insightface是一个非常高效的人脸分析库,利用insightface使用极少的代码就能实现对图像中人脸定位、人脸gender和age分析、人脸的landmark以及人脸识别等等功能。

1.1 安装insightface

insightface的安装方式非常简单,使用pip即可,安装命令如下:

pip install insightface

安装完成之后,新建文件,粘贴如下代码,即可测试安装是否正确

import cv2
import numpy as np
import insightface
from insightface.app import FaceAnalysis
from insightface.data import get_image as ins_get_image

app = FaceAnalysis(providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
app.prepare(ctx_id=0, det_size=(640, 640))
img = ins_get_image('t1')
faces = app.get(img)
rimg = app.draw_on(img, faces)
cv2.imwrite("./t1_output.jpg", rimg)

 上述代码,构建FaceAnalysis对象,完成人脸定位、人脸属性分析和人脸特征提取等工作,并将结果保存到t1_output.jpg文件中。

1.2 安装onnxruntime-gpu

如下图所示,当insightface的版本大于等于0.2时,采用onnxruntime作为推理框架,默认使用CPU进行推理,因此,为了加快模型运行速度,可以安装onnxruntime-gpu来利用GPU资源加速推理。

安装onnxruntime-gpu库的命令非常简单,使用pip安装即可,命令如下:

pip install onnxruntime-gpu

 但是,由于cuda环境和onnxruntime-gpu版本的不匹配,会导致无法利用GPU。因此,在安装onnxruntime-gpu之前,需要查看当前设备cuda和cudnn的版本,从而安装正确版本的onnxruntime-gpu。如我的设备的cuda版本为11.4,按照下表安装合适的版本。大家可以通过该链接查询,需要安装的版本。

 通过下面代码可以简单测试onnxruntime-gpu是否安装正确。

import onnxruntime as ort

print(ort.get_device())
# print(ort.get_all_providers())
print(ort.get_available_providers())

输出如下所示,当打印的available_providers中包含CUDAExecutionProvider即可。

GPU
['TensorrtExecutionProvider', 'CUDAExecutionProvider', 'CPUExecutionProvider']

2. 构建特征提取网络

基于insightface,可以使用极少的代码构建人脸的特征提取网络,具体代码查考如下。

from insightface.app import FaceAnalysis
import insightface
# import os
import cv2
# from tqdm import tqdm
# import pickle
assert insightface.__version__>='0.3'


class FaceRecognition():
    def __init__(self) -> None:
        self.app = FaceAnalysis(allowed_modules=['detection', 'recognition',"genderage"], providers=['CUDAExecutionProvider'])
        # detection network input size
        self.app.prepare(ctx_id=0, det_size=(640, 640))

    def extract_face_features(self, img_path):
        try:
            img_data = cv2.imread(img_path)
            feats = self.app.get(img_data)
        except Exception as e:
                return 
        return feats        # list

 通过上述代码,就能完成对一张图像中每个人脸特征的提取,具体来说,包括人脸的位置信息、关键点信息、人脸对应的性别和年龄,以及人脸的特征信息

3. milvus的使用

以milvus中以图搜图代码为基础,对其中的文件内容进行修改来实现人脸检索功能。

3.1 encode

使用第2节中的特征提取代码替换encode.py文件中的内容。

3.2 load操作

由于特征提取接口返回内容的结果发生变化,因此需要对load.py文件中extract_features函数进行相应的修改,代码内容如下:

# Get the vector of images
def extract_features(img_dir, model):
    try:
        cache = Cache('./tmp')
        face_embeddings = list()
        face_properites = list()
        img_list = get_imgs(img_dir)
        total = len(img_list)
        cache['total'] = total
        for i, img_path in enumerate(img_list):
            try:
                # path_encoded_list,norm_feat = model.batch_extract_feat(img_dir)
                faces = model.extract_face_features(img_path)
                for face in faces:

                    face_embeddings.append(face.normed_embedding)
                    face_dict = {
                        "image_path": img_path,
                        "gender": face["gender"],
                        "age": face["age"]
                    }
                    face_properites.append(face_dict)
                    cache['current'] = i+1
                    print(f"Extracting feature from image No. {i + 1} , {total} images in total")
            except Exception as e:
                LOGGER.error(f"Error with extracting feature from image {e}")
                continue
        return face_embeddings, face_properites
    except Exception as e:
        LOGGER.error(f"Error with extracting feature from image {e}")
        sys.exit(1)

此外插入到MySQL中的内容也发生了变化,因此,插入数据的形式的format_data函数内容,修改成如下:

# Combine the id of the vector and the name of the image into a list
def format_data(ids, properites):
    data = []
    for i in range(len(ids)):
        value = (str(ids[i]), properites[i]["image_path"].encode(), properites[i]["gender"], properites[i]["age"])
        data.append(value)
    return data

对应的MySQL创建table和插入数据的语句也需要修改成如下:

    def create_mysql_table(self, table_name):
        # Create mysql table if not exists
        self.test_connection()
        sql = "create table if not exists " + table_name + "(milvus_id TEXT, image_path TEXT, gender BOOLEAN, age INT );"
        try:
            self.cursor.execute(sql)
            LOGGER.debug(f"MYSQL create table: {table_name} with sql: {sql}")
        except Exception as e:
            LOGGER.error(f"MYSQL ERROR: {e} with sql: {sql}")
            sys.exit(1)
    def load_data_to_mysql(self, table_name, data):
        # Batch insert (Milvus_ids, img_path) to mysql
        self.test_connection()
        sql = "insert into " + table_name + " (milvus_id,image_path, gender, age) values (%s,%s, %s, %s);"
        try:
            self.cursor.executemany(sql, data)
            self.conn.commit()
            LOGGER.debug(f"MYSQL loads data to table: {table_name} successfully")
        except Exception as e:
            LOGGER.error(f"MYSQL ERROR: {e} with sql: {sql}")
            sys.exit(1)

3.3 配置文件

由于特征提取网络发生了变换,默认情况下,人脸采用arcfac-resnet50提取特征维度为512,因此,需要对VECTOR_DIMENSION进行修改。同样,为了与以图搜图分开,将DEFAULT_TABLE修改为milvus_face_search,具体修改如下图所示。

 至此,我们完成了代码的相关修改,接下来只需要启动服务,插入数据样本库,执行搜索即可。

4. 启动服务

如上一篇文章一样,使用如下命令,启动服务。

uvicorn main:app --reload

 在浏览器中输入127.0.0.1:8000/docs进入FastAPI - Swagger UI,得到如下页面内容。

 进入/img/load条目,输入table名称和数据样本库的路径,构建图像的向量样本库用于后续的检索

 进入/embedding/load条目,输入table名称,将数据加载到内存中。

 进入/img/search条目,输入table名称、图像文件和topK值,执行检索

返回topK个与目标图像相似的文件路径。

 5. 启动客户端

如上一篇文章一样,启动milvus提供的 milvusbootcamp/img-search-client:1.0   容器,在浏览器中输入127.0.0.1:80001即可进入客户端。

 从上图中可以看到当前的样本库大小为8000余个数据,由于这里只是做一个demo,所以没有插入上百万级数据,俺也没有这么多数据库🤣🤣🤣🤣🤣😂。

祭出神仙姐姐作为目标样本,得到如下的搜索结果。

 6. 总结

在本文中,基于milvus和insightface库,主要叙述了相关的实现过程,实现了对假的百万级人脸检索,哈哈✔😎

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/26408.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

点成分享 | 蛋白质浓度测定之考马斯亮蓝(Bradford)法

蛋白质是组成生物细胞、组织的重要成分,生物的所有生命活动都离不开蛋白质的参与。蛋白质是生命的物质基础,是构成细胞的基本有机物,是生命活动的主要承担者。生物材料中蛋白质含量的测定是生物学研究中最重要也是最基本的实验操作之一&#…

【微机接口】串行通信基础

计算机通信:CPU与外部的信息交换 并行通信:数据所有位同时被传输 串行通信:数据被逐位顺序传送 串行通信类型: 串行异步通信:一个字符用起始位和停止位来完成收发同步。 串行同步通信:采用同步字符来完成收发双方同…

营丘福稻品牌山东大米 国稻种芯·中国水稻节:淄博高青招牌

营丘福稻品牌山东大米 国稻种芯中国水稻节:淄博高青招牌 淄博市广播电视台新生活 大众网海报新闻记者 董玉歌 淄博报道) 新闻中国采编网 中国新闻采编网 谋定研究中国智库网 中国农民丰收节国际贸易促进会 国稻种芯中国水稻节 中国三农智库网-功能性农业农业大健…

【电源专题】案例:电源芯片规格书大标题写5A那是能输出5A吗?

这个案例是找到了问题点后再去审查规格书发现规格书里竟然有写明!只是最初始不是我导入的芯片就是了(其实就算是我导入的,以前也没有测试方法和手段能发现异常),而且这个芯片已经用了好久好久了,现在都停产了,买不到了。 从下图所示的规格书大标题中可以看到同步升压芯片…

苹果Mac电脑L2TP连接公司内部网络失败解决方案

苹果Mac电脑L2TP连接公司内部网络 苹果Mac系统在创建VPN连接时,一直提示:L2TP-VPN服务器没有响应。请尝试重新连接。如果仍然有问题,请验证你的设置并与管理员联系。 我们在添加VPN的时候需要填写机器认证中的共享秘钥,我这里填…

详解容灾恢复过程中跨数据中心级的关键故障切换

【摘要】容灾设计过程当中需要考虑的故障切换的场景有很多,数据中心内部的高可用切换不在本次讨论范围之内,我们讨论的是容灾恢复过程中的关键跨数据中心级的故障切换场景,从网络层到存储层都会涉及到。(文中涉及相关技术产品参数请以官网最新发布为准) 1. 容灾设计需要进…

c++异常处理

目录 1.c异常的由来 2.怎么使用异常来解决问题 3.异常安全 4.异常规范 5.异常处理的优缺点 1.c异常的由来 在c语言中,如果程序出现了错误,采用的是返回错误码的方式。最常见的: int main() {return 0; } 这里的return 0的0就是表示返…

Kubernetes学习(一)入门及集群搭建

一、简介 1.简介 Kubernetes 最初源于谷歌内部的Borg,Kubernetes 是一个全新的基于容器技术的分布式架构解决方案。 包含几个基本功能: 1.将应用水平扩容到多个集群 2.为扩容的实例提供负载均衡策略 3.提供基本的健康检查和自愈能力 4.实现任务的…

电机无位置控制方法研究

无位置控制方法研究 1.无位置控制技术研究现状 2.反电动势过零检测法 3.反电动势三次谐波积分检测法 4.续流二极管法 5.磁链法 6.扩展卡尔曼滤波算法(EKF) 7.基于扩展卡尔曼滤波算法(EKF)的转速及位置估算 8.电感测量法 9.涡流效…

LeetCode-878. 第 N 个神奇数字【数学,二分查找,找规律】

LeetCode-878. 第 N 个神奇数字【数学,二分查找,找规律】 题目描述:解题思路一:二分答案容斥原理。给定一个上下界,然后依次增大下界或者减小上界,直到只剩一个答案。容斥原理是,加上两个集合&a…

六、TCP实现聊天

客户端: 连接服务器 Socket(address,port)发送消息 import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets;/*** 客…

LabVIEW使用VI Snippets存储和共享重用代码段

LabVIEW使用VI Snippets存储和共享重用代码段 VI Snippets是存储、共享和重用LabVIEW代码小部分的新方式。VI代码段将截图的可移植性与VI文件的功能结合在标准PNG图像中嵌入LabVIEW代码。当将VI代码段PNG图像拖到框图上时,它会将代码片段作为图形代码拖放&#xff…

【C++】重载运算符+-=>/*[]==++-- MyString 智能指针(* ->)

目录 15.重载运算符 15.1 eg.Person 15.2 eg.MyString 15.3 智能指针 15.重载运算符 定义&#xff1a;给原有的运算符赋予新的意义。 为什么重载<<或>>一定要用友元&#xff1f; 如果是重载双目操作符&#xff08;即为类的成员函数&#xff09;&#xff0c;就…

10年老码农亲授:什么是分布式系统

首先&#xff0c;分布式系统是在硬件成本日益提高&#xff0c;或者单机提升的成本过于昂贵而程序的问题得不到解决时&#xff0c;为了解决更加高效、内容量更大的数据而采取的一种解决手段。 而分布式系统又分为两个部分&#xff0c;计算和存储&#xff0c;而准确来说这两部分…

知行之桥EDI系统2022版Tomcat部署

1.首先需要下载Tomcat&#xff0c;可在Tomcat官网获取&#xff0c;本部署步骤以apache-tomcat-9.0.67.tar.gz为例&#xff0c;通过XFTP将该包放在服务器上的指定位置&#xff0c;如/opt/test 进入/opt/test文件夹后&#xff0c;在命令行执行以下命令对该包进行解压缩 tar -zxv…

大数据毕设 - 公交数据分析与可视化系统(大数据 python flask)

文章目录0 前言1 课题背景2 具体实现3 Flask框架4 ECharts可视化工具5 最后0 前言 &#x1f525; Hi&#xff0c;大家好&#xff0c;这里是丹成学长的毕设系列文章&#xff01; &#x1f525; 对毕设有任何疑问都可以问学长哦! 这两年开始&#xff0c;各个学校对毕设的要求越…

Smart Tomcat + Servlet API的应用

文章目录前言一、Smart Tomcat二、Servlet API1.HttpServlet&#xff08;1&#xff09;方法&#xff08;2&#xff09;描述servlet的生命周期&#xff08;3&#xff09;案例2.HttpServletRequest&#xff08;1&#xff09;方法&#xff08;2&#xff09;代码示例打印请求信息获…

若依框架图片上传、富文本框编辑器功能

文章目录一、前言二、效果三、编码过程1.前端&#xff1a;index.vueprojectShow.js富文本框: Editor/index.vue图片上传&#xff1a;ImgUploadCropper/index.vue2.后端&#xff1a;实体ProjectShowProjectShowControllerIProjectShowServiceProjectShowServiceImplProjectShowM…

Linux命令大全

前言 Linux 的学习对于一个程序员的重要性是不言而喻的。前端开发相比后端开发&#xff0c;接触 Linux机会相对较少&#xff0c;因此往往容易忽视它。但是学好它却是程序员必备修养之一。 作者使用的是阿里云服务器 ECS &#xff08;最便宜的那种&#xff09; CentOS 7.7 64位…

指针初阶(C语言)

指针 指针是什么 内存划分是一个字节一个字节来划分的&#xff0c;其中每个字节都有一个编号来标识它&#xff0c;我们将这个编号称为地址&#xff0c;而指针就是地址 注意&#xff1a;编号是不占内存空间的&#xff0c;&#xff08;这些编号在内存中用十六进制表示&#xff0…