diff --git a/app/api/api_design.py b/app/api/api_design.py index 68f2a44..2720e36 100644 --- a/app/api/api_design.py +++ b/app/api/api_design.py @@ -8,8 +8,8 @@ from app.schemas.design import DesignModel, DesignProgressModel, ModelProgressMo from app.schemas.response_template import ResponseModel from app.service.design.model_process_service import model_transpose from app.service.design.service_design_batch_generate import start_design_batch_generate -from app.service.design.utils.redis_utils import Redis -from app.service.design_test.batch_design import design_generate +from app.service.design_fast.design_generate import design_generate +from app.service.design_fast.utils.redis_utils import Redis router = APIRouter() logger = logging.getLogger() diff --git a/app/service/design_test/__init__.py b/app/service/design_fast/__init__.py similarity index 100% rename from app/service/design_test/__init__.py rename to app/service/design_fast/__init__.py diff --git a/app/service/design_test/batch_design.py b/app/service/design_fast/design_generate.py similarity index 81% rename from app/service/design_test/batch_design.py rename to app/service/design_fast/design_generate.py index 1d0fe99..ac1f79c 100644 --- a/app/service/design_test/batch_design.py +++ b/app/service/design_fast/design_generate.py @@ -1,35 +1,25 @@ -import io -import json import logging import threading import time -import uuid -import cv2 -import numpy as np -from PIL import Image from minio import Minio -from app.core.config import PRIORITY_DICT -from app.service.design.utils.redis_utils import Redis -from app.service.design_test.item import BodyItem, TopItem, BottomItem +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.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 -from app.service.utils.new_oss_client import oss_upload_image id_lock = threading.Lock() logger = logging.getLogger() -# minio 配置 -MINIO_URL = "www.minio.aida.com.hk:12024" -MINIO_ACCESS = 'vXKFLSJkYeEq2DrSZvkB' -MINIO_SECRET = 'uKTZT3x7C43WvPN9QTc99DiRkwddWZrG9Uh3JVlR' -MINIO_SECURE = True - minio_client = Minio(MINIO_URL, access_key=MINIO_ACCESS, secret_key=MINIO_SECRET, secure=MINIO_SECURE) def process_item(item, basic): + # 处理project中单个item if item['type'] == "Body": body_server = BodyItem(data=item, basic=basic, minio_client=minio_client) item_data = body_server.process() @@ -43,6 +33,7 @@ def process_item(item, basic): def process_layer(item, layers): + # item处理结束后 对图层数据组装 if item['name'] == "mannequin": body_layer = organize_body(item) layers.append(body_layer) @@ -53,252 +44,6 @@ def process_layer(item, layers): layers.append(back_layer) -def organize_body(layer): - body_layer = dict(priority=0, - name=layer["name"].lower(), - image=layer['body_image'], - image_url=layer['body_path'], - mask_image=None, - mask_url=None, - sacle=1, - # mask=layer['body_mask'], - position=(0, 0)) - return body_layer - - -def organize_clothing(layer): - # 起始坐标 - start_point = calculate_start_point(layer['keypoint'], layer['scale'], layer['clothes_keypoint'], layer['body_point_test'], layer["offset"], layer["resize_scale"]) - # 前片数据 - 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=layer['clothes_keypoint'], - 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_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=layer['clothes_keypoint'], - 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'], - ) - return front_layer, back_layer - - -def calculate_start_point(keypoint_type, scale, clothes_point, body_point, offset, resize_scale): - """ - Align left - Args: - keypoint_type: string, "waistband" | "shoulder" | "ear_point" - scale: float - clothes_point: dict{'left': [x1, y1, z1], 'right': [x2, y2, z2]} - body_point: dict, containing keypoint data of body figure - - Returns: - start_point: tuple (x', y') - x' = y_body - y1 * scale + offset - y' = x_body - x1 * scale + offset - - """ - side_indicator = f'{keypoint_type}_left' - start_point = ( - int(body_point[side_indicator][1] + offset[1] - int(clothes_point[side_indicator][0]) * scale), # y - int(body_point[side_indicator][0] + offset[0] - int(clothes_point[side_indicator][1]) * scale) # x - ) - return start_point - - -def update_base_size_priority(layers, size): - # 计算透明背景图片的宽度 - min_x = min(info['position'][1] for info in layers) - x_list = [] - for info in layers: - if info['image'] is not None: - x_list.append(info['position'][1] + info['image'].width) - max_x = max(x_list) - new_width = max_x - min_x - new_height = 700 - # 更新坐标 - for info in layers: - info['adaptive_position'] = (info['position'][0], info['position'][1] - min_x) - return layers, (new_width, new_height) - - -def synthesis_single(front_image, back_image): - result_image = None - if front_image: - result_image = front_image - if back_image: - result_image.paste(back_image, (0, 0), back_image) - image_data = io.BytesIO() - result_image.save(image_data, format='PNG') - image_data.seek(0) - image_bytes = image_data.read() - bucket_name = 'aida-results' - object_name = f'result_{generate_uuid()}.png' - oss_upload_image(oss_client=minio_client, bucket=bucket_name, object_name=object_name, image_bytes=image_bytes) - return f"{bucket_name}/{object_name}" - - -def oss_upload_json(json_data, object_name): - try: - with open(f"app/service/design/design_batch/response_json/{object_name}", 'w') as file: - json.dump(json_data, file, indent=4) - - oss_client = Minio(MINIO_URL, access_key=MINIO_ACCESS, secret_key=MINIO_SECRET, secure=MINIO_SECURE) - oss_client.fput_object("test", object_name, f"app/service/design/design_batch/response_json/{object_name}") - except Exception as e: - logger.warning(str(e)) - - -def generate_uuid(): - with id_lock: - unique_id = str(uuid.uuid1()) - return unique_id - - -def positioning(all_mask_shape, mask_shape, offset): - all_start = 0 - all_end = 0 - mask_start = 0 - mask_end = 0 - if offset == 0: - all_start = 0 - all_end = min(all_mask_shape, mask_shape) - - mask_start = 0 - mask_end = min(all_mask_shape, mask_shape) - elif offset > 0: - all_start = min(offset, all_mask_shape) - all_end = min(offset + mask_shape, all_mask_shape) - - mask_start = 0 - mask_end = 0 if offset > all_mask_shape else min(all_mask_shape - offset, mask_shape) - elif offset < 0: - if abs(offset) > mask_shape: - all_start = 0 - all_end = 0 - else: - all_start = 0 - if mask_shape - abs(offset) > all_mask_shape: - all_end = min(mask_shape - abs(offset), all_mask_shape) - else: - all_end = mask_shape - abs(offset) - - if abs(offset) > mask_shape: - mask_start = mask_shape - mask_end = mask_shape - else: - mask_start = abs(offset) - if mask_shape - abs(offset) >= all_mask_shape: - mask_end = all_mask_shape + abs(offset) - else: - mask_end = mask_shape - return all_start, all_end, mask_start, mask_end - - -def synthesis(data, size, basic_info): - # 创建底图 - base_image = Image.new('RGBA', size, (0, 0, 0, 0)) - try: - all_mask_shape = (size[1], size[0]) - body_mask = None - for d in data: - if d['name'] == 'body' or d['name'] == 'mannequin': - # 创建一个新的宽高透明图像, 把模特贴上去获取mask - transparent_image = Image.new("RGBA", size, (0, 0, 0, 0)) - transparent_image.paste(d['image'], (d['adaptive_position'][1], d['adaptive_position'][0]), d['image']) # 此处可变数组会被paste篡改值,所以使用下标获取position - body_mask = np.array(transparent_image.split()[3]) - - # 根据新的坐标获取新的肩点 - left_shoulder = [x + y for x, y in zip(basic_info['body_point_test']['shoulder_left'], [d['adaptive_position'][1], d['adaptive_position'][0]])] - right_shoulder = [x + y for x, y in zip(basic_info['body_point_test']['shoulder_right'], [d['adaptive_position'][1], d['adaptive_position'][0]])] - body_mask[:min(left_shoulder[1], right_shoulder[1]), left_shoulder[0]:right_shoulder[0]] = 255 - _, 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) - - top = True - bottom = True - i = len(data) - while i: - i -= 1 - if top and data[i]['name'] in ["blouse_front", "outwear_front", "dress_front", "tops_front"]: - top = False - 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] - top_outer_mask = background + top_outer_mask - elif bottom and data[i]['name'] in ["trousers_front", "skirt_front", "bottoms_front", "dress_front"]: - bottom = False - 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] - bottom_outer_mask = background + bottom_outer_mask - elif bottom is False and top is False: - break - - all_mask = cv2.bitwise_or(top_outer_mask, bottom_outer_mask) - - for layer in data: - if layer['image'] is not None: - if layer['name'] != "body": - test_image = Image.new('RGBA', size, (0, 0, 0, 0)) - test_image.paste(layer['image'], (layer['adaptive_position'][1], layer['adaptive_position'][0]), layer['image']) - mask_data = np.where(all_mask > 0, 255, 0).astype(np.uint8) - mask_alpha = Image.fromarray(mask_data) - cropped_image = Image.composite(test_image, Image.new("RGBA", test_image.size, (255, 255, 255, 0)), mask_alpha) - base_image.paste(test_image, (0, 0), cropped_image) # test_image 已经按照坐标贴到最大宽值的图片上 坐着这里坐标为00 - else: - base_image.paste(layer['image'], (layer['adaptive_position'][1], layer['adaptive_position'][0]), layer['image']) - - result_image = base_image - - image_data = io.BytesIO() - result_image.save(image_data, format='PNG') - image_data.seek(0) - - # oss upload - image_bytes = image_data.read() - bucket_name = "aida-results" - object_name = f'result_{generate_uuid()}.png' - oss_upload_image(oss_client=minio_client, bucket=bucket_name, object_name=object_name, image_bytes=image_bytes) - return f"{bucket_name}/{object_name}" - except Exception as e: - logging.warning(f"synthesis runtime exception : {e}") - - @RunTime def design_generate(request_data): objects_data = request_data.dict()['objects'] @@ -380,31 +125,6 @@ def design_generate(request_data): return object_response -def update_progress(process_id, total): - logger.info(f"{process_id} , {total}") - r = Redis() - progress = r.read(key=process_id) - if progress and total != 1: - if int(progress) <= 100: - r.write(key=process_id, value=int(progress) + int(100 / total)) - else: - r.write(key=process_id, value=99) - return progress - elif total == 1: - r.write(key=process_id, value=100) - return progress - else: - r.write(key=process_id, value=int(100 / total)) - return progress - - -def final_progress(process_id): - r = Redis() - progress = r.read(key=process_id) - r.write(key=process_id, value=100) - return progress - - if __name__ == '__main__': object_data = { "objects": [ diff --git a/app/service/design_fast/item.py b/app/service/design_fast/item.py new file mode 100644 index 0000000..e10320d --- /dev/null +++ b/app/service/design_fast/item.py @@ -0,0 +1,61 @@ +from app.service.design_fast.pipeline import LoadImage, KeyPoint, Segmentation, Color, PrintPainting, Scaling, Split, LoadBodyImage, ContourDetection + + +class BaseItem: + def __init__(self, data, basic): + self.result = data.copy() + self.result['name'] = data['type'].lower() + self.result.pop("type") + self.result.update(basic) + + +class TopItem(BaseItem): + def __init__(self, data, basic, minio_client): + super().__init__(data, basic) + self.top_pipeline = [ + LoadImage(minio_client), + KeyPoint(), + Segmentation(minio_client), + Color(minio_client), + PrintPainting(minio_client), + Scaling(), + Split(minio_client) + ] + + def process(self): + for item in self.top_pipeline: + self.result = item(self.result) + return self.result + + +class BottomItem(BaseItem): + def __init__(self, data, basic, minio_client): + super().__init__(data, basic) + self.bottom_pipeline = [ + LoadImage(minio_client), + KeyPoint(), + ContourDetection(), + # Segmentation(), + Color(minio_client), + PrintPainting(minio_client), + Scaling(), + Split(minio_client) + ] + + def process(self): + for item in self.bottom_pipeline: + self.result = item(self.result) + return self.result + + +class BodyItem(BaseItem): + def __init__(self, data, basic, minio_client): + super().__init__(data, basic) + self.top_pipeline = [ + LoadBodyImage(minio_client), + ] + + def process(self): + for item in self.top_pipeline: + self.result = item(self.result) + return self.result diff --git a/app/service/design_test/pipeline/__init__.py b/app/service/design_fast/pipeline/__init__.py similarity index 100% rename from app/service/design_test/pipeline/__init__.py rename to app/service/design_fast/pipeline/__init__.py diff --git a/app/service/design_test/pipeline/color.py b/app/service/design_fast/pipeline/color.py similarity index 100% rename from app/service/design_test/pipeline/color.py rename to app/service/design_fast/pipeline/color.py diff --git a/app/service/design_test/pipeline/contour_detection.py b/app/service/design_fast/pipeline/contour_detection.py similarity index 100% rename from app/service/design_test/pipeline/contour_detection.py rename to app/service/design_fast/pipeline/contour_detection.py diff --git a/app/service/design_test/pipeline/keypoint.py b/app/service/design_fast/pipeline/keypoint.py similarity index 100% rename from app/service/design_test/pipeline/keypoint.py rename to app/service/design_fast/pipeline/keypoint.py diff --git a/app/service/design_test/pipeline/loading.py b/app/service/design_fast/pipeline/loading.py similarity index 100% rename from app/service/design_test/pipeline/loading.py rename to app/service/design_fast/pipeline/loading.py diff --git a/app/service/design_test/pipeline/print_painting.py b/app/service/design_fast/pipeline/print_painting.py similarity index 100% rename from app/service/design_test/pipeline/print_painting.py rename to app/service/design_fast/pipeline/print_painting.py diff --git a/app/service/design_test/pipeline/scale.py b/app/service/design_fast/pipeline/scale.py similarity index 100% rename from app/service/design_test/pipeline/scale.py rename to app/service/design_fast/pipeline/scale.py diff --git a/app/service/design_test/pipeline/segmentation.py b/app/service/design_fast/pipeline/segmentation.py similarity index 100% rename from app/service/design_test/pipeline/segmentation.py rename to app/service/design_fast/pipeline/segmentation.py diff --git a/app/service/design_test/pipeline/split.py b/app/service/design_fast/pipeline/split.py similarity index 98% rename from app/service/design_test/pipeline/split.py rename to app/service/design_fast/pipeline/split.py index 50e167d..35605b8 100644 --- a/app/service/design_test/pipeline/split.py +++ b/app/service/design_fast/pipeline/split.py @@ -8,7 +8,7 @@ from cv2 import cvtColor, COLOR_BGR2RGBA from app.core.config import AIDA_CLOTHING from app.service.design.utils.conversion_image import rgb_to_rgba -from app.service.design_test.utils.upload_image import upload_png_mask +from app.service.design_fast.utils.upload_image import upload_png_mask from app.service.utils.generate_uuid import generate_uuid from app.service.utils.new_oss_client import oss_upload_image diff --git a/app/service/design_test/utils/__init__.py b/app/service/design_fast/utils/__init__.py similarity index 100% rename from app/service/design_test/utils/__init__.py rename to app/service/design_fast/utils/__init__.py diff --git a/app/service/design_test/utils/conversion_image.py b/app/service/design_fast/utils/conversion_image.py similarity index 100% rename from app/service/design_test/utils/conversion_image.py rename to app/service/design_fast/utils/conversion_image.py diff --git a/app/service/design_test/utils/design_ensemble.py b/app/service/design_fast/utils/design_ensemble.py similarity index 100% rename from app/service/design_test/utils/design_ensemble.py rename to app/service/design_fast/utils/design_ensemble.py diff --git a/app/service/design_fast/utils/organize.py b/app/service/design_fast/utils/organize.py new file mode 100644 index 0000000..8190de0 --- /dev/null +++ b/app/service/design_fast/utils/organize.py @@ -0,0 +1,77 @@ +import cv2 + +from app.core.config import PRIORITY_DICT + + +def organize_body(layer): + body_layer = dict(priority=0, + name=layer["name"].lower(), + image=layer['body_image'], + image_url=layer['body_path'], + mask_image=None, + mask_url=None, + sacle=1, + # mask=layer['body_mask'], + position=(0, 0)) + return body_layer + + +def organize_clothing(layer): + # 起始坐标 + start_point = calculate_start_point(layer['keypoint'], layer['scale'], layer['clothes_keypoint'], layer['body_point_test'], layer["offset"], layer["resize_scale"]) + # 前片数据 + 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=layer['clothes_keypoint'], + 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_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=layer['clothes_keypoint'], + 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'], + ) + return front_layer, back_layer + + +def calculate_start_point(keypoint_type, scale, clothes_point, body_point, offset, resize_scale): + """ + Align left + Args: + keypoint_type: string, "waistband" | "shoulder" | "ear_point" + scale: float + clothes_point: dict{'left': [x1, y1, z1], 'right': [x2, y2, z2]} + body_point: dict, containing keypoint data of body figure + + Returns: + start_point: tuple (x', y') + x' = y_body - y1 * scale + offset + y' = x_body - x1 * scale + offset + + """ + side_indicator = f'{keypoint_type}_left' + start_point = ( + int(body_point[side_indicator][1] + offset[1] - int(clothes_point[side_indicator][0]) * scale), # y + int(body_point[side_indicator][0] + offset[0] - int(clothes_point[side_indicator][1]) * scale) # x + ) + return start_point diff --git a/app/service/design_fast/utils/progress.py b/app/service/design_fast/utils/progress.py new file mode 100644 index 0000000..c6a5d74 --- /dev/null +++ b/app/service/design_fast/utils/progress.py @@ -0,0 +1,30 @@ +import logging + +from app.service.design_fast.utils.redis_utils import Redis + +logger = logging.getLogger(__name__) + + +def update_progress(process_id, total): + logger.info(f"{process_id} , {total}") + r = Redis() + progress = r.read(key=process_id) + if progress and total != 1: + if int(progress) <= 100: + r.write(key=process_id, value=int(progress) + int(100 / total)) + else: + r.write(key=process_id, value=99) + return progress + elif total == 1: + r.write(key=process_id, value=100) + return progress + else: + r.write(key=process_id, value=int(100 / total)) + return progress + + +def final_progress(process_id): + r = Redis() + progress = r.read(key=process_id) + r.write(key=process_id, value=100) + return progress diff --git a/app/service/design_test/utils/redis_utils.py b/app/service/design_fast/utils/redis_utils.py similarity index 100% rename from app/service/design_test/utils/redis_utils.py rename to app/service/design_fast/utils/redis_utils.py diff --git a/app/service/design_test/utils/synthesis_item.py b/app/service/design_fast/utils/synthesis_item.py similarity index 94% rename from app/service/design_test/utils/synthesis_item.py rename to app/service/design_fast/utils/synthesis_item.py index 9527cd2..272ab23 100644 --- a/app/service/design_test/utils/synthesis_item.py +++ b/app/service/design_fast/utils/synthesis_item.py @@ -179,3 +179,19 @@ def synthesis_single(front_image, back_image): object_name = f'result_{generate_uuid()}.png' req = oss_upload_image(bucket=bucket_name, object_name=object_name, image_bytes=image_bytes) return f"{bucket_name}/{object_name}" + + +def update_base_size_priority(layers, size): + # 计算透明背景图片的宽度 + min_x = min(info['position'][1] for info in layers) + x_list = [] + for info in layers: + if info['image'] is not None: + x_list.append(info['position'][1] + info['image'].width) + max_x = max(x_list) + new_width = max_x - min_x + new_height = 700 + # 更新坐标 + for info in layers: + info['adaptive_position'] = (info['position'][0], info['position'][1] - min_x) + return layers, (new_width, new_height) diff --git a/app/service/design_test/utils/upload_image.py b/app/service/design_fast/utils/upload_image.py similarity index 100% rename from app/service/design_test/utils/upload_image.py rename to app/service/design_fast/utils/upload_image.py diff --git a/app/service/design_test/item.py b/app/service/design_test/item.py deleted file mode 100644 index 5a4667c..0000000 --- a/app/service/design_test/item.py +++ /dev/null @@ -1,281 +0,0 @@ -import time -from concurrent.futures import ThreadPoolExecutor -from pprint import pprint - -import cv2 - -from app.core.config import PRIORITY_DICT -from app.service.design.utils.synthesis_item import synthesis, synthesis_single -from app.service.design_test.pipeline import LoadImage, KeyPoint, Segmentation, Color, PrintPainting, Scaling, Split, LoadBodyImage, ContourDetection - - -class BaseItem: - def __init__(self, data, basic): - self.result = data.copy() - self.result['name'] = data['type'].lower() - self.result.pop("type") - self.result.update(basic) - - -class TopItem(BaseItem): - def __init__(self, data, basic, minio_client): - super().__init__(data, basic) - self.top_pipeline = [ - LoadImage(minio_client), - KeyPoint(), - Segmentation(minio_client), - Color(minio_client), - PrintPainting(minio_client), - Scaling(), - Split(minio_client) - ] - - def process(self): - for item in self.top_pipeline: - self.result = item(self.result) - return self.result - - -class BottomItem(BaseItem): - def __init__(self, data, basic, minio_client): - super().__init__(data, basic) - self.bottom_pipeline = [ - LoadImage(minio_client), - KeyPoint(), - ContourDetection(), - # Segmentation(), - Color(minio_client), - PrintPainting(minio_client), - Scaling(), - Split(minio_client) - ] - - def process(self): - for item in self.bottom_pipeline: - self.result = item(self.result) - return self.result - - -class BodyItem(BaseItem): - def __init__(self, data, basic, minio_client): - super().__init__(data, basic) - self.top_pipeline = [ - LoadBodyImage(minio_client), - ] - - def process(self): - for item in self.top_pipeline: - self.result = item(self.result) - return self.result - - -def process_item(item, basic, minio_client): - if item['type'] == "Body": - body_server = BodyItem(data=item, basic=basic, minio_client=minio_client) - item_data = body_server.process() - 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: - bottom_server = BottomItem(data=item, basic=basic, minio_client=minio_client) - item_data = bottom_server.process() - return item_data - - -def calculate_start_point(keypoint_type, scale, clothes_point, body_point, offset, resize_scale): - """ - Align left - Args: - keypoint_type: string, "waistband" | "shoulder" | "ear_point" - scale: float - clothes_point: dict{'left': [x1, y1, z1], 'right': [x2, y2, z2]} - body_point: dict, containing keypoint data of body figure - - Returns: - start_point: tuple (x', y') - x' = y_body - y1 * scale + offset - y' = x_body - x1 * scale + offset - - """ - side_indicator = f'{keypoint_type}_left' - start_point = ( - int(body_point[side_indicator][1] + offset[1] - int(clothes_point[side_indicator][0]) * scale), # y - int(body_point[side_indicator][0] + offset[0] - int(clothes_point[side_indicator][1]) * scale) # x - ) - return start_point - - -# 服装图层给数据组装 -def organize_clothing(layer): - # 起始坐标 - start_point = calculate_start_point(layer['keypoint'], layer['scale'], layer['clothes_keypoint'], layer['body_point_test'], layer["offset"], layer["resize_scale"]) - # 前片数据 - 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=layer['clothes_keypoint'], - 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_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=layer['clothes_keypoint'], - 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'], - ) - return front_layer, back_layer - - -# 模特图层给数据组装 -def organize_body(layer): - body_layer = dict(priority=0, - name=layer["name"].lower(), - image=layer['body_image'], - image_url=layer['body_path'], - mask_image=None, - mask_url=None, - sacle=1, - # mask=layer['body_mask'], - position=(0, 0)) - return body_layer - - -def process_layer(item, layers): - if item['name'] == "mannequin": - body_layer = organize_body(item) - layers.append(body_layer) - return item['body_image'].size - else: - front_layer, back_layer = organize_clothing(item) - layers.append(front_layer) - layers.append(back_layer) - - -def process_object(object_data): - basic = object_data['basic'] - items_response = {'layers': []} - - if basic['single_overall'] == "overall": - item_results = [process_item(item, basic) for item in object_data['items']] - layers = [] - futures = [] - body_size = None - for item in item_results: - futures = [process_layer(item, layers)] - for future in futures: - if future is not None: - body_size = future - 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': 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, - - # 'image': lay['image'], - # 'mask_image': lay['mask_image'], - }) - items_response['synthesis_url'] = synthesis(layers, new_size, basic) - else: - item_results = process_item(object_data['items'][0], basic) - items_response['layers'].append({ - 'image_category': f"{item_results['name']}_front", - 'image_size': item_results['back_image'].size if item_results['back_image'] else None, - 'position': None, - 'priority': 0, - 'image_url': item_results['front_image_url'], - 'mask_url': item_results['mask_url'], - "gradient_string": item_results['gradient_string'] if 'gradient_string' in item_results.keys() else "", - 'pattern_image_url': item_results['pattern_image_url'] if 'pattern_image_url' in item_results.keys() else None, - - }) - items_response['layers'].append({ - 'image_category': f"{item_results['name']}_back", - 'image_size': item_results['front_image'].size if item_results['front_image'] else None, - 'position': None, - 'priority': 0, - 'image_url': item_results['back_image_url'], - 'mask_url': item_results['mask_url'], - "gradient_string": item_results['gradient_string'] if 'gradient_string' in item_results.keys() else "", - 'pattern_image_url': item_results['pattern_image_url'] if 'pattern_image_url' in item_results.keys() else None, - - }) - items_response['synthesis_url'] = synthesis_single(item_results['front_image'], item_results['back_image']) - return items_response - - -def update_base_size_priority(layers, size): - # 计算透明背景图片的宽度 - min_x = min(info['position'][1] for info in layers) - x_list = [] - for info in layers: - if info['image'] is not None: - x_list.append(info['position'][1] + info['image'].width) - max_x = max(x_list) - new_width = max_x - min_x - new_height = 700 - # 更新坐标 - for info in layers: - info['adaptive_position'] = (info['position'][0], info['position'][1] - min_x) - return layers, (new_width, new_height) - - -def run(): - object = {"objects": [{"basic": {"body_point_test": {"waistband_right": [199, 239], "hand_point_right": [220, 308], "waistband_left": [113, 239], "hand_point_left": [92, 310], "shoulder_left": [99, 111], "shoulder_right": [214, 111]}, "layer_order": False, "scale_bag": 0.7, "scale_earrings": 0.16, "self_template": True, "single_overall": "single", "switch_category": "Outwear"}, "items": [ - {"color": "189 112 112", "icon": "none", "image_id": 116441, "offset": [1, 1], "path": "aida-sys-image/images/female/outwear/outwear_p3139.jpg", "print": {"element": {"element_angle_list": [], "element_path_list": [], "element_scale_list": [], "location": []}, "overall": {"location": [[0.0, 0.0]], "print_angle_list": [0.0, 0.0], "print_path_list": [], "print_scale_list": [0.0, 0.0]}, "single": {"location": [], "print_angle_list": [], "print_path_list": [], "print_scale_list": []}}, - "resize_scale": [1.0, 1.0], "type": "Outwear"}]}, {"basic": {"body_point_test": {"waistband_right": [199, 239], "hand_point_right": [220, 308], "waistband_left": [113, 239], "hand_point_left": [92, 310], "shoulder_left": [99, 111], "shoulder_right": [214, 111]}, "layer_order": False, "scale_bag": 0.7, "scale_earrings": 0.16, "self_template": True, "single_overall": "single", "switch_category": "Outwear"}, "items": [ - {"color": "189 112 112", "icon": "none", "image_id": 81518, "offset": [1, 1], "path": "aida-sys-image/images/female/outwear/0628000071.jpg", "print": {"element": {"element_angle_list": [], "element_path_list": [], "element_scale_list": [], "location": []}, "overall": {"location": [[0.0, 0.0]], "print_angle_list": [0.0, 0.0], "print_path_list": [], "print_scale_list": [0.0, 0.0]}, "single": {"location": [], "print_angle_list": [], "print_path_list": [], "print_scale_list": []}}, - "resize_scale": [1.0, 1.0], "type": "Outwear"}]}, {"basic": {"body_point_test": {"waistband_right": [199, 239], "hand_point_right": [220, 308], "waistband_left": [113, 239], "hand_point_left": [92, 310], "shoulder_left": [99, 111], "shoulder_right": [214, 111]}, "layer_order": False, "scale_bag": 0.7, "scale_earrings": 0.16, "self_template": True, "single_overall": "single", "switch_category": "Outwear"}, "items": [ - {"color": "189 112 112", "icon": "none", "image_id": 65687, "offset": [1, 1], "path": "aida-sys-image/images/female/outwear/outwear_746.jpg", "print": {"element": {"element_angle_list": [], "element_path_list": [], "element_scale_list": [], "location": []}, "overall": {"location": [[0.0, 0.0]], "print_angle_list": [0.0, 0.0], "print_path_list": [], "print_scale_list": [0.0, 0.0]}, "single": {"location": [], "print_angle_list": [], "print_path_list": [], "print_scale_list": []}}, - "resize_scale": [1.0, 1.0], "type": "Outwear"}]}, {"basic": {"body_point_test": {"waistband_right": [199, 239], "hand_point_right": [220, 308], "waistband_left": [113, 239], "hand_point_left": [92, 310], "shoulder_left": [99, 111], "shoulder_right": [214, 111]}, "layer_order": False, "scale_bag": 0.7, "scale_earrings": 0.16, "self_template": True, "single_overall": "single", "switch_category": "Outwear"}, "items": [ - {"color": "189 112 112", "icon": "none", "image_id": 90051, "offset": [1, 1], "path": "aida-sys-image/images/female/outwear/0628000864.jpg", "print": {"element": {"element_angle_list": [], "element_path_list": [], "element_scale_list": [], "location": []}, "overall": {"location": [[0.0, 0.0]], "print_angle_list": [0.0, 0.0], "print_path_list": [], "print_scale_list": [0.0, 0.0]}, "single": {"location": [], "print_angle_list": [], "print_path_list": [], "print_scale_list": []}}, - "resize_scale": [1.0, 1.0], "type": "Outwear"}]}, {"basic": {"body_point_test": {"waistband_right": [199, 239], "hand_point_right": [220, 308], "waistband_left": [113, 239], "hand_point_left": [92, 310], "shoulder_left": [99, 111], "shoulder_right": [214, 111]}, "layer_order": False, "scale_bag": 0.7, "scale_earrings": 0.16, "self_template": True, "single_overall": "single", "switch_category": "Outwear"}, "items": [ - {"color": "189 112 112", "icon": "none", "image_id": 67420, "offset": [1, 1], "path": "aida-sys-image/images/female/outwear/0825001648.jpg", "print": {"element": {"element_angle_list": [], "element_path_list": [], "element_scale_list": [], "location": []}, "overall": {"location": [[0.0, 0.0]], "print_angle_list": [0.0, 0.0], "print_path_list": [], "print_scale_list": [0.0, 0.0]}, "single": {"location": [], "print_angle_list": [], "print_path_list": [], "print_scale_list": []}}, - "resize_scale": [1.0, 1.0], "type": "Outwear"}]}, {"basic": {"body_point_test": {"waistband_right": [199, 239], "hand_point_right": [220, 308], "waistband_left": [113, 239], "hand_point_left": [92, 310], "shoulder_left": [99, 111], "shoulder_right": [214, 111]}, "layer_order": False, "scale_bag": 0.7, "scale_earrings": 0.16, "self_template": True, "single_overall": "single", "switch_category": "Outwear"}, "items": [ - {"color": "189 112 112", "icon": "none", "image_id": 90354, "offset": [1, 1], "path": "aida-sys-image/images/female/outwear/0628001300.jpg", "print": {"element": {"element_angle_list": [], "element_path_list": [], "element_scale_list": [], "location": []}, "overall": {"location": [[0.0, 0.0]], "print_angle_list": [0.0, 0.0], "print_path_list": [], "print_scale_list": [0.0, 0.0]}, "single": {"location": [], "print_angle_list": [], "print_path_list": [], "print_scale_list": []}}, - "resize_scale": [1.0, 1.0], "type": "Outwear"}]}, {"basic": {"body_point_test": {"waistband_right": [199, 239], "hand_point_right": [220, 308], "waistband_left": [113, 239], "hand_point_left": [92, 310], "shoulder_left": [99, 111], "shoulder_right": [214, 111]}, "layer_order": False, "scale_bag": 0.7, "scale_earrings": 0.16, "self_template": True, "single_overall": "single", "switch_category": "Outwear"}, "items": [ - {"color": "189 112 112", "icon": "none", "image_id": 67420, "offset": [1, 1], "path": "aida-sys-image/images/female/outwear/0825001648.jpg", "print": {"element": {"element_angle_list": [], "element_path_list": [], "element_scale_list": [], "location": []}, "overall": {"location": [[0.0, 0.0]], "print_angle_list": [0.0, 0.0], "print_path_list": [], "print_scale_list": [0.0, 0.0]}, "single": {"location": [], "print_angle_list": [], "print_path_list": [], "print_scale_list": []}}, - "resize_scale": [1.0, 1.0], "type": "Outwear"}]}, {"basic": {"body_point_test": {"waistband_right": [199, 239], "hand_point_right": [220, 308], "waistband_left": [113, 239], "hand_point_left": [92, 310], "shoulder_left": [99, 111], "shoulder_right": [214, 111]}, "layer_order": False, "scale_bag": 0.7, "scale_earrings": 0.16, "self_template": True, "single_overall": "single", "switch_category": "Outwear"}, "items": [ - {"color": "189 112 112", "icon": "none", "image_id": 101477, "offset": [1, 1], "path": "aida-sys-image/images/female/outwear/903000063.jpg", "print": {"element": {"element_angle_list": [], "element_path_list": [], "element_scale_list": [], "location": []}, "overall": {"location": [[0.0, 0.0]], "print_angle_list": [0.0, 0.0], "print_path_list": [], "print_scale_list": [0.0, 0.0]}, "single": {"location": [], "print_angle_list": [], "print_path_list": [], "print_scale_list": []}}, - "resize_scale": [1.0, 1.0], "type": "Outwear"}]}], "process_id": "3615898424593104"} - - object_result = {} - with ThreadPoolExecutor() as executor: - results = list(executor.map(process_object, object['objects'])) - for i, result in enumerate(results): - object_result[i] = result - - pprint(object_result) - - -if __name__ == '__main__': - start_time = time.time() - run() - print(time.time() - start_time)