人脸注册应用程序工作流
面部识别技术已成为一股无处不在的力量,重塑了安全、社交媒体和智能手机身份验证等行业。在这篇博客中,我们深入探讨了面部识别的迷人领域,并配备了强大的 Python、OpenCV、图像嵌入和 Qdrant 三重奏。加入我们的旅程,我们将解开创建强大的面部识别系统的复杂性。
在第 1 部分中,我们通过深入研究面部识别技术的基础知识来奠定基础。了解基本原理,探索其应用,并掌握 Python 和 OpenCV 在我们的开发堆栈中的重要性。
任何项目的关键步骤都是准备开发环境。了解如何无缝集成 Python、OpenCV 和 Qdrant,为我们的面部识别系统创建一个和谐的生态系统。我们提供分步说明,确保您在继续前进之前有坚实的基础。
随着基础工作到位,我们深入研究项目的核心。探索面部识别算法的复杂性,并见证我们使用 Python 和 OpenCV 实现它们时的魔力。揭示人脸检测、特征提取和模型训练的内部工作原理。
如果没有强大的数据库来有效地存储和管理面部数据,任何面部识别系统都是不完整的。在最后一期中,我们将指导您完成Qdrant的集成,以增强我们系统的存储和检索功能。见证 Python、OpenCV 和 Qdrant 之间的协同作用,我们将项目推向高潮。
在本博客结束时,您将全面了解面部识别技术以及开发自己的系统的实用技能。
该实验展示了 Python OpenCV 和高级 AI 技术在创建复杂的面部识别/搜索应用程序方面的实际实施,展示了增强用户交互和认知响应的潜力。由于图像是敏感数据,我们不想依赖任何在线服务或将它们上传到互联网上。上面定义的整个管道被开发为100%在本地工作。
OpenCV 或开源计算机视觉库是一个开源计算机视觉和机器学习软件库。OpenCV 最初由英特尔开发,现在由开发人员社区维护。它为图像和视频分析提供了广泛的工具和功能,包括用于图像处理、计算机视觉和机器学习的各种算法。
OpenCV 的主要功能包括:
OpenCV 广泛用于学术界、工业界和研究领域,用于从简单的图像处理到复杂的计算机视觉和机器学习应用程序的任务。它的多功能性和全面的工具集使其成为在计算机视觉领域工作的开发人员的首选库。
这是一个 Python 包,用于使用 OpenAI 强大的 CLIP 模型通过 Hugging Face 转换器从图像生成嵌入向量。这些图像嵌入源自一个图像模型,该模型在2020年年中之前已经看到了整个互联网,可用于许多方面:无监督聚类(例如通过umap),嵌入搜索(例如通过faiss),以及将下游用于其他与框架无关的ML / AI任务,例如构建分类器或计算图像相似性。
向量存储是专门用于高效存储和检索向量嵌入的数据库。这种专业化至关重要,因为像 SQL 这样的传统数据库没有针对处理大量向量数据进行微调。
嵌入在高维空间中以数值向量格式表示数据,通常是非结构化数据,如文本或图像。传统的关系数据库不适合存储和检索这些向量表示。
https://qdrant.tech/documentation
Qdrant 是一个专门的矢量相似性搜索引擎,旨在通过用户友好的 API 提供生产就绪服务。它有助于点(向量)以及其他有效载荷的存储、搜索和管理。这些有效载荷作为补充信息,提高搜索的精度,并为用户提供有价值的数据。
Qdrant 的入门是无缝的。利用 Python qdrant-client,访问 Qdrant 的最新 Docker 映像并建立本地连接,或探索 Qdrant 的 Cloud 免费套餐选项,直到您准备好进行全面过渡。
在一组文档或术语的上下文中,语义相似性是一种指标,它根据项目的含义或语义内容的相似性来衡量项目之间的距离,而不是依赖于词典相似性。这涉及使用数学工具来评估语言单元、概念或实例之间语义关系的强度。通过此过程获得的数字描述是通过比较支持其含义或描述其性质的信息而得出的。
区分语义相似性和语义相关性至关重要。语义关联性包括两个术语之间的任何关系,而语义相似性具体涉及“是”关系。这种区别阐明了语义比较的细微差别及其在各种语言和概念环境中的应用。
pip install qdrant-client imgbeddings pillow opencv-python
mkdir photos
从 OpenCV GitHub 存储库下载haarcascade_frontalface_default.xml预训练的 Haar 级联模型并将其存储在本地。
此代码是在 Google Colab 上使用 Python 实现的。
#import required libraries
import cv2
import numpy as np
from imgbeddings import imgbeddings
from PIL import Image
def detect_face(image_path,target_path):
# loading the haar case algorithm file into alg variable
alg = "haarcascade_frontalface_default.xml"
# passing the algorithm to OpenCV
haar_cascade = cv2.CascadeClassifier(alg)
# loading the image path into file_name variable
file_name = image_path
# reading the image
img = cv2.imread(file_name, 0)
# creating a black and white version of the image
gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
# detecting the faces
faces = haar_cascade.detectMultiScale(gray_img, scaleFactor=1.05, minNeighbors=2, minSize=(100, 100))
# for each face detected
for x, y, w, h in faces:
# crop the image to select only the face
cropped_image = img[y : y + h, x : x + w]
# loading the target image path into target_file_name variable
target_file_name = target_path
cv2.imwrite(
target_file_name,
cropped_image,
)
以下代码负责
faces = haar_cascade.detectMultiScale(gray_img, scaleFactor=1.05, minNeighbors=2, minSize=(100, 100))
哪里:
for 循环遍历检测到的所有人脸,并将它们存储在单独的文件中。您可能希望定义一个变量(可能使用 x 和 y 参数)以将各种面孔存储在不同的文件中。
人脸检测阶段的结果并不完美:它可以识别出四张可见的四张脸中的三张,但对于我们的目的来说已经足够好了。您可以微调算法参数,以找到更适合您的用例的参数。
def generate_embeddings(image_path):
#
# loading the face image path into file_name variable
file_name = "/content/target_photo_1.jpg"
# opening the image
img = Image.open(file_name)
# loading the `imgbeddings`
ibed = imgbeddings()
# calculating the embeddings
embedding = ibed.to_embeddings(img)[0]
emb_array = np.array(embedding).reshape(1,-1)
return emb_array
os.mkdir("target")
# loop through the images in the photos folder and extract faces
file_path = "/content/photos"
for item in os.listdir(file_path):
if item.endswith(".jpeg"):
detect_face(os.path.join(file_path,item),os.path.join("/content/target",item))
img_embeddings = [generate_embeddings(os.path.join("/content/target",item)) for item in os.listdir("/content/target")]
print(len(img_embeddings))
#
print(img_embeddings[0].shape)
#
#save the vector of embeddings as a NumPy array so that we don't have to run it again later
np.save("vectors_cv2", np.array(img_embeddings), allow_pickle=False)
# Create a local Qdrant vector store
client =QdrantClient(path="qdrant_db_cv2")
#
my_collection = "image_collection_cv2"
client.recreate_collection(
collection_name=my_collection,
vectors_config=models.VectorParams(size=768, distance=models.Distance.COSINE)
)
# generate metadata
payload = []
files_list= os.listdir("/content/target")
for i in range(len(os.listdir("/content/target"))):
payload.append({"image_id" :i,
"name":files_list[i].split(".")[0]})
print(payload[:3])
ids = list(range(len(os.listdir("/content/target"))))
#Load the embeddings from the save pickle file
embeddings = np.load("vectors_cv2.npy").tolist()
#
# Load the image embeddings
for i in range(0, len(os.listdir("/content/target"))):
client.upsert(
collection_name=my_collection,
points=models.Batch(
ids=[ids[i]],
vectors=embeddings[i],
payloads=[payload[i]]
)
)
client.count(
collection_name=my_collection,
exact=True,
)
##Response
CountResult(count=6)
client.scroll(
collection_name=my_collection,
limit=10
)
加载新图像并提取人脸
load_image_path = '/content/target/Aishw.jpeg'
target_image_path = 'black.jpeg'
detect_face(load_image_path,target_path)
Image.open("/content/black.jpeg")
灰度裁剪的人脸图像已保存
query_embedding = generate_embeddings("/content/black.jpeg")
print(type(query_embedding))
#
print(query_embedding.shape)
##Response
numpy.ndarray
(1, 768)
results = client.search(
collection_name=my_collection,
query_vector=query_embedding[0],
limit=5,
with_payload=True
)
print(results)
files_list= [ os.path.join("/content/target",f) for f in os.listdir("/content/target")]
print(files_list)
##Response
[ScoredPoint(id=3, version=0, score=0.9999998807907104, payload={'image_id': 3, 'name': 'Aishw'}, vector=None, shard_key=None),
ScoredPoint(id=2, version=0, score=0.9999998807907104, payload={'image_id': 2, 'name': 'deepika'}, vector=None, shard_key=None),
ScoredPoint(id=1, version=0, score=0.9999998807907104, payload={'image_id': 1, 'name': 'nohra'}, vector=None, shard_key=None),
ScoredPoint(id=0, version=0, score=0.9999998807907104, payload={'image_id': 0, 'name': 'kajol'}, vector=None, shard_key=None),
ScoredPoint(id=5, version=0, score=0.9999998211860657, payload={'image_id': 5, 'name': 'kareena'}, vector=None, shard_key=None)]
['/content/target/kajol.jpeg',
'/content/target/nohra.jpeg',
'/content/target/deepika.jpeg',
'/content/target/Aishw.jpeg',
'/content/target/aish.jpeg',
'/content/target/kareena.jpeg']
def see_images(results, top_k=2):
for i in range(top_k):
image_id = results[i].payload['image_id']
name = results[i].payload['name']
score = results[i].score
image = Image.open(files_list[image_id])
print(f"Result #{i+1}: {name} was diagnosed with {score * 100} confidence")
print(f"This image score was {score}")
display(image)
print("-" * 50)
print()
see_images(results, top_k=5)
结果 #1:Aishw 被诊断为 99.99998807907104 置信度。
该图像得分为 0.9999998807907104。
— — — — — — — — — — — — — — — — — — — — — — — — —
结果 #2:deepika 被诊断为 99.99998807907104 置信度。
该图像得分为 0.9999998807907104。
— — — — — — — — — — — — — — — — — — — — — — — — —
结果 #3:nohra 被诊断为 99.99998807907104 置信度。
该图像得分为 0.9999998807907104。
— — — — — — — — — — — — — — — — — — — — — — — — —
结果 #4:kajol 被诊断为 99.99998807907104 置信度。
该图像得分为 0.9999998807907104。
— — — — — — — — — — — — — — — — — — — — — — — — —
结果 #5:kareena 被诊断为 99.99998211860657 置信度。
该图像得分为 0.9999998211860657。
正如你所看到的,我们使用了现有的图像,并取回了其他图像以及原始图像。相似性分数还为我们提供了查询图像与数据库中图像相似性的良好指示。
除了 OpenCV,我们还可以使用 Vision Transformer 来执行相同的任务。请在下面找到示例代码:
pip install -qU qdrant-client transformers datasets
from transformers import ViTImageProcessor, ViTModel
from qdrant_client import QdrantClient
from qdrant_client.http import models
from datasets import load_dataset
import numpy as np
import torch
# Create a local Qdrant vector store
client =QdrantClient(path="qdrant_db")
my_collection = "image_collection"
client.recreate_collection(
collection_name=my_collection,
vectors_config=models.VectorParams(size=384, distance=models.Distance.COSINE)
)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
processor = ViTImageProcessor.from_pretrained('facebook/dino-vits16')
model = ViTModel.from_pretrained('facebook/dino-vits16').to(device)
import pandas as pd
import os
image_file = []
image_name =[]
#
for file in os.listdir("/content/photos"):
if file.endswith(".jpeg"):
image_name.append(file.split(".")[0])
image_file.append(Image.open(os.path.join("/content/photos",file)))
#
df = pd.DataFrame({"Image":image_file,"Name":image_name})
descriptions = df['Name'].tolist()
print(descriptions)
数据帧快照
在计算机视觉系统中,矢量数据库用于存储图像特征。这些图像特征是捕获其视觉内容的图像的矢量表示,它们用于提高计算机视觉任务(如对象检测、图像分类和图像检索)的性能。
为了从图像中提取这些有用的特征表示,我们将使用视觉转换器 (ViT)。ViT是先进的算法,使计算机能够以与人类类似的方式“看到”和理解视觉信息。他们使用 transformer 架构来处理图像并从中提取有意义的特征。
要了解 ViT 的工作原理,请想象您有一个包含许多不同部分的大型拼图游戏。为了解决这个难题,你通常会看看各个部分,它们的形状,以及它们如何组合在一起形成完整的画面。ViT的工作方式类似,这意味着视觉转换器不是一次查看整个图像,而是将其分解成称为“补丁”的更小部分。这些补丁中的每一个都像是一块拼图,捕获图像的特定部分,然后由ViT分析和处理这些碎片。
通过分析这些斑块,ViT可以识别重要的图案,如边缘、颜色和纹理,并将它们组合起来,形成对给定图像的连贯理解。
final_embeddings = []
for item in df['Image'].values.tolist():
inputs = processor(images=item, return_tensors="pt").to(device)
with torch.no_grad():
outputs = model(**inputs).last_hidden_state.mean(dim=1).cpu().numpy()
final_embeddings.append(outputs)
np.save("vectors", np.array(final_embeddings), allow_pickle=False)
payload = []
for i in range(df.shape[0]):
payload.append({"image_id" :i,
"name":df.iloc[i]['Name']})
ids = list(range(df.shape[0]))
embeddings = np.load("vectors.npy").tolist()
for i in range(0, df.shape[0]):
client.upsert(
collection_name=my_collection,
points=models.Batch(
ids=[ids[i]],
vectors=embeddings[i],
payloads=[payload[i]]
)
)
#check if the update is successful
client.count(
collection_name=my_collection,
exact=True,
)
#To visually inspect the collection we just created, we can scroll through our vectors with the client.scroll() method.
client.scroll(
collection_name=my_collection,
limit=10
)
img = Image.open("YOUR IMAGE PATH")
inputs = processor(images=img, return_tensors="pt").to(device)
one_embedding = model(**inputs).last_hidden_state
#
results = client.search(
collection_name=my_collection,
query_vector=one_embedding.mean(dim=1)[0].tolist(),
limit=5,
with_payload=True
)
see_images(results, top_k=2)
结果 #1:Aishw 被诊断为 100.00000144622251 置信度。
图像得分为 1.0000000144622252。
— — — — — — — — — — — — — — — — — — — — — — — — —
结果 #2:deepika 被诊断为 90.48531271076924 置信度。
图像得分为 0.9048531271076924。
— — — — — — — — — — — — — — — — — — — — — — — — —
结果 #3:nohra 被诊断为 88.62201422801974 置信度。
图像得分为 0.8862201422801974。
— — — — — — — — — — — — — — — — — — — — — — — — —
结果 #4:aish 被诊断为 87.71421890846095 置信度。
该图像得分为 0.8771421890846095。
— — — — — — — — — — — — — — — — — — — — — — — — —
结果 #5:kareena 被诊断为 86.80090570447916 置信度。
该图像得分为 0.8680090570447916。
— — — — — — — — — — — — — — — — — — — — — — — — —