feat 1.design 取消进度模式测试

2.结果以stream发送到java
3.新增配饰类
fix
This commit is contained in:
zhouchengrong
2024-11-26 16:08:10 +08:00
parent 754c6eff87
commit 7eb9b18f8f
9 changed files with 405 additions and 11 deletions

View File

@@ -2,13 +2,13 @@ import json
import logging import logging
import os 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.design import DesignModel, DesignProgressModel, ModelProgressModel, DBGConfigModel
from app.schemas.response_template import ResponseModel from app.schemas.response_template import ResponseModel
from app.service.design.model_process_service import model_transpose 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_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 from app.service.design_fast.utils.redis_utils import Redis
router = APIRouter() router = APIRouter()
@@ -16,7 +16,7 @@ logger = logging.getLogger()
@router.post("/design") @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) 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') @router.post('/get_progress')
def get_progress(request_data: DesignProgressModel): def get_progress(request_data: DesignProgressModel):
""" """

View File

@@ -5,8 +5,8 @@ import time
from minio import Minio from minio import Minio
from app.core.config import * from app.core.config import *
from app.service.design_fast.item import BodyItem, TopItem, BottomItem from app.service.design_fast.item import BodyItem, TopItem, BottomItem, AccessoriesItem
from app.service.design_fast.utils.organize import organize_body, organize_clothing 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.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.design_fast.utils.synthesis_item import synthesis, synthesis_single, update_base_size_priority
from app.service.utils.decorator import RunTime 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']: elif item['type'].lower() in ['blouse', 'outwear', 'dress', 'tops']:
top_server = TopItem(data=item, basic=basic, minio_client=minio_client) top_server = TopItem(data=item, basic=basic, minio_client=minio_client)
item_data = top_server.process() 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) bottom_server = BottomItem(data=item, basic=basic, minio_client=minio_client)
item_data = bottom_server.process() 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 return item_data
@@ -38,6 +43,10 @@ def process_layer(item, layers):
body_layer = organize_body(item) body_layer = organize_body(item)
layers.append(body_layer) layers.append(body_layer)
return item['body_image'].size 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: else:
front_layer, back_layer = organize_clothing(item) front_layer, back_layer = organize_clothing(item)
layers.append(front_layer) layers.append(front_layer)
@@ -57,7 +66,7 @@ def design_generate(request_data):
def process_object(step, object): def process_object(step, object):
nonlocal active_threads nonlocal active_threads
basic = object['basic'] basic = object['basic']
items_response = {'layers': []} items_response = {'layers': [], 'objectSign': object['objectSign'] if 'objectSign' in object.keys() else ""}
if basic['single_overall'] == "overall": if basic['single_overall'] == "overall":
item_results = [] item_results = []
for item in object['items']: for item in object['items']:
@@ -126,6 +135,136 @@ def design_generate(request_data):
return object_response 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__': if __name__ == '__main__':
object_data = { object_data = {
"objects": [ "objects": [

View File

@@ -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: class BaseItem:
@@ -9,6 +9,27 @@ class BaseItem:
self.result.update(basic) 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): class TopItem(BaseItem):
def __init__(self, data, basic, minio_client): def __init__(self, data, basic, minio_client):
super().__init__(data, basic) super().__init__(data, basic)

View File

@@ -74,6 +74,8 @@ class LoadImage:
keypoint = 'head_point' keypoint = 'head_point'
elif name == 'earring': elif name == 'earring':
keypoint = 'ear_point' keypoint = 'ear_point'
elif name == 'accessories':
keypoint = "accessories"
else: else:
raise KeyError(f"{name} does not belong to item category list: blouse, outwear, dress, trousers, skirt, " raise KeyError(f"{name} does not belong to item category list: blouse, outwear, dress, trousers, skirt, "
f"bag, shoes, hairstyle, earring.") f"bag, shoes, hairstyle, earring.")

View File

@@ -18,7 +18,7 @@ class Scaling:
- -
int(result['body_point_test'][result['keypoint'] + '_right'][0])) ** 2 + 1 int(result['body_point_test'][result['keypoint'] + '_right'][0])) ** 2 + 1
) )
if distance_clo == 0: if distance_clo == 0:
result['scale'] = 1 result['scale'] = 1
else: else:
@@ -46,4 +46,6 @@ class Scaling:
result['scale'] = result['scale_bag'] result['scale'] = result['scale_bag']
elif result['keypoint'] == 'ear_point': elif result['keypoint'] == 'ear_point':
result['scale'] = result['scale_earrings'] result['scale'] = result['scale_earrings']
else:
result['scale'] = 1
return result return result

View File

@@ -21,7 +21,7 @@ class Split(object):
def __call__(self, result): def __call__(self, result):
try: 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'] front_mask = result['front_mask']
back_mask = result['back_mask'] back_mask = result['back_mask']
rgba_image = rgb_to_rgba(result['final_image'], front_mask + back_mask) rgba_image = rgb_to_rgba(result['final_image'], front_mask + back_mask)

View File

@@ -55,6 +55,45 @@ def organize_clothing(layer):
return front_layer, back_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): def calculate_start_point(keypoint_type, scale, clothes_point, body_point, offset, resize_scale):
""" """
Align left Align left

View File

@@ -79,9 +79,11 @@ def synthesis(data, size, basic_info):
_, binary_body_mask = cv2.threshold(body_mask, 127, 255, cv2.THRESH_BINARY) _, binary_body_mask = cv2.threshold(body_mask, 127, 255, cv2.THRESH_BINARY)
top_outer_mask = np.array(binary_body_mask) top_outer_mask = np.array(binary_body_mask)
bottom_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 top = True
bottom = True bottom = True
accessories = True
i = len(data) i = len(data)
while i: while i:
i -= 1 i -= 1
@@ -109,10 +111,23 @@ def synthesis(data, size, basic_info):
background = np.zeros_like(top_outer_mask) 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] 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 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: elif bottom is False and top is False:
break break
all_mask = cv2.bitwise_or(top_outer_mask, bottom_outer_mask) 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: for layer in data:
if layer['image'] is not None: if layer['image'] is not None:

View File

@@ -82,7 +82,7 @@ if __name__ == '__main__':
# url = "aida-users/89/sketchboard/female/Dress/e6724ab7-8d3f-4677-abe0-c3e42ab7af85.jpeg" # 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/87/print/956614a2-7e75-4fbe-9ed0-c1831e37a2c9-4-87.png"
# url = "aida-users/89/single_logo/123-89.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" # url = "aida-collection-element/12148/Sketchboard/95ea577b-305b-4a62-b30a-39c0dd3ddb3f.png"
read_type = "2" read_type = "2"