图片

寻找与自己穿搭风格相似的明星

在上一篇文章中,我们探索了如何使用人工智能技术,特别是开源AI向量数据库Milvus和Hugging Face模型,来寻找与自己穿搭风格相似的明星。本文将进一步介绍如何对项目代码进行微调,以获得更详细和准确的结果,并在文末提供彩蛋。

项目代码微调

1. 代码获取首先,需要获取项目使用到的图片,可以通过以下链接下载:图片下载链接

2. 环境准备使用Jupyter Notebook来运行项目,可以通过以下链接直接打开:Jupyter Notebook

3. 代码修改对上篇文章中的项目代码进行必要的修改,以提高结果的准确性和详细程度。具体修改方法将在下文中详细说明。

彩蛋文末附赠的彩蛋将为读者带来更多惊喜,敬期待。


本文内容是对上一篇文章的延伸,旨在帮助读者更深入地理解和应用AI技术于时尚领域。
图片

图像处理库导入与使用指南

概述

在进行图像处理任务之前,我们需要导入一系列必要的库和工具。本文将详细介绍如何导入这些库,并简要说明它们的作用。

导入图像处理库

以下是进行图像处理所需导入的主要库列表:

  • torch: 用于深度学习的特征提取。
  • transformers: 包含segformer对象,用于图像分割任务。
  • matplotlib: 用于数据可视化。
  • torchvision: 包含Resizemasks_to_boxescrop等工具,用于图像的预处理和操作。

导入步骤1. 首先,确保你的环境中已经安装了上述库。如果没有,可以使用pip命令进行安装。2. 使用import语句导入所需的库。例如: python import torch from transformers import Segformer import matplotlib.pyplot as plt from torchvision import transforms 3. 根据你的项目需求,选择合适的工具和函数进行图像处理。

注意事项

  • 确保导入的库版本与你的项目兼容,以避免潜在的兼容性问题。
  • 在使用segformer等高级对象时,需要先了解其使用方法和参数配置。

结语通过上述步骤,你可以顺利地导入并使用所需的图像处理库。希望本文能够帮助你在图像处理项目中取得成功。

import torch  
from torch import nn, tensor  
from transformers import AutoFeatureExtractor, SegformerForSemanticSegmentation  
import matplotlib.pyplot as plt  
from torchvision.transforms import Resize  
import torchvision.transforms as T  
from torchvision.ops import masks_to_boxes  
from torchvision.transforms.functional import crop  
  • 预处理明星照片

在导入所有必要的图像处理库和工具后,就可以开始处理图像。以下三个函数 get_segmentation、get_masks 和 crop_images 用于分割并裁剪图片中的时尚单品,以供后续使用。

import torch  
def get_segmentation(extractor, model, image):  
    inputs = extractor(images=image, return_tensors="pt")  
  
    outputs = model(**inputs)  
    logits = outputs.logits.cpu()  
  
    upsampled_logits = nn.functional.interpolate(  
        logits,  
        size=image.size[::-1],  
        mode="bilinear",  
        align_corners=False,  
    )  
  
    pred_seg = upsampled_logits.argmax(dim=1)[0]  
    return pred_seg  
  
# 返回两个 masks(tensor)列表和 obj_ids(int)  
# 来自 Hugging Face 的 mattmdjaga/segformer_b2_clothes 模型  
def get_masks(segmentation):  
    obj_ids = torch.unique(segmentation)  
    obj_ids = obj_ids[1:]  
    masks = segmentation == obj_ids[:, None, None]  
    return masks, obj_ids  
  
def crop_images(masks, obj_ids, img):  
    boxes = masks_to_boxes(masks)  
    crop_boxes = []  
    for box in boxes:  
        crop_box = tensor([box[0], box[1], box[2]-box[0], box[3]-box[1]])  
        crop_boxes.append(crop_box)  
    preprocess = T.Compose([  
        T.Resize(size=(256, 256)),  
        T.ToTensor()  
    ])  
    cropped_images = {}  
    for i in range(len(crop_boxes)):  
        crop_box = crop_boxes[i]  
        cropped = crop(img, crop_box[1].item(), crop_box[0].item(), crop_box[3].item(), crop_box[2].item())  
        cropped_images[obj_ids[i].item()] = preprocess(cropped)  
    return cropped_images  
