From 884a10213be72ec90ffc38d3de978c3d192e2823 Mon Sep 17 00:00:00 2001 From: zhouchengrong Date: Thu, 28 Mar 2024 10:12:21 +0800 Subject: [PATCH] =?UTF-8?q?attribute=20=E5=AD=97=E6=AE=B5=E5=90=8D?= =?UTF-8?q?=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- app/api/api_similar_match.py | 25 ++++ app/schemas/similar_match.py | 6 + .../attribute_recognition/const_debug.py | 139 ++++++++++++++++++ .../outfit_matcher/test_param/test.json | 19 +++ app/service/similar_match/__init__.py | 0 app/service/similar_match/service.py | 110 ++++++++++++++ 7 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 app/api/api_similar_match.py create mode 100644 app/schemas/similar_match.py create mode 100644 app/service/attribute_recognition/const_debug.py create mode 100644 app/service/outfit_matcher/test_param/test.json create mode 100644 app/service/similar_match/__init__.py create mode 100644 app/service/similar_match/service.py diff --git a/.gitignore b/.gitignore index 1965b2b..261f9d2 100644 --- a/.gitignore +++ b/.gitignore @@ -130,4 +130,5 @@ uwsgi .conf app/logs *.log -*.jpg \ No newline at end of file +*.jpg +*.zip \ No newline at end of file diff --git a/app/api/api_similar_match.py b/app/api/api_similar_match.py new file mode 100644 index 0000000..1a49e7b --- /dev/null +++ b/app/api/api_similar_match.py @@ -0,0 +1,25 @@ +import logging +import time + +from fastapi import APIRouter + +from app.schemas.similar_match import SimilarMatchMItem +from app.service.similar_match.service import SimilarMatch +from app.service.utils.decorator import RunTime + +logger = logging.getLogger() +router = APIRouter() + + +@RunTime +@router.post("similar_match") +def similar_match(request_item: SimilarMatchMItem): + try: + if request_item.result_number <= 0: + raise KeyError("result number can't be less than 0") + service = SimilarMatch(request_item) + search_response = service.match_features() + return {"message": "ok", "data": search_response} + except KeyError as e: + logger.warning(str(e)) + return {"message": "result number can't be less than 0", "data": []} diff --git a/app/schemas/similar_match.py b/app/schemas/similar_match.py new file mode 100644 index 0000000..e5fb063 --- /dev/null +++ b/app/schemas/similar_match.py @@ -0,0 +1,6 @@ +from pydantic import BaseModel + + +class SimilarMatchMItem(BaseModel): + image_path: str + result_number: int diff --git a/app/service/attribute_recognition/const_debug.py b/app/service/attribute_recognition/const_debug.py new file mode 100644 index 0000000..3b20939 --- /dev/null +++ b/app/service/attribute_recognition/const_debug.py @@ -0,0 +1,139 @@ +import torch + +device = torch.device('cuda') +top_discription_list = [r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\1_top_length.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\2_top_type.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\3_top_Sleeve_length.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\4_top_Sleeve_shape.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\5_top_Sleeve_shoulder.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\6_top_Neckline.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\7_outer_Print.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\8_outer_Material.csv', + # r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\9_top_Material.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\9_top_Softness.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\10_top_Design.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\11_top_OPType.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\12_top_Silhouette.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\top\7_top_Collar.csv'] + +top_model_list = ['top_length', + 'top_type', + 'top_Sleeve_length', + 'top_Sleeve_shape', + 'top_Sleeve_shoulder', + 'top_Neckline', + 'top_print', + 'top_material', + 'top_Softness', + 'top_Design', + 'top_optype', + 'top_Silhouette', + 'top_Collar' + ] + +bottom_discription_list = [ + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\bottom\2_bottom_subtype.csv', + # r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\bottom\3_bottom_structure.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\bottom\3_bottom_length.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\bottom\7_outer_Print.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\bottom\8_outer_Material.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\bottom\5_bottom_Softness.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\bottom\8_bottom_Silhouette.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\bottom\7_bottom_OPType.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\bottom\6_bottom_Design.csv'] + +bottom_model_list = [ + 'bottom_sub-Type', + 'bottom_length', + 'bottom_print', + 'bottom_material', + 'bottom_Softness_B', + 'bottom_Silhouette_B', + 'bottom_OPType_B', + 'bottom_design'] + +outwear_discription_list = [r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\outwear\1_outer_length.csv', + # r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\outwear\2_outer_type.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\outwear\3_outer_sleeve_length.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\outwear\4_outer_sleeve_shape.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\outwear\5_outer_sleeve_shoulder.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\outwear\6_outer_Collar.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\outwear\7_outer_Print.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\outwear\8_outer_Material.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\outwear\9_outer_Softness.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\outwear\10_outer_Design.csv', + # r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\outwear\11_outer_opening.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\outwear\12_outer_OPType.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\outwear\13_outer_Silhouette.csv', ] + +outwear_model_list = ['outwear_outer_length', + # 'outwear_2_outer_type', + 'outwear_outer_sleeve_length', + 'outwear_outer_sleeve_shape', + 'outwear_outer_sleeve_shoulder', + 'outwear_outer_collar', + 'outwear_print', + 'outwear_material', + 'outwear_outer_softness', + 'outwear_outer_design', + # 'outwear_11_outer_opening', + 'outwear_outer_optype', + 'outwear_outer_silhouette'] + +jumpsuit_discription_list = [r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\jumpsuit\1_jumsuit_length.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\jumpsuit\2_jumpsuit_Sleeve_length.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\jumpsuit\3_jumpsuit_Sleeve_shape.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\jumpsuit\4_jumpsuit_Sleeve_shoulder.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\jumpsuit\5_jumpsuit_Neckline.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\jumpsuit\6_jumpsuit_Collar.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\jumpsuit\7_jumpsuit_Print.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\jumpsuit\8_jumpsuit_Material.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\jumpsuit\9_jumpsuit_Softness.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\jumpsuit\10_jumsuit_design.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\jumpsuit\11_jumpsuit_OPType.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\jumpsuit\12_jumpsuit_subtype.csv'] + +jumpsuit_model_list = ['jumpsuit_length', + 'jumpsuit_sleeve_length', + 'jumpsuit_sleeve_shape', + 'jumpsuit_sleeve_shoulder', + 'jumpsuit_neckline', + 'jumpsuit_collar', + 'jumpsuit_print', + 'jumpsuit_material', + 'jumpsuit_softness', + 'jumpsuit_design', + 'jumpsuit_optype', + 'jumpsuit_subtype'] + +dress_discription_list = [r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\dress\1_dress_length.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\dress\3_top_Sleeve_length.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\dress\4_top_Sleeve_shape.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\dress\5_top_Sleeve_shoulder.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\dress\ori5_dress_Neckline.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\dress\7_outer_Print.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\dress\7_top_Collar.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\dress\8_outer_Material.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\dress\9_dress_Design.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\dress\9_top_Softness.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\dress\11_dress_Silhouette.csv', + # r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\dress\11_top_OPType.csv', + r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\dress\12_dress_type.csv'] + +dress_model_list = ['dress_length', + 'dress_sleeve_length', + 'dress_sleeve_shape', + 'dress_sleeve_shoulder', + 'dress_neckline', + 'dress_print', + 'dress_collar', + 'dress_material', + 'dress_design', + 'dress_softness', + 'dress_silohouette12', + # 'dress_' + 'dress_type' + ] + +category_discription = r'E:\workspace\trinity_client_mixi\app\service\attribute_recognition\discriptor\category\category_dis.csv' +category_model = 'category' diff --git a/app/service/outfit_matcher/test_param/test.json b/app/service/outfit_matcher/test_param/test.json new file mode 100644 index 0000000..a62fd97 --- /dev/null +++ b/app/service/outfit_matcher/test_param/test.json @@ -0,0 +1,19 @@ +{ + "topk": 1, + "max_outfits": 5, + "is_best": true, + "query": [ + { + "image_path": "mi-tu/26/BOTTOM/PANTS/MKTS27000_0BLK.jpg/3f4676db-98a1-44d4-947f-9d1f59828629.jpg", + "item_name": "MKTS27000", + "semantic_category": "BOTTOM/PANTS" + } + ], + "database": [ + { + "image_path": "mi-tu/26/TOP/BLOUSE/MKTS27002_0WHT.jpg/131cc29e-8f70-4134-a0e8-82f826b00058.jpg", + "item_name": "MKTS27002", + "semantic_category": "TOP/BLOUSE" + } + ] +} \ No newline at end of file diff --git a/app/service/similar_match/__init__.py b/app/service/similar_match/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/service/similar_match/service.py b/app/service/similar_match/service.py new file mode 100644 index 0000000..87d9440 --- /dev/null +++ b/app/service/similar_match/service.py @@ -0,0 +1,110 @@ +import io +import json + +import numpy as np +import tritonclient.http as httpclient +from PIL import Image +from minio import Minio +from pymilvus import MilvusClient + +from app.core.config import * +from torchvision import transforms + +from app.schemas.similar_match import SimilarMatchMItem +from app.service.utils.decorator import RunTime + + +class SimilarMatch: + def __init__(self, request_data): + self.minio_client = Minio( + f"{MINIO_IP}:{MINIO_PORT}", + access_key=MINIO_ACCESS, + secret_key=MINIO_SECRET, + secure=MINIO_SECURE) + self.triton_client = httpclient.InferenceServerClient(url=f"{OM_TRITON_IP}:{OM_TRITON_PORT}") + self.image_path = request_data.image_path + self.result_number = request_data.result_number + self.features = self.get_features() + + @staticmethod + def resize_image(img): + """ + Args: + img: ndarray (height, width, channel) + """ + image_transforms = transforms.Compose([ + transforms.Resize(112), + transforms.CenterCrop(112), + transforms.ToTensor(), + transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]), + ]) + resized_img = image_transforms(img).numpy() + return resized_img + + def load_image(self, img_path): + # 从 MinIO 中获取对象(图像文件) + image_data = self.minio_client.get_object(img_path.split("/", 1)[0], img_path.split("/", 1)[1]) + # 读取图像数据并转换为 PIL 图像对象 + pil_image = Image.open(io.BytesIO(image_data.data)).convert("RGB") + # 将 PIL 图像转换为 NumPy 数组 + # image_array = np.array(pil_image) + return pil_image + + def preprocess(self, img_path): + image = self.load_image(img_path) + image = self.resize_image(image) + image = np.stack([[image]], axis=0) + + category = np.stack([[1, 6]], axis=0) + + mask = np.zeros((1, 1), dtype=np.float32) + return image, category, mask + + def get_features(self): + image, category, mask = self.preprocess(self.image_path) + # 输入集 + inputs = [ + httpclient.InferInput("input__0", image.shape, datatype="FP32"), + httpclient.InferInput("input__1", category.shape, datatype="INT16"), + httpclient.InferInput("input__2", mask.shape, datatype="FP32"), + ] + inputs[0].set_data_from_numpy(image.astype(np.float32), binary_data=True) + inputs[1].set_data_from_numpy(category.astype(np.int16), binary_data=True) + inputs[2].set_data_from_numpy(mask.astype(np.float32), binary_data=True) + # 输出集 + outputs = [ + httpclient.InferRequestedOutput("output__0", binary_data=True), + httpclient.InferRequestedOutput("output__1", binary_data=True) + ] + results = self.triton_client.infer(model_name="outfit_matcher_type_aware", inputs=inputs, outputs=outputs) + # 推理 + # 取结果 + features = results.as_numpy("output__1") # Shape (N, 64) + return features + + @RunTime + def match_features(self): + # 连接milvus + # 连接milvus + client = MilvusClient(uri="http://10.1.1.240:19530", db_name="mixi") + try: + search_response = client.search( + collection_name="mixi_outfit", # Replace with the actual name of your collection + # Replace with your query vector + data=[self.features[0]], + limit=self.result_number, # Max. number of search results to return + output_fields=["id", "image_path"], # Search parameters + ) + return search_response + finally: + client.close() + + +if __name__ == '__main__': + request_data = SimilarMatchMItem(image_path="test/top/test_top1.jpg", result_number=1) + + service = SimilarMatch(request_data) + search_response = service.match_features() + + print(json.dumps(search_response, indent=4))