From 7eb9b18f8f8cbb00505da5be453d28622bcf058c Mon Sep 17 00:00:00 2001 From: zhouchengrong Date: Tue, 26 Nov 2024 16:08:10 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=20=201.design=20=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6=E6=A8=A1=E5=BC=8F=E6=B5=8B=E8=AF=95=202.?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E4=BB=A5stream=E5=8F=91=E9=80=81=E5=88=B0jav?= =?UTF-8?q?a=203.=E6=96=B0=E5=A2=9E=E9=85=8D=E9=A5=B0=E7=B1=BB=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/api_design.py | 182 +++++++++++++++++- app/service/design_fast/design_generate.py | 147 +++++++++++++- app/service/design_fast/item.py | 23 ++- app/service/design_fast/pipeline/loading.py | 2 + app/service/design_fast/pipeline/scale.py | 4 +- app/service/design_fast/pipeline/split.py | 2 +- app/service/design_fast/utils/organize.py | 39 ++++ .../design_fast/utils/synthesis_item.py | 15 ++ app/service/utils/new_oss_client.py | 2 +- 9 files changed, 405 insertions(+), 11 deletions(-) diff --git a/app/api/api_design.py b/app/api/api_design.py index b0231a2..665d544 100644 --- a/app/api/api_design.py +++ b/app/api/api_design.py @@ -2,13 +2,13 @@ import json import logging import os -from fastapi import APIRouter, HTTPException, UploadFile, File, Form +from fastapi import APIRouter, HTTPException, UploadFile, File, Form, BackgroundTasks from app.schemas.design import DesignModel, DesignProgressModel, ModelProgressModel, DBGConfigModel from app.schemas.response_template import ResponseModel from app.service.design.model_process_service import model_transpose from app.service.design_batch.service import start_design_batch_generate -from app.service.design_fast.design_generate import design_generate +from app.service.design_fast.design_generate import design_generate, design_generate_v2 from app.service.design_fast.utils.redis_utils import Redis router = APIRouter() @@ -16,7 +16,7 @@ logger = logging.getLogger() @router.post("/design") -def design(request_data: DesignModel): +def design(request_data: DesignModel, background_tasks: BackgroundTasks): """ 创建一个具有以下参数的请求体: 示例参数: @@ -196,6 +196,182 @@ def design(request_data: DesignModel): return ResponseModel(data=data) +@router.post("/design_v2") +async def design_v2(request_data: DesignModel, background_tasks: BackgroundTasks): + """ + 创建一个具有以下参数的请求体: + 示例参数: + { + "objects": [ + { + "basic": { + "body_point_test": { + "waistband_right": [ + 200, + 241 + ], + "hand_point_right": [ + 223, + 297 + ], + "waistband_left": [ + 112, + 241 + ], + "hand_point_left": [ + 92, + 305 + ], + "shoulder_left": [ + 99, + 116 + ], + "shoulder_right": [ + 215, + 116 + ] + }, + "layer_order": true, + "scale_bag": 0.7, + "scale_earrings": 0.16, + "self_template": true, + "single_overall": "overall", + "switch_category": "" + }, + "items": [ + { + "businessId": 270372, + "color": "30 28 28", + "image_id": 69780, + "offset": [ + 0, + 0 + ], + "path": "aida-sys-image/images/female/trousers/0825000630.jpg", + "print": { + "element": { + "element_angle_list": [], + "element_path_list": [], + "element_scale_list": [], + "location": [] + }, + "overall": { + "location": [], + "print_angle_list": [], + "print_path_list": [], + "print_scale_list": [] + }, + "single": { + "location": [], + "print_angle_list": [], + "print_path_list": [], + "print_scale_list": [] + } + }, + "priority": 10, + "resize_scale": [ + 1.0, + 1.0 + ], + "type": "Trousers" + }, + { + "businessId": 270373, + "color": "30 28 28", + "image_id": 98243, + "offset": [ + 0, + 0 + ], + "path": "aida-sys-image/images/female/blouse/0902003811.jpg", + "print": { + "element": { + "element_angle_list": [], + "element_path_list": [], + "element_scale_list": [], + "location": [] + }, + "overall": { + "location": [], + "print_angle_list": [], + "print_path_list": [], + "print_scale_list": [] + }, + "single": { + "location": [], + "print_angle_list": [], + "print_path_list": [], + "print_scale_list": [] + } + }, + "priority": 11, + "resize_scale": [ + 1.0, + 1.0 + ], + "type": "Blouse" + }, + { + "businessId": 270374, + "color": "172 68 68", + "image_id": 98244, + "offset": [ + 0, + 0 + ], + "path": "aida-sys-image/images/female/outwear/0825000410.jpg", + "print": { + "element": { + "element_angle_list": [], + "element_path_list": [], + "element_scale_list": [], + "location": [] + }, + "overall": { + "location": [], + "print_angle_list": [], + "print_path_list": [], + "print_scale_list": [] + }, + "single": { + "location": [], + "print_angle_list": [], + "print_path_list": [], + "print_scale_list": [] + } + }, + "priority": 12, + "resize_scale": [ + 1.0, + 1.0 + ], + "transparent":{ + "mask_url":"test/transparent_test/transparent_mask.png", + "scale":0.1 + }, + "type": "Outwear" + }, + { + "body_path": "aida-sys-image/models/female/5bdfe7ca-64eb-44e4-b03d-8e517520c795.png", + "image_id": 96090, + "type": "Body" + } + ] + } + ], + "process_id": "83" + } + """ + try: + # 异步 + logger.info(f"generate_image request item is : @@@@@@:{json.dumps(request_data.dict())}") + background_tasks.add_task(design_generate_v2, request_data) + except Exception as e: + logger.warning(f"design Run Exception @@@@@@:{e}") + raise HTTPException(status_code=404, detail=str(e)) + return ResponseModel() + + @router.post('/get_progress') def get_progress(request_data: DesignProgressModel): """ diff --git a/app/service/design_fast/design_generate.py b/app/service/design_fast/design_generate.py index 582de4c..80edd96 100644 --- a/app/service/design_fast/design_generate.py +++ b/app/service/design_fast/design_generate.py @@ -5,8 +5,8 @@ import time from minio import Minio from app.core.config import * -from app.service.design_fast.item import BodyItem, TopItem, BottomItem -from app.service.design_fast.utils.organize import organize_body, organize_clothing +from app.service.design_fast.item import BodyItem, TopItem, BottomItem, AccessoriesItem +from app.service.design_fast.utils.organize import organize_body, organize_clothing, organize_accessories from app.service.design_fast.utils.progress import final_progress, update_progress from app.service.design_fast.utils.synthesis_item import synthesis, synthesis_single, update_base_size_priority from app.service.utils.decorator import RunTime @@ -26,9 +26,14 @@ def process_item(item, basic): elif item['type'].lower() in ['blouse', 'outwear', 'dress', 'tops']: top_server = TopItem(data=item, basic=basic, minio_client=minio_client) item_data = top_server.process() - else: + elif item['type'].lower() in ['skirt', 'trousers', 'bottoms']: bottom_server = BottomItem(data=item, basic=basic, minio_client=minio_client) item_data = bottom_server.process() + elif item['type'].lower() in ['accessories']: + bottom_server = AccessoriesItem(data=item, basic=basic, minio_client=minio_client) + item_data = bottom_server.process() + else: + raise NotImplementedError(f"Item type {item['type']} not implemented") return item_data @@ -38,6 +43,10 @@ def process_layer(item, layers): body_layer = organize_body(item) layers.append(body_layer) return item['body_image'].size + elif item['name'] == 'accessories': + front_layer, back_layer = organize_accessories(item) + layers.append(front_layer) + layers.append(back_layer) else: front_layer, back_layer = organize_clothing(item) layers.append(front_layer) @@ -57,7 +66,7 @@ def design_generate(request_data): def process_object(step, object): nonlocal active_threads basic = object['basic'] - items_response = {'layers': []} + items_response = {'layers': [], 'objectSign': object['objectSign'] if 'objectSign' in object.keys() else ""} if basic['single_overall'] == "overall": item_results = [] for item in object['items']: @@ -126,6 +135,136 @@ def design_generate(request_data): return object_response +@RunTime +def design_generate_v2(request_data): + objects_data = request_data.dict()['objects'] + # process_id = request_data.dict()['process_id'] + # object_response = {} + threads = [] + active_threads = 0 + lock = threading.Lock() + + # total = len(objects_data) + + def process_object(step, object): + nonlocal active_threads + basic = object['basic'] + items_response = {'layers': [], 'objectSign': object['objectSign'] if 'objectSign' in object.keys() else ""} + if basic['single_overall'] == "overall": + item_results = [] + for item in object['items']: + item_results.append(process_item(item, basic)) + layers = [] + body_size = None + for item in item_results: + body_size = process_layer(item, layers) + layers = sorted(layers, key=lambda s: s.get("priority", float('inf'))) + + layers, new_size = update_base_size_priority(layers, body_size) + + for lay in layers: + items_response['layers'].append({ + 'image_category': "body" if lay['name'] == 'mannequin' else lay['name'], + 'position': lay['position'], + 'priority': lay.get("priority", None), + 'resize_scale': lay['resize_scale'] if "resize_scale" in lay.keys() else None, + 'image_size': lay['image'] if lay['image'] is None else lay['image'].size, + 'gradient_string': lay['gradient_string'] if 'gradient_string' in lay.keys() else "", + 'mask_url': lay['mask_url'], + 'image_url': lay['image_url'] if 'image_url' in lay.keys() else None, + 'pattern_image_url': lay['pattern_image_url'] if 'pattern_image_url' in lay.keys() else None, + # 'back_perspective_url': lay['back_perspective_url'] if 'back_perspective_url' in lay.keys() else None, + }) + items_response['synthesis_url'] = synthesis(layers, new_size, basic) + else: + item_result = process_item(object['items'][0], basic) + items_response['layers'].append({ + 'image_category': f"{item_result['name']}_front", + 'image_size': item_result['back_image'].size if item_result['back_image'] else None, + 'position': None, + 'priority': 0, + 'image_url': item_result['front_image_url'], + 'mask_url': item_result['mask_url'], + "gradient_string": item_result['gradient_string'] if 'gradient_string' in item_result.keys() else "", + 'pattern_image_url': item_result['pattern_image_url'] if 'pattern_image_url' in item_result.keys() else None, + }) + items_response['layers'].append({ + 'image_category': f"{item_result['name']}_back", + 'image_size': item_result['front_image'].size if item_result['front_image'] else None, + 'position': None, + 'priority': 0, + 'image_url': item_result['back_image_url'], + 'mask_url': item_result['mask_url'], + "gradient_string": item_result['gradient_string'] if 'gradient_string' in item_result.keys() else "", + 'pattern_image_url': item_result['pattern_image_url'] if 'pattern_image_url' in item_result.keys() else None, + }) + items_response['synthesis_url'] = synthesis_single(item_result['front_image'], item_result['back_image']) + + # 发送结果给java端 + url = "https://3998-117-143-125-51.ngrok-free.app/api/third/party/receiveDesignResults" + headers = { + 'Accept': "*/*", + 'Accept-Encoding': "gzip, deflate, br", + 'User-Agent': "PostmanRuntime-ApipostRuntime/1.1.0", + 'Connection': "keep-alive", + 'Content-Type': "application/json" + } + response = post_request(url, json_data=items_response, headers=headers) + if response: + # 打印结果 + logger.info(response.text) + logger.info(items_response) + + # update_progress(process_id, total) + + # with lock: + # object_response[step] = items_response + # active_threads -= 1 + + for step, object in enumerate(objects_data): + t = threading.Thread(target=process_object, args=(step, object)) + threads.append(t) + t.start() + # with lock: + # active_threads += 1 + + # for t in threads: + # t.join() + # final_progress(process_id) + # return object_response + + +import requests + + +def post_request(url, data=None, json_data=None, headers=None, auth=None, timeout=5): + """ + 发送POST请求的封装函数 + + :param url: 接口的URL地址 + :param data: 要发送的数据(字典形式,用于表单数据等,会自动编码) + :param json_data: 要发送的JSON数据(字典形式,会自动转换为JSON字符串) + :param headers: 请求头字典 + :param auth: 认证信息(如 ('username', 'password') 形式用于基本认证) + :param timeout: 超时时间,单位为秒 + :return: 返回接口的响应对象 + """ + try: + response = requests.post( + url, + data=data, + json=json_data, + headers=headers, + auth=auth, + timeout=timeout + ) + response.raise_for_status() # 如果请求失败,抛出异常 + return response + except requests.RequestException as e: + print(f"POST请求出错: {e}") + return None + + if __name__ == '__main__': object_data = { "objects": [ diff --git a/app/service/design_fast/item.py b/app/service/design_fast/item.py index f7af700..ec18b17 100644 --- a/app/service/design_fast/item.py +++ b/app/service/design_fast/item.py @@ -1,4 +1,4 @@ -from app.service.design_fast.pipeline import LoadImage, KeyPoint, Segmentation, Color, PrintPainting, Scaling, Split, LoadBodyImage, ContourDetection, BackPerspective +from app.service.design_fast.pipeline import LoadImage, KeyPoint, Segmentation, Color, PrintPainting, Scaling, Split, LoadBodyImage, ContourDetection class BaseItem: @@ -9,6 +9,27 @@ class BaseItem: self.result.update(basic) +class AccessoriesItem(BaseItem): + def __init__(self, data, basic, minio_client): + super().__init__(data, basic) + self.Accessories_pipeline = [ + LoadImage(minio_client), + # KeyPoint(), + ContourDetection(), + # Segmentation(minio_client), + # BackPerspective(minio_client), + Color(minio_client), + PrintPainting(minio_client), + Scaling(), + Split(minio_client) + ] + + def process(self): + for item in self.Accessories_pipeline: + self.result = item(self.result) + return self.result + + class TopItem(BaseItem): def __init__(self, data, basic, minio_client): super().__init__(data, basic) diff --git a/app/service/design_fast/pipeline/loading.py b/app/service/design_fast/pipeline/loading.py index 0ce0dfa..5a55d9d 100644 --- a/app/service/design_fast/pipeline/loading.py +++ b/app/service/design_fast/pipeline/loading.py @@ -74,6 +74,8 @@ class LoadImage: keypoint = 'head_point' elif name == 'earring': keypoint = 'ear_point' + elif name == 'accessories': + keypoint = "accessories" else: raise KeyError(f"{name} does not belong to item category list: blouse, outwear, dress, trousers, skirt, " f"bag, shoes, hairstyle, earring.") diff --git a/app/service/design_fast/pipeline/scale.py b/app/service/design_fast/pipeline/scale.py index 732fcd8..c901aa7 100644 --- a/app/service/design_fast/pipeline/scale.py +++ b/app/service/design_fast/pipeline/scale.py @@ -18,7 +18,7 @@ class Scaling: - int(result['body_point_test'][result['keypoint'] + '_right'][0])) ** 2 + 1 ) - + if distance_clo == 0: result['scale'] = 1 else: @@ -46,4 +46,6 @@ class Scaling: result['scale'] = result['scale_bag'] elif result['keypoint'] == 'ear_point': result['scale'] = result['scale_earrings'] + else: + result['scale'] = 1 return result diff --git a/app/service/design_fast/pipeline/split.py b/app/service/design_fast/pipeline/split.py index 2f67027..344c5c5 100644 --- a/app/service/design_fast/pipeline/split.py +++ b/app/service/design_fast/pipeline/split.py @@ -21,7 +21,7 @@ class Split(object): def __call__(self, result): try: - if result['name'] in ('outwear', 'dress', 'blouse', 'skirt', 'trousers', 'tops', 'bottoms'): + if result['name'] in ('outwear', 'dress', 'blouse', 'skirt', 'trousers', 'tops', 'bottoms','accessories'): front_mask = result['front_mask'] back_mask = result['back_mask'] rgba_image = rgb_to_rgba(result['final_image'], front_mask + back_mask) diff --git a/app/service/design_fast/utils/organize.py b/app/service/design_fast/utils/organize.py index 92be044..33edc4f 100644 --- a/app/service/design_fast/utils/organize.py +++ b/app/service/design_fast/utils/organize.py @@ -55,6 +55,45 @@ def organize_clothing(layer): return front_layer, back_layer +def organize_accessories(layer): + # 起始坐标 + start_point = (0, 0) + # 前片数据 + front_layer = dict(priority=layer['priority'] if layer.get("layer_order", False) else PRIORITY_DICT.get(f'{layer["name"].lower()}_front', None), + name=f'{layer["name"].lower()}_front', + image=layer["front_image"], + # mask_image=layer['front_mask_image'], + image_url=layer['front_image_url'], + mask_url=layer['mask_url'], + sacle=layer['scale'], + clothes_keypoint=(0, 0), + position=start_point, + resize_scale=layer["resize_scale"], + mask=cv2.resize(layer['mask'], layer["front_image"].size), + gradient_string=layer['gradient_string'] if 'gradient_string' in layer.keys() else "", + pattern_image_url=layer['pattern_image_url'], + pattern_image=layer['pattern_image'], + # back_perspective_url=layer['back_perspective_url'] if 'back_perspective_url' in layer.keys() else "" + ) + # 后片数据 + back_layer = dict(priority=-layer.get("priority", 0) if layer.get("layer_order", False) else PRIORITY_DICT.get(f'{layer["name"].lower()}_back', None), + name=f'{layer["name"].lower()}_back', + image=layer["back_image"], + # mask_image=layer['back_mask_image'], + image_url=layer['back_image_url'], + mask_url=layer['mask_url'], + sacle=layer['scale'], + clothes_keypoint=(0, 0), + position=start_point, + resize_scale=layer["resize_scale"], + mask=cv2.resize(layer['mask'], layer["front_image"].size), + gradient_string=layer['gradient_string'] if 'gradient_string' in layer.keys() else "", + pattern_image_url=layer['pattern_image_url'], + # back_perspective_url=layer['back_perspective_url'] if 'back_perspective_url' in layer.keys() else "" + ) + return front_layer, back_layer + + def calculate_start_point(keypoint_type, scale, clothes_point, body_point, offset, resize_scale): """ Align left diff --git a/app/service/design_fast/utils/synthesis_item.py b/app/service/design_fast/utils/synthesis_item.py index f5d505f..d7711f3 100644 --- a/app/service/design_fast/utils/synthesis_item.py +++ b/app/service/design_fast/utils/synthesis_item.py @@ -79,9 +79,11 @@ def synthesis(data, size, basic_info): _, binary_body_mask = cv2.threshold(body_mask, 127, 255, cv2.THRESH_BINARY) top_outer_mask = np.array(binary_body_mask) bottom_outer_mask = np.array(binary_body_mask) + accessories_outer_mask = np.array(binary_body_mask) top = True bottom = True + accessories = True i = len(data) while i: i -= 1 @@ -109,10 +111,23 @@ def synthesis(data, size, basic_info): background = np.zeros_like(top_outer_mask) background[all_y_start:all_y_end, all_x_start:all_x_end] = sketch_mask[mask_y_start:mask_y_end, mask_x_start:mask_x_end] bottom_outer_mask = background + bottom_outer_mask + elif accessories and data[i]['name'] in ['accessories_front']: + mask_shape = data[i]['mask'].shape + y_offset, x_offset = data[i]['adaptive_position'] + # 初始化叠加区域的起始和结束位置 + all_y_start, all_y_end, mask_y_start, mask_y_end = positioning(all_mask_shape=all_mask_shape[0], mask_shape=mask_shape[0], offset=y_offset) + all_x_start, all_x_end, mask_x_start, mask_x_end = positioning(all_mask_shape=all_mask_shape[1], mask_shape=mask_shape[1], offset=x_offset) + # 将叠加区域赋值为相应的像素值 + _, sketch_mask = cv2.threshold(data[i]['mask'], 127, 255, cv2.THRESH_BINARY) + background = np.zeros_like(top_outer_mask) + background[all_y_start:all_y_end, all_x_start:all_x_end] = sketch_mask[mask_y_start:mask_y_end, mask_x_start:mask_x_end] + accessories_outer_mask = background + accessories_outer_mask + pass elif bottom is False and top is False: break all_mask = cv2.bitwise_or(top_outer_mask, bottom_outer_mask) + all_mask = cv2.bitwise_or(all_mask, accessories_outer_mask) for layer in data: if layer['image'] is not None: diff --git a/app/service/utils/new_oss_client.py b/app/service/utils/new_oss_client.py index f402a14..a338adb 100644 --- a/app/service/utils/new_oss_client.py +++ b/app/service/utils/new_oss_client.py @@ -82,7 +82,7 @@ if __name__ == '__main__': # url = "aida-users/89/sketchboard/female/Dress/e6724ab7-8d3f-4677-abe0-c3e42ab7af85.jpeg" # url = "aida-users/87/print/956614a2-7e75-4fbe-9ed0-c1831e37a2c9-4-87.png" # url = "aida-users/89/single_logo/123-89.png" - url ="aida-results/result_27915298-a656-11ef-b4f3-0242ac150002.png" + url ="aida-results/result_461110a5-aba2-11ef-83e7-0826ae3ad6b3.png" # url = "aida-collection-element/12148/Sketchboard/95ea577b-305b-4a62-b30a-39c0dd3ddb3f.png" read_type = "2"