import os  
image_paths = []  
for celeb in os.listdir("./photos"):  
    for image in os.listdir(f"./photos/{celeb}/"):  
        image_paths.append(f"./photos/{celeb}/{image}")  
  
from milvus import default_server  
from pymilvus import utility, connections  
default_server.start()  
connections.connect(host="127.0.0.1", port=default_server.listen_port)  
DIMENSION = 2048  
BATCH_SIZE = 128  
COLLECTION_NAME = "fashion"  
TOP_K = 3  
from pymilvus import FieldSchema, CollectionSchema, Collection, DataType  
  
fields = [  
    FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),  
    FieldSchema(name='filepath', dtype=DataType.VARCHAR, max_length=200),  
    FieldSchema(name="name", dtype=DataType.VARCHAR, max_length=200),  
    FieldSchema(name="seg_id", dtype=DataType.INT64),  
    FieldSchema(name='embedding', dtype=DataType.FLOAT_VECTOR, dim=DIMENSION)  
]  
  
schema = CollectionSchema(fields=fields)  
collection = Collection(name=COLLECTION_NAME, schema=schema)  
index_params = {  
    "index_type": "IVF_FLAT",  
    "metric_type": "L2",  
    "params": {"nlist": 128},  
}  
collection.create_index(field_name="embedding", index_params=index_params)  
collection.load()  

接着,运行以下代码,使用来自 Hugging Face 的 Nvidia ResNet 50 模型生成 embedding 向量。

# 如遇 SSL 证书 URL 错误,请在导入 resnet50 模型前运行此步骤  
import ssl  
ssl._create_default_https_context = ssl._create_unverified_context  
# 并删除最后一层模型输出  
embeddings_model = torch.hub.load('NVIDIA/DeepLearningExamples:torchhub', 'nvidia_resnet50', pretrained=True)  
embeddings_model = torch.nn.Sequential(*(list(embeddings_model.children())[:-1]))  
embeddings_model.eval()

以下函数定义了如何将图像转换为向量并插入到 Milvus 向量数据库中。代码会循环遍历所有图像。(注意:如果需要开启 Milvus 全新特性动态 Schema,需要修改代码。)

def embed_insert(data, collection, model):  
    with torch.no_grad():  
        output = model(torch.stack(data[0])).squeeze()  
        collection.insert([data[1], data[2], data[3], output.tolist()])  
from PIL import Image  
data_batch = [[], [], [], []]  
  
for path in image_paths:  
    image = Image.open(path)  
    path_split = path.split("/")  
    name = " ".join(path_split[2].split("_"))  
    segmentation = get_segmentation(extractor, model, image)  
    masks, ids = get_masks(segmentation)  
    cropped_images = crop_images(masks, ids, image)for key, image in cropped_images.items():  
        data_batch[0].append(image)  
        data_batch[1].append(path)  
        data_batch[2].append(name)  
        data_batch[3].append(key)  
        if len(data_batch[0]) % BATCH_SIZE == 0:  
            embed_insert(data_batch, collection, embeddings_model)  
            data_batch = [[], [], [], []]  
  
if len(data_batch[0]) != 0:  
    embed_insert(data_batch, collection, embeddings_model)  
  
collection.flush()  
  • 查询向量数据库

以下代码演示了如何使用输入图像查询 Milvus 向量数据库,以检索和上传衣服图像最相似的的前三个结果。

def embed_search_images(data, model):  
    with torch.no_grad():  
    output = model(torch.stack(data))  
    if len(output) > 1:  
        return output.squeeze().tolist()  
    else:  
        return torch.flatten(output, start_dim=1).tolist()  
# data_batch[0]是 tensor 列表  
# data_batch[1]是图像文件的文件路径(字符串)  
# data_batch[2]是图像中人物的名称列表(字符串)  
# data_batch[3]是分割键值列表(int)  
data_batch = [[], [], [], []]  
  
search_paths = ["./photos/Taylor_Swift/Taylor_Swift_3.jpg", "./photos/Taylor_Swift/Taylor_Swift_8.jpg"]  
  
