4 Commits

Author SHA1 Message Date
9db2f96557 更新 .gitea/workflows/prod_build_manual.yaml 2026-04-24 10:20:13 +08:00
zcr
cc2404831d Merge branch 'develop' 2026-04-17 14:15:57 +08:00
zcr
6892361050 修复design印花部分 overall 模式印花平铺起始从印花图片中心开始
All checks were successful
git commit AiDA python develop 分支构建部署 / scheduled_deploy (push) Has been skipped
2026-04-15 17:36:29 +08:00
zcr
f0b73d5fc1 修复design印花部分 mask_inv_print 提取错误
All checks were successful
git commit AiDA python develop 分支构建部署 / scheduled_deploy (push) Has been skipped
2026-04-15 17:23:00 +08:00
3 changed files with 111 additions and 55 deletions

View File

@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
REMOTE_DEPLOY_PATH: /workspace/AiDA_Workspace/Python_Server_Workspace/Prod REMOTE_DEPLOY_PATH: /workspace/AiDA_Workspace/Python_Server_Workspace/AiDA_Prod
steps: steps:
- name: 1.检出代码 - name: 1.检出代码

View File

@@ -27,7 +27,7 @@ class NoSegPrintPainting:
# 获取平铺 + 旋转 的overall print # 获取平铺 + 旋转 的overall print
painting_dict = self.painting_collection(painting_dict, overall_print) painting_dict = self.painting_collection(painting_dict, overall_print)
result['no_seg_sketch_overall'] = result['no_seg_sketch_print'] = self.printpaint(result, painting_dict, print_=True) result['no_seg_sketch_overall'] = result['no_seg_sketch_print'] = self.printpaint(result, painting_dict, print_=True)
result['pattern_image'] = result['no_seg_sketch_overall'] # result['pattern_image'] = result['no_seg_sketch_overall']
if single_print: if single_print:
print_background = np.zeros((result['pattern_image'].shape[0], result['pattern_image'].shape[1], 3), dtype=np.uint8) print_background = np.zeros((result['pattern_image'].shape[0], result['pattern_image'].shape[1], 3), dtype=np.uint8)
@@ -166,7 +166,8 @@ class NoSegPrintPainting:
dim_max = max(painting_dict['dim_image_h'], painting_dict['dim_image_w']) dim_max = max(painting_dict['dim_image_h'], painting_dict['dim_image_w'])
dim_pattern = (int(dim_max * print_['scale'] / 5), int(dim_max * print_['scale'] / 5)) dim_pattern = (int(dim_max * print_['scale'] / 5), int(dim_max * print_['scale'] / 5))
gap = print_dict.get('gap', [[0, 0]])[0] gap = print_dict.get('gap', [[0, 0]])[0]
painting_dict['tile_print'] = tile_image(pattern=print_['image'], painting_dict['tile_print'], painting_dict['mask_inv_print'] = tile_image(pattern=print_['image'],
mask=print_['mask'],
dim=dim_pattern, dim=dim_pattern,
gap_x=gap[0], gap_x=gap[0],
gap_y=gap[1], gap_y=gap[1],
@@ -174,7 +175,8 @@ class NoSegPrintPainting:
canvas_w=painting_dict['dim_image_w'], canvas_w=painting_dict['dim_image_w'],
location=painting_dict['location'], location=painting_dict['location'],
angle=int(print_.get('print_angle_list', [0])[0])) angle=int(print_.get('print_angle_list', [0])[0]))
painting_dict['mask_inv_print'] = np.zeros(painting_dict['tile_print'].shape[:2], dtype=np.uint8) # painting_dict['mask_inv_print'] = np.zeros(painting_dict['tile_print'].shape[:2], dtype=np.uint8)
# painting_dict['mask_inv_print'] = self.get_mask_inv(painting_dict['tile_print'])
return painting_dict return painting_dict
def tile_image(self, pattern, dim, scale, dim_image_h, dim_image_w, location, trigger=False): def tile_image(self, pattern, dim, scale, dim_image_h, dim_image_w, location, trigger=False):
@@ -255,10 +257,15 @@ class NoSegPrintPainting:
image = oss_get_image(oss_client=self.minio_client, bucket=bucket_name, object_name=object_name, data_type="PIL") image = oss_get_image(oss_client=self.minio_client, bucket=bucket_name, object_name=object_name, data_type="PIL")
# 判断图片格式如果是RGBA 则贴在一张纯白图片上 防止透明转黑 # 判断图片格式如果是RGBA 则贴在一张纯白图片上 防止透明转黑
if image.mode == "RGBA": if image.mode == "RGBA":
mask_pil = image.split()[3]
new_background = Image.new('RGB', image.size, (255, 255, 255)) new_background = Image.new('RGB', image.size, (255, 255, 255))
new_background.paste(image, mask=image.split()[3]) new_background.paste(image, mask=image.split()[3])
image = new_background image = new_background
else:
mask_pil = Image.new('L', image.size, 255) # L=灰度图255=纯白
print_dict['image'] = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR) print_dict['image'] = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
print_dict['mask'] = cv2.threshold(np.array(mask_pil), 127, 255, cv2.THRESH_BINARY)[1]
return print_dict return print_dict
def crop_image(self, image, image_size_h, image_size_w, location, print_shape): def crop_image(self, image, image_size_h, image_size_w, location, print_shape):
@@ -408,9 +415,12 @@ class NoSegPrintPainting:
return cropped_img return cropped_img
def tile_image(pattern, dim, gap_x, gap_y, canvas_h, canvas_w, location, angle=0): def tile_image(pattern, mask, dim, gap_x, gap_y, canvas_h, canvas_w, location, angle=0):
""" """
按照指定的 X/Y 间距平铺印花,并支持旋转 按照指定的 X/Y 间距平铺印花,并支持旋转
【修改版】以被平铺图案的【中心】作为平铺基准点
:param location: [[center_y, center_x]] → 第一个图案中心的坐标
:param angle: 旋转角度 (度数, 逆时针) :param angle: 旋转角度 (度数, 逆时针)
""" """
# 1. 确保输入是 RGBA # 1. 确保输入是 RGBA
@@ -422,35 +432,54 @@ def tile_image(pattern, dim, gap_x, gap_y, canvas_h, canvas_w, location, angle=0
rotated_p = rotate_image(resized_p, angle) rotated_p = rotate_image(resized_p, angle)
p_h, p_w = rotated_p.shape[:2] p_h, p_w = rotated_p.shape[:2]
# 3. 创建透明单元格 # 3. 创建透明单元格(图案放在单元格中心)
cell_h, cell_w = p_h + gap_y, p_w + gap_x cell_h = p_h + gap_y
cell_w = p_w + gap_x
unit_cell = np.zeros((cell_h, cell_w, 4), dtype=np.uint8) unit_cell = np.zeros((cell_h, cell_w, 4), dtype=np.uint8)
unit_cell[:p_h, :p_w, :] = rotated_p
# 计算图案在单元格中的左上角位置(让图案居中)
start_y = (cell_h - p_h) // 2
start_x = (cell_w - p_w) // 2
unit_cell[start_y:start_y + p_h, start_x:start_x + p_w, :] = rotated_p
# 4. 执行平铺 # 4. 执行平铺
tiles_y = (canvas_h // cell_h) + 2 tiles_y = (canvas_h // cell_h) + 3 # 多加一点余量更安全
tiles_x = (canvas_w // cell_w) + 2 tiles_x = (canvas_w // cell_w) + 3
full_tiled = np.tile(unit_cell, (tiles_y, tiles_x, 1)) full_tiled = np.tile(unit_cell, (tiles_y, tiles_x, 1))
# 5. 裁剪平铺层 # 5. 计算偏移(关键修改:以中心为基准)
offset_x = int(location[0][1] % cell_w) center_y, center_x = location[0][0], location[0][1] # 第一个图案的中心位置
offset_y = int(location[0][0] % cell_h)
# 计算从哪个位置开始裁剪,才能让中心落在指定坐标
offset_y = int((center_y - (p_h // 2)) % cell_h)
offset_x = int((center_x - (p_w // 2)) % cell_w)
tiled_layer = full_tiled[offset_y: offset_y + canvas_h, tiled_layer = full_tiled[offset_y: offset_y + canvas_h,
offset_x: offset_x + canvas_w] offset_x: offset_x + canvas_w]
# 6. 创建纯白色背景并合成 # 6. 创建纯白色背景并合成(保持你原来的风格)
# 创建一个纯白色的 BGR 画布
white_background = np.full((canvas_h, canvas_w, 3), 255, dtype=np.uint8) white_background = np.full((canvas_h, canvas_w, 3), 255, dtype=np.uint8)
# 分离平铺层的颜色通道和 Alpha 通道
tiled_bgr = tiled_layer[:, :, :3] tiled_bgr = tiled_layer[:, :, :3]
alpha_mask = tiled_layer[:, :, 3] / 255.0 # 归一化到 0-1 alpha_mask = tiled_layer[:, :, 3] / 255.0
alpha_mask = cv2.merge([alpha_mask, alpha_mask, alpha_mask]) # 扩展到 3 通道 alpha_mask = cv2.merge([alpha_mask, alpha_mask, alpha_mask])
# 执行 Alpha 混合:结果 = 平铺层 * alpha + 背景 * (1 - alpha) tiled_print = (tiled_bgr * alpha_mask + white_background * (1 - alpha_mask)).astype(np.uint8)
result = (tiled_bgr * alpha_mask + white_background * (1 - alpha_mask)).astype(np.uint8)
return result # ====================== 处理 Mask ======================
# Mask 也同样居中处理
resized_mask = cv2.resize(mask, dim, interpolation=cv2.INTER_NEAREST)
rotated_mask = rotate_image(resized_mask, angle) # 注意mask也需要旋转
unit_mask = np.zeros((cell_h, cell_w), dtype=np.uint8)
unit_mask[start_y:start_y + p_h, start_x:start_x + p_w] = rotated_mask
full_mask_tiled = np.tile(unit_mask, (tiles_y, tiles_x))
tiled_mask = full_mask_tiled[offset_y: offset_y + canvas_h,
offset_x: offset_x + canvas_w]
return tiled_print, cv2.bitwise_not(tiled_mask)
def rotate_image(image, angle): def rotate_image(image, angle):

View File

@@ -41,7 +41,7 @@ class PrintPainting:
if overall_print['print_path_list']: if overall_print['print_path_list']:
overall_print['location'][0] = [x * y for x, y in zip(overall_print['location'][0], result['resize_scale'])] overall_print['location'][0] = [x * y for x, y in zip(overall_print['location'][0], result['resize_scale'])]
painting_dict = {'dim_image_h': result['pattern_image'].shape[0], 'dim_image_w': result['pattern_image'].shape[1]} painting_dict = {'dim_image_h': result['pattern_image'].shape[0], 'dim_image_w': result['pattern_image'].shape[1]}
result['print_image'] = result['pattern_image'] result['print_image'] = result['pattern_image'].copy()
# 获取平铺 + 旋转 的overall print # 获取平铺 + 旋转 的overall print
painting_dict = self.painting_collection(painting_dict, overall_print) painting_dict = self.painting_collection(painting_dict, overall_print)
result['print_image'] = self.printpaint(result, painting_dict, print_=True) result['print_image'] = self.printpaint(result, painting_dict, print_=True)
@@ -229,7 +229,8 @@ class PrintPainting:
dim_max = max(painting_dict['dim_image_h'], painting_dict['dim_image_w']) dim_max = max(painting_dict['dim_image_h'], painting_dict['dim_image_w'])
dim_pattern = (int(dim_max * print_['scale'] / 5), int(dim_max * print_['scale'] / 5)) dim_pattern = (int(dim_max * print_['scale'] / 5), int(dim_max * print_['scale'] / 5))
gap = print_dict.get('gap', [[0, 0]])[0] gap = print_dict.get('gap', [[0, 0]])[0]
painting_dict['tile_print'] = tile_image(pattern=print_['image'], painting_dict['tile_print'], painting_dict['mask_inv_print'] = tile_image(pattern=print_['image'],
mask=print_['mask'],
dim=dim_pattern, dim=dim_pattern,
gap_x=gap[0], gap_x=gap[0],
gap_y=gap[1], gap_y=gap[1],
@@ -237,7 +238,6 @@ class PrintPainting:
canvas_w=painting_dict['dim_image_w'], canvas_w=painting_dict['dim_image_w'],
location=painting_dict['location'], location=painting_dict['location'],
angle=int(print_.get('print_angle_list', [0])[0])) angle=int(print_.get('print_angle_list', [0])[0]))
painting_dict['mask_inv_print'] = np.zeros(painting_dict['tile_print'].shape[:2], dtype=np.uint8)
return painting_dict return painting_dict
def tile_image(self, pattern, dim, scale, dim_image_h, dim_image_w, location, trigger=False): def tile_image(self, pattern, dim, scale, dim_image_h, dim_image_w, location, trigger=False):
@@ -318,10 +318,15 @@ class PrintPainting:
image = oss_get_image(oss_client=self.minio_client, bucket=bucket_name, object_name=object_name, data_type="PIL") image = oss_get_image(oss_client=self.minio_client, bucket=bucket_name, object_name=object_name, data_type="PIL")
# 判断图片格式如果是RGBA 则贴在一张纯白图片上 防止透明转黑 # 判断图片格式如果是RGBA 则贴在一张纯白图片上 防止透明转黑
if image.mode == "RGBA": if image.mode == "RGBA":
mask_pil = image.split()[3]
new_background = Image.new('RGB', image.size, (255, 255, 255)) new_background = Image.new('RGB', image.size, (255, 255, 255))
new_background.paste(image, mask=image.split()[3]) new_background.paste(image, mask=image.split()[3])
image = new_background image = new_background
else:
mask_pil = Image.new('L', image.size, 255) # L=灰度图255=纯白
print_dict['image'] = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR) print_dict['image'] = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
print_dict['mask'] = cv2.threshold(np.array(mask_pil), 127, 255, cv2.THRESH_BINARY)[1]
return print_dict return print_dict
def crop_image(self, image, image_size_h, image_size_w, location, print_shape): def crop_image(self, image, image_size_h, image_size_w, location, print_shape):
@@ -471,9 +476,12 @@ class PrintPainting:
return cropped_img return cropped_img
def tile_image(pattern, dim, gap_x, gap_y, canvas_h, canvas_w, location, angle=0): def tile_image(pattern, mask, dim, gap_x, gap_y, canvas_h, canvas_w, location, angle=0):
""" """
按照指定的 X/Y 间距平铺印花,并支持旋转 按照指定的 X/Y 间距平铺印花,并支持旋转
【修改版】以被平铺图案的【中心】作为平铺基准点
:param location: [[center_y, center_x]] → 第一个图案中心的坐标
:param angle: 旋转角度 (度数, 逆时针) :param angle: 旋转角度 (度数, 逆时针)
""" """
# 1. 确保输入是 RGBA # 1. 确保输入是 RGBA
@@ -485,35 +493,54 @@ def tile_image(pattern, dim, gap_x, gap_y, canvas_h, canvas_w, location, angle=0
rotated_p = rotate_image(resized_p, angle) rotated_p = rotate_image(resized_p, angle)
p_h, p_w = rotated_p.shape[:2] p_h, p_w = rotated_p.shape[:2]
# 3. 创建透明单元格 # 3. 创建透明单元格(图案放在单元格中心)
cell_h, cell_w = p_h + gap_y, p_w + gap_x cell_h = p_h + gap_y
cell_w = p_w + gap_x
unit_cell = np.zeros((cell_h, cell_w, 4), dtype=np.uint8) unit_cell = np.zeros((cell_h, cell_w, 4), dtype=np.uint8)
unit_cell[:p_h, :p_w, :] = rotated_p
# 计算图案在单元格中的左上角位置(让图案居中)
start_y = (cell_h - p_h) // 2
start_x = (cell_w - p_w) // 2
unit_cell[start_y:start_y + p_h, start_x:start_x + p_w, :] = rotated_p
# 4. 执行平铺 # 4. 执行平铺
tiles_y = (canvas_h // cell_h) + 2 tiles_y = (canvas_h // cell_h) + 3 # 多加一点余量更安全
tiles_x = (canvas_w // cell_w) + 2 tiles_x = (canvas_w // cell_w) + 3
full_tiled = np.tile(unit_cell, (tiles_y, tiles_x, 1)) full_tiled = np.tile(unit_cell, (tiles_y, tiles_x, 1))
# 5. 裁剪平铺层 # 5. 计算偏移(关键修改:以中心为基准)
offset_x = int(location[0][1] % cell_w) center_y, center_x = location[0][0], location[0][1] # 第一个图案的中心位置
offset_y = int(location[0][0] % cell_h)
# 计算从哪个位置开始裁剪,才能让中心落在指定坐标
offset_y = int((center_y - (p_h // 2)) % cell_h)
offset_x = int((center_x - (p_w // 2)) % cell_w)
tiled_layer = full_tiled[offset_y: offset_y + canvas_h, tiled_layer = full_tiled[offset_y: offset_y + canvas_h,
offset_x: offset_x + canvas_w] offset_x: offset_x + canvas_w]
# 6. 创建纯白色背景并合成 # 6. 创建纯白色背景并合成(保持你原来的风格)
# 创建一个纯白色的 BGR 画布
white_background = np.full((canvas_h, canvas_w, 3), 255, dtype=np.uint8) white_background = np.full((canvas_h, canvas_w, 3), 255, dtype=np.uint8)
# 分离平铺层的颜色通道和 Alpha 通道
tiled_bgr = tiled_layer[:, :, :3] tiled_bgr = tiled_layer[:, :, :3]
alpha_mask = tiled_layer[:, :, 3] / 255.0 # 归一化到 0-1 alpha_mask = tiled_layer[:, :, 3] / 255.0
alpha_mask = cv2.merge([alpha_mask, alpha_mask, alpha_mask]) # 扩展到 3 通道 alpha_mask = cv2.merge([alpha_mask, alpha_mask, alpha_mask])
# 执行 Alpha 混合:结果 = 平铺层 * alpha + 背景 * (1 - alpha) tiled_print = (tiled_bgr * alpha_mask + white_background * (1 - alpha_mask)).astype(np.uint8)
result = (tiled_bgr * alpha_mask + white_background * (1 - alpha_mask)).astype(np.uint8)
return result # ====================== 处理 Mask ======================
# Mask 也同样居中处理
resized_mask = cv2.resize(mask, dim, interpolation=cv2.INTER_NEAREST)
rotated_mask = rotate_image(resized_mask, angle) # 注意mask也需要旋转
unit_mask = np.zeros((cell_h, cell_w), dtype=np.uint8)
unit_mask[start_y:start_y + p_h, start_x:start_x + p_w] = rotated_mask
full_mask_tiled = np.tile(unit_mask, (tiles_y, tiles_x))
tiled_mask = full_mask_tiled[offset_y: offset_y + canvas_h,
offset_x: offset_x + canvas_w]
return tiled_print, cv2.bitwise_not(tiled_mask)
def rotate_image(image, angle): def rotate_image(image, angle):