diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0b6bf22 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +seg_cache +test \ No newline at end of file diff --git a/app/api/api_design.py b/app/api/api_design.py index aa9fe43..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): """ 创建一个具有以下参数的请求体: 示例参数: @@ -67,7 +67,6 @@ def design(request_data: DesignModel): 0 ], "path": "aida-sys-image/images/female/trousers/0825000630.jpg", - "seg_mask_url": "test/result.png", "print": { "element": { "element_angle_list": [], @@ -104,7 +103,6 @@ def design(request_data: DesignModel): 0 ], "path": "aida-sys-image/images/female/blouse/0902003811.jpg", - "seg_mask_url": "test/result.png", "print": { "element": { "element_angle_list": [], @@ -141,7 +139,6 @@ def design(request_data: DesignModel): 0 ], "path": "aida-sys-image/images/female/outwear/0825000410.jpg", - "seg_mask_url": "test/result.png", "print": { "element": { "element_angle_list": [], @@ -167,6 +164,10 @@ def design(request_data: DesignModel): 1.0, 1.0 ], + "transparent":{ + "mask_url":"test/transparent_test/transparent_mask.png", + "scale":0.1 + }, "type": "Outwear" }, { @@ -195,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/api/api_generate_image.py b/app/api/api_generate_image.py index b021158..53790a3 100644 --- a/app/api/api_generate_image.py +++ b/app/api/api_generate_image.py @@ -26,6 +26,7 @@ def generate_image(request_item: GenerateImageModel, background_tasks: Backgroun - **mode**: 生成模式,img2img或者txt2img - **category**: 生成图片的类别,sketch print 等等 - **gender**: 生成sketch专用,服装类别 + - **version**: 使用模型版本 fast 或者 high 示例参数: { diff --git a/app/api/api_query_image.py b/app/api/api_query_image.py index d27c67b..ca0dbe6 100644 --- a/app/api/api_query_image.py +++ b/app/api/api_query_image.py @@ -1,8 +1,7 @@ import json import logging -from http.client import HTTPException -from fastapi import APIRouter +from fastapi import APIRouter, HTTPException from app.schemas.query_image import QueryImageModel from app.schemas.response_template import ResponseModel diff --git a/app/service/design_fast/design_generate.py b/app/service/design_fast/design_generate.py index ac1f79c..f4012cf 100644 --- a/app/service/design_fast/design_generate.py +++ b/app/service/design_fast/design_generate.py @@ -2,11 +2,12 @@ import logging import threading import time +import requests 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 +27,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 +44,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 +67,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']: @@ -81,6 +91,7 @@ def design_generate(request_data): '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: @@ -125,6 +136,117 @@ def design_generate(request_data): return object_response +@RunTime +def design_generate_v2(request_data): + objects_data = request_data.dict()['objects'] + threads = [] + + def process_object(step, object): + basic = object['basic'] + items_response = { + 'layers': [], + 'objectSign': object['objectSign'] if 'objectSign' in object.keys() else "", + 'requestId': object['requestId'] if 'requestId' 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) + + for step, object in enumerate(objects_data): + t = threading.Thread(target=process_object, args=(step, object)) + threads.append(t) + t.start() + + +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 e10320d..ec18b17 100644 --- a/app/service/design_fast/item.py +++ b/app/service/design_fast/item.py @@ -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) @@ -16,6 +37,7 @@ class TopItem(BaseItem): LoadImage(minio_client), KeyPoint(), Segmentation(minio_client), + # BackPerspective(minio_client), Color(minio_client), PrintPainting(minio_client), Scaling(), @@ -36,6 +58,7 @@ class BottomItem(BaseItem): KeyPoint(), ContourDetection(), # Segmentation(), + # BackPerspective(minio_client), Color(minio_client), PrintPainting(minio_client), Scaling(), diff --git a/app/service/design_fast/pipeline/__init__.py b/app/service/design_fast/pipeline/__init__.py index ec55933..f265bbe 100644 --- a/app/service/design_fast/pipeline/__init__.py +++ b/app/service/design_fast/pipeline/__init__.py @@ -1,3 +1,4 @@ +from .back_perspective import BackPerspective from .color import Color from .contour_detection import ContourDetection from .keypoint import KeyPoint @@ -13,6 +14,7 @@ __all__ = [ 'KeyPoint', 'ContourDetection', 'Segmentation', + 'BackPerspective', 'Color', 'PrintPainting', 'Scaling', diff --git a/app/service/design_fast/pipeline/back_perspective.py b/app/service/design_fast/pipeline/back_perspective.py new file mode 100644 index 0000000..5ddd37c --- /dev/null +++ b/app/service/design_fast/pipeline/back_perspective.py @@ -0,0 +1,79 @@ +import cv2 +import numpy as np + +from app.service.design_fast.utils.design_ensemble import get_seg_result +from app.service.utils.new_oss_client import oss_upload_image + + +class BackPerspective: + def __init__(self, minio_client): + self.minio_client = minio_client + + def __call__(self, result): + + # 如果sketch为系统图 查看是否有对应的 背后视角图 + if result['path'].split('/')[0] == 'aida-sys-image': + file_path = result['path'].replace("images", 'images_back', 1) + if self.is_file_exists(bucket_name='aida-sys-image', file_name=file_path[file_path.find('/') + 1:]): + result['back_perspective_url'] = file_path + return result + else: + seg_result = get_seg_result("1", result['image'])[0] + elif result['name'] in ['blouse', 'outwear', 'dress', 'tops']: + seg_result = result['seg_result'] + else: + seg_result = get_seg_result("1", result['image'])[0] + + m = self.thicken_contours_and_display(seg_result, thickness=10, color=(0, 0, 0)) + back_sketch = result['image'].copy() + back_sketch[m > 100] = 255 + # 上传背后视角图 + _, img_encoded = cv2.imencode(".jpg", back_sketch) + + resp = oss_upload_image(self.minio_client, bucket='test', object_name=result['path'], image_bytes=img_encoded.tobytes()) + result['back_perspective_url'] = f"{resp.bucket_name}/{resp.object_name}" + return result + + def thicken_contours_and_display(self, mask, thickness=10, color=(0, 0, 0)): + mask = mask.astype(np.uint8) * 255 + # 查找轮廓 + contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + + # 创建一个彩色副本用于绘制轮廓 + mask_color = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR) + + def thicken_contour_inward(contour, thick): + # 创建一个空白的黑色图像与原始掩码大小相同 + blank = np.zeros_like(mask) + # 在空白图像上绘制白色的轮廓 + cv2.drawContours(blank, [contour], -1, 255, thickness=thick) + # 找到轮廓的中心(可以用重心等方法近似) + M = cv2.moments(contour) + cx = int(M['m10'] / M['m00']) + cy = int(M['m01'] / M['m00']) + # 进行距离变换,离中心越近的值越小 + dist_transform = cv2.distanceTransform(255 - blank, cv2.DIST_L2, 5) + # 根据距离变换的值来决定是否保留像素,离中心近的像素更容易被保留 + result = np.zeros_like(mask) + for i in range(dist_transform.shape[0]): + for j in range(dist_transform.shape[1]): + if dist_transform[i, j] < thick: + result[i, j] = 255 + return result + + for contour in contours: + thickened_contour = thicken_contour_inward(contour, thickness) + mask_color[thickened_contour > 0] = color + + _, binary_result = cv2.threshold(mask_color, 127, 255, cv2.THRESH_BINARY) + + # 转换为掩码形式 + mask_result = cv2.cvtColor(binary_result, cv2.COLOR_BGR2GRAY) + return mask_result + + def is_file_exists(self, bucket_name, file_name): + try: + self.minio_client.stat_object(bucket_name, file_name) + return True + except Exception: + return False diff --git a/app/service/design_fast/pipeline/color.py b/app/service/design_fast/pipeline/color.py index 546c671..3033bb5 100644 --- a/app/service/design_fast/pipeline/color.py +++ b/app/service/design_fast/pipeline/color.py @@ -14,11 +14,18 @@ class Color: def __call__(self, result): dim_image_h, dim_image_w = result['image'].shape[0:2] + # 渐变色 if "gradient" in result.keys() and result['gradient'] != "": bucket_name = result['gradient'].split('/')[0] object_name = result['gradient'][result['gradient'].find('/') + 1:] pattern = self.get_gradient(bucket_name=bucket_name, object_name=object_name) resize_pattern = cv2.resize(pattern, (dim_image_w, dim_image_h), interpolation=cv2.INTER_AREA) + # 无色 + elif "color" not in result.keys() or result['color'] == "": + result['final_image'] = result['pattern_image'] = result['single_image'] = result['image'] + result['alpha'] = 100 / 255.0 + return result + # 正常颜色 else: pattern = self.get_pattern(result['color']) resize_pattern = cv2.resize(pattern, (dim_image_w, dim_image_h), interpolation=cv2.INTER_AREA) 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..d1c7a36 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,16 @@ class Scaling: result['scale'] = result['scale_bag'] elif result['keypoint'] == 'ear_point': result['scale'] = result['scale_earrings'] + elif result['keypoint'] == 'accessories': + # 由于没有识别配饰keypoint的模型 所以统一将配饰的两个关键点设定为 (0,0) (0,img.width) + # 模特的关键点设定为(0,0) (0,320/2) 距离比例简写为 160 / img.width + distance_clo = result['img_shape'][1] + distance_bdy = 320 / 2 + + if distance_clo == 0: + result['scale'] = 1 + else: + result['scale'] = distance_bdy / distance_clo + 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 737b50e..344c5c5 100644 --- a/app/service/design_fast/pipeline/split.py +++ b/app/service/design_fast/pipeline/split.py @@ -8,9 +8,10 @@ from cv2 import cvtColor, COLOR_BGR2RGBA from app.core.config import AIDA_CLOTHING from app.service.design_fast.utils.conversion_image import rgb_to_rgba +from app.service.design_fast.utils.transparent import sketch_to_transparent 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 +from app.service.utils.new_oss_client import oss_upload_image, oss_get_image class Split(object): @@ -20,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) @@ -30,6 +31,24 @@ class Split(object): front_mask = cv2.resize(front_mask, new_size) result_front_image[front_mask != 0] = rgba_image[front_mask != 0] result_front_image_pil = Image.fromarray(cvtColor(result_front_image, COLOR_BGR2RGBA)) + if 'transparent' in result.keys(): + # 用户自选区域transparent + transparent = result['transparent'] + if transparent['mask_url'] is not None and transparent['mask_url'] != "": + # 预处理用户自选区mask + seg_mask = oss_get_image(oss_client=self.minio_client, bucket=transparent['mask_url'].split('/')[0], object_name=transparent['mask_url'][transparent['mask_url'].find('/') + 1:], data_type="cv2") + seg_mask = cv2.resize(seg_mask, new_size, interpolation=cv2.INTER_NEAREST) + # 转换颜色空间为 RGB(OpenCV 默认是 BGR) + image_rgb = cv2.cvtColor(seg_mask, cv2.COLOR_BGR2RGB) + + r, g, b = cv2.split(image_rgb) + blue_mask = b > r + + # 创建红色和绿色掩码 + transparent_mask = np.array(blue_mask, dtype=np.uint8) * 255 + result_front_image_pil = sketch_to_transparent(result_front_image_pil, transparent_mask, transparent["scale"]) + else: + result_front_image_pil = sketch_to_transparent(result_front_image_pil, front_mask, transparent["scale"]) result['front_image'], result["front_image_url"], _ = upload_png_mask(self.minio_client, result_front_image_pil, f'{generate_uuid()}', mask=None) height, width = front_mask.shape diff --git a/app/service/design_fast/utils/design_ensemble.py b/app/service/design_fast/utils/design_ensemble.py index f4f6a34..267ea00 100644 --- a/app/service/design_fast/utils/design_ensemble.py +++ b/app/service/design_fast/utils/design_ensemble.py @@ -85,7 +85,7 @@ def seg_preprocess(img_path): if ori_shape != (img_scale_w, img_scale_h): # mmcv.imresize(img, img_scale_h, img_scale_w) # 老代码 引以为戒!哈哈哈~ h和w写反了 img = cv2.resize(img, (img_scale_h, img_scale_w)) - img = mmcv.imnormalize(img, mean=np.array([123.675, 116.28, 103.53]), std=np.array([58.395, 57.12, 57.375]), to_rgb=True) + # img = mmcv.imnormalize(img, mean=np.array([123.675, 116.28, 103.53]), std=np.array([58.395, 57.12, 57.375]), to_rgb=True) preprocessed_img = np.expand_dims(img.transpose(2, 0, 1), axis=0) return preprocessed_img, ori_shape diff --git a/app/service/design_fast/utils/organize.py b/app/service/design_fast/utils/organize.py index 8190de0..33edc4f 100644 --- a/app/service/design_fast/utils/organize.py +++ b/app/service/design_fast/utils/organize.py @@ -33,8 +33,8 @@ def organize_clothing(layer): 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'] - + 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), @@ -50,6 +50,46 @@ def organize_clothing(layer): 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 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 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/design_fast/utils/transparent.py b/app/service/design_fast/utils/transparent.py new file mode 100644 index 0000000..3f73807 --- /dev/null +++ b/app/service/design_fast/utils/transparent.py @@ -0,0 +1,26 @@ +from PIL import Image + + +def sketch_to_transparent(image, mask, transparency): + # 打开原始图片 + image = image.convert("RGBA") + # 打开mask图片,假设mask图片是灰度图,白色区域为要处理的区域,黑色区域为保留的区域 + mask = Image.fromarray(mask) + + # 根据透明度调整因子,将透明度转换为0-255之间的值 + alpha_value = int((1 - transparency) * 255.0) + + # 获取图片的像素数据 + image_pixels = image.load() + mask_pixels = mask.load() + + width, height = image.size + + for y in range(height): + for x in range(width): + # 如果mask区域对应的像素为白色(值大于128,这里假设白色为要处理的区域,可根据实际情况调整) + if mask_pixels[x, y] > 128: + r, g, b, a = image_pixels[x, y] + image_pixels[x, y] = (r, g, b, alpha_value) + + return image diff --git a/app/service/search_image_with_text/service.py b/app/service/search_image_with_text/service.py index 712050f..edd4d93 100644 --- a/app/service/search_image_with_text/service.py +++ b/app/service/search_image_with_text/service.py @@ -6,6 +6,8 @@ from chromadb.config import Settings from chromadb.utils.embedding_functions.ollama_embedding_function import OllamaEmbeddingFunction from tqdm import tqdm +from app.core.config import OLLAMA_URL + # 读取 csv 文件 # csv_file_path = r'D:/Files/csv/output/output.csv' # image_path = r'D:/images-clean' @@ -17,7 +19,8 @@ client = chromadb.Client(Settings(is_persistent=True, persist_directory="/vector # client = chromadb.Client(Settings(is_persistent=True, persist_directory="./service/search_image_with_text/vector_db")) # client = chromadb.Client(Settings(is_persistent=True, persist_directory="D:/workspace/AiDLab/vector_db")) # 创建集合 -embedding_fn = OllamaEmbeddingFunction(url="http://10.1.1.240:11434/api/embeddings", model_name="mxbai-embed-large") +# embedding_fn = OllamaEmbeddingFunction(url="http://localhost:11434/api/embeddings", model_name="mxbai-embed-large") +embedding_fn = OllamaEmbeddingFunction(url=OLLAMA_URL, model_name="mxbai-embed-large") # def create_collection(): @@ -66,7 +69,7 @@ embedding_fn = OllamaEmbeddingFunction(url="http://10.1.1.240:11434/api/embeddin def query(gender, content): collection = client.get_collection("sub_sketches_description", embedding_function=embedding_fn) # 6. 查询相似内容 - user_gender = gender # 用户输入的性别 + user_gender = gender.lower() # 用户输入的性别 user_content = content # 用户输入的内容 results = collection.query( diff --git a/app/service/utils/new_oss_client.py b/app/service/utils/new_oss_client.py index 95a0fbf..4b3cbb1 100644 --- a/app/service/utils/new_oss_client.py +++ b/app/service/utils/new_oss_client.py @@ -82,9 +82,10 @@ 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-users/31/sketchboard/female/dress/6edcbf92-7da9-4809-a0a8-a4b4f06dec1e0628000041.jpg" + url = "aida-users/89/test/123-89.png" + # url = "aida-collection-element/12148/Sketchboard/95ea577b-305b-4a62-b30a-39c0dd3ddb3f.png" - read_type = "cv2" + read_type = "2" if read_type == "cv2": img = oss_get_image(oss_client=minio_client, bucket=url.split('/')[0], object_name=url[url.find('/') + 1:], data_type=read_type) cv2.imshow("", img) diff --git a/requirements.txt b/requirements.txt index 6c9e38f..7350714 100644 Binary files a/requirements.txt and b/requirements.txt differ