for path in search_paths:  
    image = Image.open(path)  
    path_split = path.split("/")  
    name = " ".join(path_split[2].split("_"))  
    segmentation = get_segmentation(extractor, model, image)  
    masks, ids = get_masks(segmentation)  
    cropped_images = crop_images(masks, ids, image)  
    for key, image in cropped_images.items():  
        data_batch[0].append(image)  
        data_batch[1].append(path)  
        data_batch[2].append(name)  
        data_batch[3].append(key)  
  
embeds = embed_search_images(data_batch[0], embeddings_model)  
import time  
start = time.time()  
res = collection.search(embeds,  
    anns_field='embedding',  
    param={"metric_type": "L2",  
        "params": {"nprobe": 10}},  
    limit=TOP_K,  
    output_fields=['filepath'])  
finish = time.time()  
print(finish - start)  
for index, result in enumerate(res):  
    print(index)  
    print(result)  

扩展图像识别项目的应用场景

在原有图像识别项目的基础上,我们可以通过修改代码来实现更广泛的应用。本节将介绍如何通过调整代码,实现识别图像中的时尚单品,而不仅仅是明星的着装风格。

1. 调整代码以识别时尚单品

首先,我们需要对现有代码进行一些调整,以便它能够识别图像中的时尚元素。这可能包括衣服、配饰、鞋子等。通过分析图像并识别这些元素,我们可以为用户提供更个性化的时尚建议。

2. 获取不包含边界框的图像

进一步地,我们可以修改代码来获取不包含边界框的图像。这意味着图像中的时尚单品将被直接展示,而不是通过边界框来标示。这样的展示方式可以让用户更直观地看到单品的细节。

3. 应用场景拓展

  • 个性化推荐:根据用户喜好和图像识别结果,为用户提供个性化的时尚单品推荐。
  • 时尚趋势分析:通过收集大量图像数据,分析当前流行的时尚趋势。
  • 虚拟试衣间:结合3D技术,让用户在虚拟环境中试穿识别出的时尚单品。

4. 技术实现要点

  • 图像处理:使用图像处理技术来增强对时尚单品的识别能力。
  • 机器学习:利用机器学习算法来提高识别的准确性和效率。
  • 用户界面:设计直观易用的用户界面,提升用户体验。 通过这些步骤,我们的项目不仅能够识别明星的着装风格,还能够扩展到更广泛的时尚领域,为用户提供更加丰富的服务。
    图片

接下来,将为大家介绍如何修改上述代码寻找更多匹配的穿衣风格。

  • 导入所需的图像处理库和工具

同样,需要先导入所有必要的图像处理库。如果已经完成导入,请跳过此步骤。

import torch  
from torch import nn, tensor  
from transformers import AutoFeatureExtractor, SegformerForSemanticSegmentation  
import matplotlib.pyplot as plt  
from torchvision.transforms import Resize  
import torchvision.transforms as T  
from torchvision.ops import masks_to_boxes  
from torchvision.transforms.functional import crop  

在图像预处理的流程中,我们主要关注三个关键步骤:分割、掩膜提取和图像裁剪。以下是针对这些步骤的详细说明和代码调整建议:

  1. 分割图像获取 (get_segmentation 函数)
  • 无需对 get_segmentation 函数进行修改,保持其原有功能,用于获取图像的分割信息。
  1. 掩膜提取 (get_masks 函数)
  • 调整 get_masks 函数,使其仅提取与 wanted 列表中指定的分割 ID 相对应的掩膜图像。
  1. 图像裁剪 (crop_images 函数)
  • crop_images 函数进行重要调整,以适应新的流程需求。原函数仅返回裁剪后的图像列表,现在需要返回三个对象:
  • Embedding 向量:裁剪图像对应的特征向量,这将优化后续的数据处理流程。
  • 边界框坐标:原始图像上边界框的坐标列表,用于定位裁剪图像的原始位置。
  • 分割 ID 列表:与裁剪图像相对应的分割 ID 列表,以便于后续处理和分析。 通过这些调整,我们能够更有效地处理图像数据,为后续的分析和应用打下坚实的基础。
