Merge branch 'refs/heads/develop'

# Conflicts:
#	app/api/api_query_image.py
#	app/service/search_image_with_text/service.py
This commit is contained in:
zhouchengrong
2024-12-02 23:40:16 +08:00
19 changed files with 552 additions and 22 deletions

2
.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
seg_cache
test

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):
""" """
创建一个具有以下参数的请求体: 创建一个具有以下参数的请求体:
示例参数: 示例参数:
@@ -67,7 +67,6 @@ def design(request_data: DesignModel):
0 0
], ],
"path": "aida-sys-image/images/female/trousers/0825000630.jpg", "path": "aida-sys-image/images/female/trousers/0825000630.jpg",
"seg_mask_url": "test/result.png",
"print": { "print": {
"element": { "element": {
"element_angle_list": [], "element_angle_list": [],
@@ -104,7 +103,6 @@ def design(request_data: DesignModel):
0 0
], ],
"path": "aida-sys-image/images/female/blouse/0902003811.jpg", "path": "aida-sys-image/images/female/blouse/0902003811.jpg",
"seg_mask_url": "test/result.png",
"print": { "print": {
"element": { "element": {
"element_angle_list": [], "element_angle_list": [],
@@ -141,7 +139,6 @@ def design(request_data: DesignModel):
0 0
], ],
"path": "aida-sys-image/images/female/outwear/0825000410.jpg", "path": "aida-sys-image/images/female/outwear/0825000410.jpg",
"seg_mask_url": "test/result.png",
"print": { "print": {
"element": { "element": {
"element_angle_list": [], "element_angle_list": [],
@@ -167,6 +164,10 @@ def design(request_data: DesignModel):
1.0, 1.0,
1.0 1.0
], ],
"transparent":{
"mask_url":"test/transparent_test/transparent_mask.png",
"scale":0.1
},
"type": "Outwear" "type": "Outwear"
}, },
{ {
@@ -195,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

@@ -26,6 +26,7 @@ def generate_image(request_item: GenerateImageModel, background_tasks: Backgroun
- **mode**: 生成模式img2img或者txt2img - **mode**: 生成模式img2img或者txt2img
- **category**: 生成图片的类别sketch print 等等 - **category**: 生成图片的类别sketch print 等等
- **gender**: 生成sketch专用服装类别 - **gender**: 生成sketch专用服装类别
- **version**: 使用模型版本 fast 或者 high
示例参数: 示例参数:
{ {

View File

@@ -1,8 +1,7 @@
import json import json
import logging 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.query_image import QueryImageModel
from app.schemas.response_template import ResponseModel from app.schemas.response_template import ResponseModel

View File

@@ -2,11 +2,12 @@ import logging
import threading import threading
import time import time
import requests
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 +27,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 +44,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 +67,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']:
@@ -81,6 +91,7 @@ def design_generate(request_data):
'mask_url': lay['mask_url'], 'mask_url': lay['mask_url'],
'image_url': lay['image_url'] if 'image_url' in lay.keys() else None, '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, '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) items_response['synthesis_url'] = synthesis(layers, new_size, basic)
else: else:
@@ -125,6 +136,117 @@ def design_generate(request_data):
return object_response 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__': if __name__ == '__main__':
object_data = { object_data = {
"objects": [ "objects": [

View File

@@ -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)
@@ -16,6 +37,7 @@ class TopItem(BaseItem):
LoadImage(minio_client), LoadImage(minio_client),
KeyPoint(), KeyPoint(),
Segmentation(minio_client), Segmentation(minio_client),
# BackPerspective(minio_client),
Color(minio_client), Color(minio_client),
PrintPainting(minio_client), PrintPainting(minio_client),
Scaling(), Scaling(),
@@ -36,6 +58,7 @@ class BottomItem(BaseItem):
KeyPoint(), KeyPoint(),
ContourDetection(), ContourDetection(),
# Segmentation(), # Segmentation(),
# BackPerspective(minio_client),
Color(minio_client), Color(minio_client),
PrintPainting(minio_client), PrintPainting(minio_client),
Scaling(), Scaling(),

View File

@@ -1,3 +1,4 @@
from .back_perspective import BackPerspective
from .color import Color from .color import Color
from .contour_detection import ContourDetection from .contour_detection import ContourDetection
from .keypoint import KeyPoint from .keypoint import KeyPoint
@@ -13,6 +14,7 @@ __all__ = [
'KeyPoint', 'KeyPoint',
'ContourDetection', 'ContourDetection',
'Segmentation', 'Segmentation',
'BackPerspective',
'Color', 'Color',
'PrintPainting', 'PrintPainting',
'Scaling', 'Scaling',

View File

@@ -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

View File

@@ -14,11 +14,18 @@ class Color:
def __call__(self, result): def __call__(self, result):
dim_image_h, dim_image_w = result['image'].shape[0:2] dim_image_h, dim_image_w = result['image'].shape[0:2]
# 渐变色
if "gradient" in result.keys() and result['gradient'] != "": if "gradient" in result.keys() and result['gradient'] != "":
bucket_name = result['gradient'].split('/')[0] bucket_name = result['gradient'].split('/')[0]
object_name = result['gradient'][result['gradient'].find('/') + 1:] object_name = result['gradient'][result['gradient'].find('/') + 1:]
pattern = self.get_gradient(bucket_name=bucket_name, object_name=object_name) 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) 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: else:
pattern = self.get_pattern(result['color']) pattern = self.get_pattern(result['color'])
resize_pattern = cv2.resize(pattern, (dim_image_w, dim_image_h), interpolation=cv2.INTER_AREA) resize_pattern = cv2.resize(pattern, (dim_image_w, dim_image_h), interpolation=cv2.INTER_AREA)

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

@@ -46,4 +46,16 @@ 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']
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 return result

View File

@@ -8,9 +8,10 @@ from cv2 import cvtColor, COLOR_BGR2RGBA
from app.core.config import AIDA_CLOTHING 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.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.design_fast.utils.upload_image import upload_png_mask
from app.service.utils.generate_uuid import generate_uuid 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): class Split(object):
@@ -20,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)
@@ -30,6 +31,24 @@ class Split(object):
front_mask = cv2.resize(front_mask, new_size) front_mask = cv2.resize(front_mask, new_size)
result_front_image[front_mask != 0] = rgba_image[front_mask != 0] result_front_image[front_mask != 0] = rgba_image[front_mask != 0]
result_front_image_pil = Image.fromarray(cvtColor(result_front_image, COLOR_BGR2RGBA)) 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)
# 转换颜色空间为 RGBOpenCV 默认是 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) 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 height, width = front_mask.shape

View File

@@ -85,7 +85,7 @@ def seg_preprocess(img_path):
if ori_shape != (img_scale_w, img_scale_h): if ori_shape != (img_scale_w, img_scale_h):
# mmcv.imresize(img, img_scale_h, img_scale_w) # 老代码 引以为戒!哈哈哈~ h和w写反了 # mmcv.imresize(img, img_scale_h, img_scale_w) # 老代码 引以为戒!哈哈哈~ h和w写反了
img = cv2.resize(img, (img_scale_h, img_scale_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) preprocessed_img = np.expand_dims(img.transpose(2, 0, 1), axis=0)
return preprocessed_img, ori_shape return preprocessed_img, ori_shape

View File

@@ -33,8 +33,8 @@ def organize_clothing(layer):
mask=cv2.resize(layer['mask'], layer["front_image"].size), mask=cv2.resize(layer['mask'], layer["front_image"].size),
gradient_string=layer['gradient_string'] if 'gradient_string' in layer.keys() else "", gradient_string=layer['gradient_string'] if 'gradient_string' in layer.keys() else "",
pattern_image_url=layer['pattern_image_url'], 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), 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), mask=cv2.resize(layer['mask'], layer["front_image"].size),
gradient_string=layer['gradient_string'] if 'gradient_string' in layer.keys() else "", gradient_string=layer['gradient_string'] if 'gradient_string' in layer.keys() else "",
pattern_image_url=layer['pattern_image_url'], 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 return front_layer, back_layer

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

@@ -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

View File

@@ -6,6 +6,8 @@ from chromadb.config import Settings
from chromadb.utils.embedding_functions.ollama_embedding_function import OllamaEmbeddingFunction from chromadb.utils.embedding_functions.ollama_embedding_function import OllamaEmbeddingFunction
from tqdm import tqdm from tqdm import tqdm
from app.core.config import OLLAMA_URL
# 读取 csv 文件 # 读取 csv 文件
# csv_file_path = r'D:/Files/csv/output/output.csv' # csv_file_path = r'D:/Files/csv/output/output.csv'
# image_path = r'D:/images-clean' # 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="./service/search_image_with_text/vector_db"))
# client = chromadb.Client(Settings(is_persistent=True, persist_directory="D:/workspace/AiDLab/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(): # def create_collection():
@@ -66,7 +69,7 @@ embedding_fn = OllamaEmbeddingFunction(url="http://10.1.1.240:11434/api/embeddin
def query(gender, content): def query(gender, content):
collection = client.get_collection("sub_sketches_description", embedding_function=embedding_fn) collection = client.get_collection("sub_sketches_description", embedding_function=embedding_fn)
# 6. 查询相似内容 # 6. 查询相似内容
user_gender = gender # 用户输入的性别 user_gender = gender.lower() # 用户输入的性别
user_content = content # 用户输入的内容 user_content = content # 用户输入的内容
results = collection.query( results = collection.query(

View File

@@ -82,9 +82,10 @@ 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-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" # url = "aida-collection-element/12148/Sketchboard/95ea577b-305b-4a62-b30a-39c0dd3ddb3f.png"
read_type = "cv2" read_type = "2"
if read_type == "cv2": 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) 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) cv2.imshow("", img)

Binary file not shown.