wanted = [1, 3, 4, 5, 6, 7, 8, 9, 10, 16, 17]  
def get_segmentation(image):  
    inputs = extractor(images=image, return_tensors="pt")  
  
    outputs = segmentation_model(**inputs)  
    logits = outputs.logits.cpu()  
  
    upsampled_logits = nn.functional.interpolate(  
        logits,  
        size=image.size[::-1],  
        mode="bilinear",  
        align_corners=False,  
    )  
  
    pred_seg = upsampled_logits.argmax(dim=1)[0]  
    return pred_seg  
  
# returns two lists masks (tensor) and obj_ids (int)  
# "mattmdjaga/segformer_b2_clothes" from hugging face  
def get_masks(segmentation):  
    obj_ids = torch.unique(segmentation)  
    obj_ids = obj_ids[1:]  
    wanted_ids = [x.item() for x in obj_ids if x in wanted]  
    wanted_ids = torch.Tensor(wanted_ids)  
    masks = segmentation == wanted_ids[:, None, None]  
    return masks, obj_ids  
  
def crop_images(masks, obj_ids, img):  
    boxes = masks_to_boxes(masks)  
    crop_boxes = []  
    for box in boxes:  
        crop_box = tensor([box[0], box[1], box[2]-box[0], box[3]-box[1]])  
        crop_boxes.append(crop_box)  
    preprocess = T.Compose([  
        T.Resize(size=(256, 256)),  
        T.ToTensor()  
    ])  
    cropped_images = []  
    seg_ids = []  
    for i in range(len(crop_boxes)):  
        crop_box = crop_boxes[i]  
        cropped = crop(img, crop_box[1].item(), crop_box[0].item(), crop_box[3].item(), crop_box[2].item())  
        cropped_images.append(preprocess(cropped))  
        seg_ids.append(obj_ids[i].item())  
    with torch.no_grad():  
        embeddings = embeddings_model(torch.stack(cropped_images)).squeeze().tolist()  
    return embeddings, boxes.tolist(), seg_ids  

有了图像数据之后,就可以加载数据了。这一步骤需要使用到批量插入功能,上篇文章的教程中也有涉及,但不同点在于,本文的教程中将数据作为 dictionary 列表一次性插入。这种插入方式更简洁,同时还允许我们在插入数据时动态新增 Schema 字段。

for path in image_paths:  
    image = Image.open(path)  
    path_split = path.split("/")  
    name = " ".join(path_split[2].split("_"))  
    segmentation = get_segmentation(image)  
    masks, ids = get_masks(segmentation)  
    embeddings, crop_corners, seg_ids = crop_images(masks, ids, image)  
    inserts = [{"embedding": embeddings[x], "seg_id": seg_ids[x], "name": name, "filepath": path, "crop_corner": crop_corners[x]} for x in range(len(embeddings))]  
    collection.insert(inserts)  
    collection.flush()

向量数据库Milvus查询教程

本文将介绍如何在向量数据库Milvus中进行数据查询,并对查询结果进行可视化展示。本教程与上一篇教程相比,有以下主要区别:

1. 查询限制

  • 将图像中匹配的时尚单品数量限制为5件。

2. 查询返回结果

  • 指定查询返回最相似的3张图像。

3. 图像色彩图获取

  • 添加了获取图片色彩图的函数。

可视化展示在matplotlib中设置figures和axes,通过循环遍历所有图像,应用以下3个函数:

  • 应用分割结果函数
  • 应用边界框函数
  • 应用色彩图函数

步骤说明

  1. 设置环境:在matplotlib中创建必要的图形和坐标轴。
  2. 循环遍历图像:对每张图像应用上述函数,以获取分割结果和边界框。
  3. 查询数据:根据每张图像中匹配的时尚单品数量,获取最相似的3张图像。
  4. 结果展示:最终返回的结果图像将展示带有边界框的匹配单品。

注意事项

  • 确保查询结果的准确性,边界框应清晰标示出匹配的单品。 通过以上步骤,用户可以有效地在Milvus中查询数据,并对查询结果进行可视化展示。
from pprint import pprint  
from PIL import ImageDraw  
from collections import Counter  
import matplotlib.patches as patches  
  
LIMIT = 5 # 每张图像中匹配的时尚单品件数  
CLOSEST = 3 # 返回的最相似图像数量。CLOSEST <= Limit  
  
search_paths = ["./photos/Taylor_Swift/Taylor_Swift_2.jpg", "./photos/Jenna_Ortega/Jenna_Ortega_6.jpg"] # Images to search fordef get_cmap(n, name='hsv'):  
    '''Returns a function that maps each index in 0, 1, ..., n-1 to a distinct  
    RGB color; the keyword argument name must be a standard mpl colormap name.  
    Sourced from <https://stackoverflow.com/questions/14720331/how-to-generate-random-colors-in-matplotlib>'''return plt.cm.get_cmap(name, n)  
  
# 创建结果 subplot  
f, axarr = plt.subplots(max(len(search_paths), 2), CLOSEST + 1)  
  
for search_i, path in enumerate(search_paths):  
    # Generate crops and embeddings for all items found  
    image = Image.open(path)  
    segmentation = get_segmentation(image)  
    masks, ids = get_masks(segmentation)  
    embeddings, crop_corners, _ = crop_images(masks, ids, image)  
  
# 生成色彩图  
    cmap = get_cmap(len(crop_corners))  
  
    # Display the first box with image being searched for  
    axarr[search_i][0].imshow(image)  
    axarr[search_i][0].set_title('Search Image')  
    axarr[search_i][0].axis('off')  
    for i, (x0, y0, x1, y1) in enumerate(crop_corners):  
        rect = patches.Rectangle((x0, y0), x1-x0, y1-y0, linewidth=1, edgecolor=cmap(i), facecolor='none')  
        axarr[search_i][0].add_patch(rect)  
  
    # 查询向量数据库  
    start = time.time()  
    res = collection.search(embeddings,  
        anns_field='embedding',  
        param={"metric_type": "L2",  
        "params": {"nprobe": 10}, "offset": 0},  
        limit=LIMIT,  
        output_fields=['filepath', 'crop_corner'])  
    finish = time.time()  
  
    print("Total Search Time: ", finish - start)  
  
    # 根据位置给查询结果增加不同的权重  
    filepaths = []  
    for hits in res:  
        seen = set()  
        for i, hit in enumerate(hits):  
            if hit.entity.get("filepath") not in seen:  
                seen.add(hit.entity.get("filepath"))  
                filepaths.extend([hit.entity.get("filepath") for _ in range(len(hits) - i)])  
    # 查找排名最高的图像  
    counts = Counter(filepaths)  
    most_common = [path for path, _ in counts.most_common(CLOSEST)]  
    # 提取每张图像中与查询图像相关的时尚单品  
    matches = {}  
    for i, hits in enumerate(res):  
        matches[i] = {}  
        tracker = set(most_common)  
        for hit in hits:  
            if hit.entity.get("filepath") in tracker:  
                matches[i][hit.entity.get("filepath")] = hit.entity.get("crop_corner")  
                tracker.remove( hit.entity.get("filepath"))  
        # 返回最相似图像:  
    # 返回与查询图像临近的图像  
        image = Image.open(res_path)  
        axarr[search_i][res_i+1].imshow(image)  
        axarr[search_i][res_i+1].set_title(" ".join(res_path.split("/")[2].split("_")))  
        axarr[search_i][res_i+1].axis('off')  
# 为匹配单品添加边界框  
        if res_path in value:  
            x0, y0, x1, y1 = value[res_path]  
            rect = patches.Rectangle((x0, y0), x1-x0, y1-y0, linewidth=1, edgecolor=cmap(key), facecolor='none')  
            axarr[search_i][res_i+1].add_patch(rect)

运行上述步骤后,结果如下所示:

图片

项目后续:探索更多应用场景

1. 扩展对比功能

  • 将不同单品进行归类对比,丰富数据库中的图像资源,以提供更多样化的查询结果。

2. 时尚探测与推荐系统

  • 利用明星图像转换为可购买衣服的图像,实现用户上传照片后,系统推荐风格相似的衣物。 ### 3. 穿搭生成系统
  • 构建一个系统,根据用户上传的多张照片推荐穿搭,使用生成式图像模型提供穿搭建议,实现难度较高。

总结

1. 教程回顾

  • 本文教程扩展了时尚 AI 项目的应用场景,利用 Milvus 的动态 Schema 功能筛选分割 ID 并保留边界框,在查询中根据时尚单品件数返回最相似的图像。

2. 动态 Schema 功能

  • Milvus 的动态 Schema 功能允许在上传数据时添加新字段,简化了批量上传数据的过程,并在预处理中剔除非着装类元素。

3. 进一步应用搭建

  • 通过代码调整,可以构建时尚推荐系统、用户着装搭配系统,以及生成式时尚 AI 应用。

专题活动预告

  • 「寻找 AIGC 时代的 CVP 实践之星」 专题活动即将启动,Zilliz 将联合国内大模型厂商,提供向量数据库与大模型技术支持,共同提升应用落地效果。

参与方式

  • 如果你的应用适合 CVP 框架并寻求专业帮助,可通过邮箱 business@zilliz.com 申请参与活动。

本文作者

  • 作者信息待补充。
    图片

 唐玉剑
Zilliz 开发者布道师

推荐阅读

[
图片

LLM 落地电商行业的最佳实践来了?Zilliz X AWS 有话说

活动背景大模型技术正加速改革和重塑各行各业,电商行业因其高度数字化成为大模型应用的绝佳领域。向量数据库和云计算是大模型落地的基石。

活动介绍Zilliz 联合亚马逊云科技举办活动,探讨大模型在电商行业的应用场景、方案解析和最佳实践。

活动议程

  • 活动日期:2023年9月7日 13:30-17:00
  • 活动地点:上海市黄浦区河南中路88号外滩中心威斯汀大饭店

议题概览

  1. 电商场景构建 GenAI 应用实践分享
  • 李雪晴
  • 探讨基于亚马逊云科技产品构建 GenAI 应用的方法。
  1. 向量数据库在电商及大模型领域应用方案介绍
  • 沈亮
  • 介绍向量数据库的基本概念、功能和电商领域应用。
  1. 得物基于向量数据库 Milvus 的大模型应用实践
  • 孟令公
  • 分享得物构建大模型训练推理平台的经验。
  1. 基于智能搜索和大语言模型打造下一代企业知识库
  • 熊俊峰
  • 介绍如何使用智能搜索和大语言模型构建企业知识库。
  1. Cupshe 如何基于向量检索和 AI 技术构建电商智能搜索方案
  • 吴万涛
  • 讨论如何结合关键词搜索和向量语义搜索优化电商搜索结果。
  1. CVP 讲堂—— 0-1 搭建电商行业知识库应用
  • 陈将
  • 介绍如何使用向量数据库和大语言模型搭建智能问答机器人。

专题活动Zilliz 将联合大模型厂商甄选应用场景,提供技术专家支持,共同提升应用落地效果。

联系方式感兴趣的应用开发者可以联系:business@zilliz.com 参与活动。

推荐阅读

当一个程序员决定穿上粉色裤子

作为一个大众眼中的“非典型程序员”,作者喜欢拥抱时尚和潮流,经常在演讲时穿粉色裤子,这已成为他的标志性打扮。某天,作者突发奇想,想借助Milvus找到一个与自己穿搭风格最为相似的明星。

项目背景

最近,作者遇到了一个名为Fashion AI的项目,该项目利用微调模型对服装图片进行分割,然后裁剪出标注的时尚单品,并将图片转化为embedding向量存储在Milvus数据库中。通过上传自己穿着打扮的照片,可以查询到与自己时尚风格最相似的明星。

实现路径

1. 图像分割作者在Hugging Face上找到了segformer模型,该模型可以对不同的服装图片进行准确分割,并识别出18种对象类型。通过编写get_segmentation函数,可以生成18层的图像分割掩膜。

2. 裁剪和调整图像大小使用get_masks函数为图像中每个监测到的对象生成新图像,并调整图像大小。

3. 向量数据库存储将裁剪后的图像添加至Milvus向量数据库中,使用PyMilvus连接至Milvus Lite版本,并创建Collection。

4. 获取embedding向量使用Nvidia提供的ResNet50模型,删除最后一层输出,以获取embedding向量。

5. 寻找相似明星上传图片转化为向量后,在Milvus数据库中查询相似数据,返回最相似的3个明星。

结语作者鼓励大家尝试这个项目,并分享自己的结果。

图片
’ fill=’%23FFFFFF’%3E%3Crect x=‘249’ y=‘126’ width=‘1’ height=‘1’%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)