607 lines
33 KiB
Python
607 lines
33 KiB
Python
import logging
|
||
import random
|
||
|
||
import cv2
|
||
import numpy as np
|
||
from PIL import Image
|
||
|
||
from app.service.utils.oss_client import oss_get_image
|
||
from ..builder import PIPELINES
|
||
|
||
logger = logging.getLogger()
|
||
|
||
|
||
@PIPELINES.register_module()
|
||
class Painting(object):
|
||
def __init__(self, painting_flag=True):
|
||
self.painting_flag = painting_flag
|
||
|
||
# @ClassCallRunTime
|
||
def __call__(self, result):
|
||
if result['name'] not in ['hairstyle', 'earring'] and self.painting_flag and result['color'] != 'none':
|
||
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)
|
||
else:
|
||
pattern = self.get_pattern(result['color'])
|
||
resize_pattern = cv2.resize(pattern, (dim_image_w, dim_image_h), interpolation=cv2.INTER_AREA)
|
||
closed_mo = np.expand_dims(result['mask'], axis=2).repeat(3, axis=2)
|
||
gray_mo = np.expand_dims(result['gray'], axis=2).repeat(3, axis=2)
|
||
logger.info(f"image id is :{result['image_id']}")
|
||
get_image_fir = resize_pattern * (closed_mo / 255) * (gray_mo / 255)
|
||
result['pattern_image'] = get_image_fir.astype(np.uint8)
|
||
result['final_image'] = result['pattern_image']
|
||
canvas = np.full_like(result['final_image'], 255)
|
||
temp_bg = np.expand_dims(cv2.bitwise_not(result['mask']), axis=2).repeat(3, axis=2)
|
||
tmp1 = (canvas * (temp_bg / 255)).astype(np.uint8)
|
||
temp_fg = np.expand_dims(result['mask'], axis=2).repeat(3, axis=2)
|
||
tmp2 = (result['final_image'] * (temp_fg / 255)).astype(np.uint8)
|
||
result['single_image'] = cv2.add(tmp1, tmp2)
|
||
result['alpha'] = 100 / 255.0
|
||
else:
|
||
closed_mo = np.expand_dims(result['mask'], axis=2).repeat(3, axis=2)
|
||
get_image_fir = result['image'] * (closed_mo / 255)
|
||
result['pattern_image'] = get_image_fir.astype(np.uint8)
|
||
result['final_image'] = result['pattern_image']
|
||
return result
|
||
|
||
@staticmethod
|
||
def get_gradient(bucket_name, object_name):
|
||
# image_data = minio_client.get_object(bucket_name, object_name)
|
||
# image_data = s3.get_object(Bucket=bucket_name, Key=object_name)['Body']
|
||
|
||
# 从数据流中读取图像
|
||
# image_bytes = image_data.read()
|
||
|
||
# 将图像数据转换为numpy数组
|
||
# image_array = np.asarray(bytearray(image_bytes), dtype=np.uint8)
|
||
|
||
# 使用OpenCV解码图像数组
|
||
# image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
|
||
image = oss_get_image(bucket=bucket_name, object_name=object_name, data_type="cv2")
|
||
if image.shape[2] == 4:
|
||
image = cv2.cvtColor(image, cv2.COLOR_BGRA2BGR)
|
||
return image
|
||
|
||
@staticmethod
|
||
def crop_image(image, image_size_h, image_size_w):
|
||
x_offset = np.random.randint(low=0, high=int(image_size_h / 5) - 6)
|
||
y_offset = np.random.randint(low=0, high=int(image_size_w / 5) - 6)
|
||
image = image[x_offset: x_offset + image_size_h, y_offset: y_offset + image_size_w, :]
|
||
return image
|
||
|
||
@staticmethod
|
||
def get_pattern(single_color):
|
||
if single_color is None:
|
||
raise False
|
||
R, G, B = single_color.split(' ')
|
||
pattern = np.zeros([1, 1, 3], np.uint8)
|
||
pattern[0, 0, 0] = int(B)
|
||
pattern[0, 0, 1] = int(G)
|
||
pattern[0, 0, 2] = int(R)
|
||
return pattern
|
||
|
||
|
||
@PIPELINES.register_module()
|
||
class PrintPainting(object):
|
||
def __init__(self, print_flag=True):
|
||
self.print_flag = print_flag
|
||
|
||
# @ClassCallRunTime
|
||
def __call__(self, result):
|
||
single_print = result['print']['single']
|
||
overall_print = result['print']['overall']
|
||
element_print = result['print']['element']
|
||
result['single_image'] = None
|
||
result['print_image'] = None
|
||
if overall_print['print_path_list']:
|
||
painting_dict = {'dim_image_h': result['pattern_image'].shape[0], 'dim_image_w': result['pattern_image'].shape[1]}
|
||
result['print_image'] = result['pattern_image']
|
||
if "print_angle_list" in overall_print.keys() and overall_print['print_angle_list'][0] != 0:
|
||
painting_dict = self.painting_collection(painting_dict, overall_print, print_trigger=True)
|
||
painting_dict['tile_print'] = self.rotate_crop_image(img=painting_dict['tile_print'], angle=-overall_print['print_angle_list'][0], crop=True)
|
||
painting_dict['mask_inv_print'] = self.rotate_crop_image(img=painting_dict['mask_inv_print'], angle=-overall_print['print_angle_list'][0], crop=True)
|
||
|
||
# resize 到sketch大小
|
||
painting_dict['tile_print'] = self.resize_and_crop(img=painting_dict['tile_print'], target_width=painting_dict['dim_image_w'], target_height=painting_dict['dim_image_h'])
|
||
painting_dict['mask_inv_print'] = self.resize_and_crop(img=painting_dict['mask_inv_print'], target_width=painting_dict['dim_image_w'], target_height=painting_dict['dim_image_h'])
|
||
else:
|
||
painting_dict = self.painting_collection(painting_dict, overall_print, print_trigger=True, is_single=False)
|
||
result['print_image'] = self.printpaint(result, painting_dict, print_=True)
|
||
result['single_image'] = result['final_image'] = result['pattern_image'] = result['print_image']
|
||
|
||
if single_print['print_path_list']:
|
||
print_background = np.zeros((result['pattern_image'].shape[0], result['pattern_image'].shape[1], 3), dtype=np.uint8)
|
||
mask_background = np.zeros((result['pattern_image'].shape[0], result['pattern_image'].shape[1], 3), dtype=np.uint8)
|
||
for i in range(len(single_print['print_path_list'])):
|
||
image, image_mode = self.read_image(single_print['print_path_list'][i])
|
||
if image_mode == "RGBA":
|
||
new_size = (int(image.width * single_print['print_scale_list'][i]), int(image.height * single_print['print_scale_list'][i]))
|
||
|
||
mask = image.split()[3]
|
||
resized_source = image.resize(new_size)
|
||
resized_source_mask = mask.resize(new_size)
|
||
|
||
rotated_resized_source = resized_source.rotate(-single_print['print_angle_list'][i])
|
||
rotated_resized_source_mask = resized_source_mask.rotate(-single_print['print_angle_list'][i])
|
||
|
||
source_image_pil = Image.fromarray(cv2.cvtColor(print_background, cv2.COLOR_BGR2RGB))
|
||
source_image_pil_mask = Image.fromarray(cv2.cvtColor(mask_background, cv2.COLOR_BGR2RGB))
|
||
|
||
source_image_pil.paste(rotated_resized_source, (int(single_print['location'][i][0]), int(single_print['location'][i][1])), rotated_resized_source)
|
||
source_image_pil_mask.paste(rotated_resized_source_mask, (int(single_print['location'][i][0]), int(single_print['location'][i][1])), rotated_resized_source_mask)
|
||
|
||
print_background = cv2.cvtColor(np.array(source_image_pil), cv2.COLOR_RGBA2BGR)
|
||
mask_background = cv2.cvtColor(np.array(source_image_pil_mask), cv2.COLOR_RGBA2BGR)
|
||
ret, mask_background = cv2.threshold(mask_background, 124, 255, cv2.THRESH_BINARY)
|
||
else:
|
||
mask = self.get_mask_inv(image)
|
||
mask = np.expand_dims(mask, axis=2)
|
||
mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
|
||
mask = cv2.bitwise_not(mask)
|
||
# 旋转后的坐标需要重新算
|
||
rotate_mask, _ = self.img_rotate(mask, single_print['print_angle_list'][i], single_print['print_scale_list'][i])
|
||
rotate_image, rotated_new_size = self.img_rotate(image, single_print['print_angle_list'][i], single_print['print_scale_list'][i])
|
||
# x, y = int(result['print']['location'][i][0] - rotated_new_size[0] - (rotate_mask.shape[0] - image.shape[0]) / 2), int(result['print']['location'][i][1] - rotated_new_size[1] - (rotate_mask.shape[1] - image.shape[1]) / 2)
|
||
x, y = int(single_print['location'][i][0] - rotated_new_size[0]), int(single_print['location'][i][1] - rotated_new_size[1])
|
||
|
||
image_x = print_background.shape[1]
|
||
image_y = print_background.shape[0]
|
||
print_x = rotate_image.shape[1]
|
||
print_y = rotate_image.shape[0]
|
||
|
||
# 有bug
|
||
# if x + print_x > image_x:
|
||
# rotate_image = rotate_image[:, :x + print_x - image_x]
|
||
# rotate_mask = rotate_mask[:, :x + print_x - image_x]
|
||
# #
|
||
# if y + print_y > image_y:
|
||
# rotate_image = rotate_image[:y + print_y - image_y]
|
||
# rotate_mask = rotate_mask[:y + print_y - image_y]
|
||
|
||
# 不能是并行
|
||
# 当前第一轮的if (108以及115)是判断有没有过下界和右界。第二轮的是判断左上有没有超出。 如果这个样子的话,先裁了右边,再左移,region就会有问题
|
||
# 先挪 再判断 最后裁剪
|
||
|
||
# 如果print旋转了 或者 print贴边了 则需要判断 判断左界和上界是否小于0
|
||
if x <= 0:
|
||
rotate_image = rotate_image[:, -x:]
|
||
rotate_mask = rotate_mask[:, -x:]
|
||
start_x = x = 0
|
||
else:
|
||
start_x = x
|
||
|
||
if y <= 0:
|
||
rotate_image = rotate_image[-y:, :]
|
||
rotate_mask = rotate_mask[-y:, :]
|
||
start_y = y = 0
|
||
else:
|
||
start_y = y
|
||
|
||
# ------------------
|
||
# 如果print-size大于image-size 则需要裁剪print
|
||
|
||
if x + print_x > image_x:
|
||
rotate_image = rotate_image[:, :image_x - x]
|
||
rotate_mask = rotate_mask[:, :image_x - x]
|
||
|
||
if y + print_y > image_y:
|
||
rotate_image = rotate_image[:image_y - y, :]
|
||
rotate_mask = rotate_mask[:image_y - y, :]
|
||
|
||
# mask_background[start_y:y + rotate_mask.shape[0], start_x:x + rotate_mask.shape[1]] = cv2.bitwise_xor(mask_background[start_y:y + rotate_mask.shape[0], start_x:x + rotate_mask.shape[1]], rotate_mask)
|
||
# print_background[start_y:y + rotate_image.shape[0], start_x:x + rotate_image.shape[1]] = cv2.add(print_background[start_y:y + rotate_image.shape[0], start_x:x + rotate_image.shape[1]], rotate_image)
|
||
|
||
# mask_background[start_y:y + rotate_mask.shape[0], start_x:x + rotate_mask.shape[1]] = rotate_mask
|
||
# print_background[start_y:y + rotate_image.shape[0], start_x:x + rotate_image.shape[1]] = rotate_image
|
||
mask_background = self.stack_prin(mask_background, result['pattern_image'], rotate_mask, start_y, y, start_x, x)
|
||
print_background = self.stack_prin(print_background, result['pattern_image'], rotate_image, start_y, y, start_x, x)
|
||
|
||
# gray_image = cv2.cvtColor(mask_background, cv2.COLOR_BGR2GRAY)
|
||
# print_background = cv2.bitwise_and(print_background, print_background, mask=gray_image)
|
||
|
||
print_mask = cv2.bitwise_and(result['mask'], cv2.cvtColor(mask_background, cv2.COLOR_BGR2GRAY))
|
||
img_fg = cv2.bitwise_or(print_background, print_background, mask=print_mask)
|
||
img_bg = cv2.bitwise_and(result['pattern_image'], result['pattern_image'], mask=cv2.bitwise_not(print_mask))
|
||
mask_mo = np.expand_dims(print_mask, axis=2).repeat(3, axis=2)
|
||
gray_mo = np.expand_dims(result['gray'], axis=2).repeat(3, axis=2)
|
||
img_fg = (img_fg * (mask_mo / 255) * (gray_mo / 255)).astype(np.uint8)
|
||
result['final_image'] = cv2.add(img_bg, img_fg)
|
||
canvas = np.full_like(result['final_image'], 255)
|
||
temp_bg = np.expand_dims(cv2.bitwise_not(result['mask']), axis=2).repeat(3, axis=2)
|
||
tmp1 = (canvas * (temp_bg / 255)).astype(np.uint8)
|
||
temp_fg = np.expand_dims(result['mask'], axis=2).repeat(3, axis=2)
|
||
tmp2 = (result['final_image'] * (temp_fg / 255)).astype(np.uint8)
|
||
result['single_image'] = cv2.add(tmp1, tmp2)
|
||
|
||
if element_print['element_path_list']:
|
||
print_background = np.zeros((result['final_image'].shape[0], result['final_image'].shape[1], 3), dtype=np.uint8)
|
||
mask_background = np.zeros((result['final_image'].shape[0], result['final_image'].shape[1], 3), dtype=np.uint8)
|
||
for i in range(len(element_print['element_path_list'])):
|
||
image, image_mode = self.read_image(element_print['element_path_list'][i])
|
||
if image_mode == "RGBA":
|
||
new_size = (int(image.width * element_print['element_scale_list'][i]), int(image.height * element_print['element_scale_list'][i]))
|
||
|
||
mask = image.split()[3]
|
||
resized_source = image.resize(new_size)
|
||
resized_source_mask = mask.resize(new_size)
|
||
|
||
rotated_resized_source = resized_source.rotate(-element_print['element_angle_list'][i])
|
||
rotated_resized_source_mask = resized_source_mask.rotate(-element_print['element_angle_list'][i])
|
||
|
||
source_image_pil = Image.fromarray(cv2.cvtColor(print_background, cv2.COLOR_BGR2RGB))
|
||
source_image_pil_mask = Image.fromarray(cv2.cvtColor(mask_background, cv2.COLOR_BGR2RGB))
|
||
|
||
source_image_pil.paste(rotated_resized_source, (int(element_print['location'][i][0]), int(element_print['location'][i][1])), rotated_resized_source)
|
||
source_image_pil_mask.paste(rotated_resized_source_mask, (int(element_print['location'][i][0]), int(element_print['location'][i][1])), rotated_resized_source_mask)
|
||
|
||
print_background = cv2.cvtColor(np.array(source_image_pil), cv2.COLOR_RGBA2BGR)
|
||
mask_background = cv2.cvtColor(np.array(source_image_pil_mask), cv2.COLOR_RGBA2BGR)
|
||
else:
|
||
mask = self.get_mask_inv(image)
|
||
mask = np.expand_dims(mask, axis=2)
|
||
mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
|
||
mask = cv2.bitwise_not(mask)
|
||
# 旋转后的坐标需要重新算
|
||
rotate_mask, _ = self.img_rotate(mask, element_print['element_angle_list'][i], element_print['element_scale_list'][i])
|
||
rotate_image, rotated_new_size = self.img_rotate(image, element_print['element_angle_list'][i], element_print['element_scale_list'][i])
|
||
# x, y = int(result['print']['location'][i][0] - rotated_new_size[0] - (rotate_mask.shape[0] - image.shape[0]) / 2), int(result['print']['location'][i][1] - rotated_new_size[1] - (rotate_mask.shape[1] - image.shape[1]) / 2)
|
||
x, y = int(element_print['location'][i][0] - rotated_new_size[0]), int(element_print['location'][i][1] - rotated_new_size[1])
|
||
|
||
image_x = print_background.shape[1]
|
||
image_y = print_background.shape[0]
|
||
print_x = rotate_image.shape[1]
|
||
print_y = rotate_image.shape[0]
|
||
|
||
# 有bug
|
||
# if x + print_x > image_x:
|
||
# rotate_image = rotate_image[:, :x + print_x - image_x]
|
||
# rotate_mask = rotate_mask[:, :x + print_x - image_x]
|
||
# #
|
||
# if y + print_y > image_y:
|
||
# rotate_image = rotate_image[:y + print_y - image_y]
|
||
# rotate_mask = rotate_mask[:y + print_y - image_y]
|
||
|
||
# 不能是并行
|
||
# 当前第一轮的if (108以及115)是判断有没有过下界和右界。第二轮的是判断左上有没有超出。 如果这个样子的话,先裁了右边,再左移,region就会有问题
|
||
# 先挪 再判断 最后裁剪
|
||
|
||
# 如果print旋转了 或者 print贴边了 则需要判断 判断左界和上界是否小于0
|
||
if x <= 0:
|
||
rotate_image = rotate_image[:, -x:]
|
||
rotate_mask = rotate_mask[:, -x:]
|
||
start_x = x = 0
|
||
else:
|
||
start_x = x
|
||
|
||
if y <= 0:
|
||
rotate_image = rotate_image[-y:, :]
|
||
rotate_mask = rotate_mask[-y:, :]
|
||
start_y = y = 0
|
||
else:
|
||
start_y = y
|
||
|
||
# ------------------
|
||
# 如果print-size大于image-size 则需要裁剪print
|
||
|
||
if x + print_x > image_x:
|
||
rotate_image = rotate_image[:, :image_x - x]
|
||
rotate_mask = rotate_mask[:, :image_x - x]
|
||
|
||
if y + print_y > image_y:
|
||
rotate_image = rotate_image[:image_y - y, :]
|
||
rotate_mask = rotate_mask[:image_y - y, :]
|
||
|
||
# mask_background[start_y:y + rotate_mask.shape[0], start_x:x + rotate_mask.shape[1]] = cv2.bitwise_xor(mask_background[start_y:y + rotate_mask.shape[0], start_x:x + rotate_mask.shape[1]], rotate_mask)
|
||
# print_background[start_y:y + rotate_image.shape[0], start_x:x + rotate_image.shape[1]] = cv2.add(print_background[start_y:y + rotate_image.shape[0], start_x:x + rotate_image.shape[1]], rotate_image)
|
||
|
||
# mask_background[start_y:y + rotate_mask.shape[0], start_x:x + rotate_mask.shape[1]] = rotate_mask
|
||
# print_background[start_y:y + rotate_image.shape[0], start_x:x + rotate_image.shape[1]] = rotate_image
|
||
mask_background = self.stack_prin(mask_background, result['pattern_image'], rotate_mask, start_y, y, start_x, x)
|
||
print_background = self.stack_prin(print_background, result['pattern_image'], rotate_image, start_y, y, start_x, x)
|
||
|
||
# gray_image = cv2.cvtColor(mask_background, cv2.COLOR_BGR2GRAY)
|
||
# print_background = cv2.bitwise_and(print_background, print_background, mask=gray_image)
|
||
|
||
print_mask = cv2.bitwise_and(result['mask'], cv2.cvtColor(mask_background, cv2.COLOR_BGR2GRAY))
|
||
img_fg = cv2.bitwise_or(print_background, print_background, mask=print_mask)
|
||
# TODO element 丢失信息
|
||
three_channel_image = cv2.merge([cv2.bitwise_not(print_mask), cv2.bitwise_not(print_mask), cv2.bitwise_not(print_mask)])
|
||
img_bg = cv2.bitwise_and(result['final_image'], three_channel_image)
|
||
# mask_mo = np.expand_dims(print_mask, axis=2).repeat(3, axis=2)
|
||
# gray_mo = np.expand_dims(result['gray'], axis=2).repeat(3, axis=2)
|
||
# img_fg = (img_fg * (mask_mo / 255) * (gray_mo / 255)).astype(np.uint8)
|
||
result['final_image'] = cv2.add(img_bg, img_fg)
|
||
canvas = np.full_like(result['final_image'], 255)
|
||
temp_bg = np.expand_dims(cv2.bitwise_not(result['mask']), axis=2).repeat(3, axis=2)
|
||
tmp1 = (canvas * (temp_bg / 255)).astype(np.uint8)
|
||
temp_fg = np.expand_dims(result['mask'], axis=2).repeat(3, axis=2)
|
||
tmp2 = (result['final_image'] * (temp_fg / 255)).astype(np.uint8)
|
||
result['single_image'] = cv2.add(tmp1, tmp2)
|
||
return result
|
||
|
||
@staticmethod
|
||
def stack_prin(print_background, pattern_image, rotate_image, start_y, y, start_x, x):
|
||
temp_print = np.zeros((pattern_image.shape[0], pattern_image.shape[1], 3), dtype=np.uint8)
|
||
temp_print[start_y:y + rotate_image.shape[0], start_x:x + rotate_image.shape[1]] = rotate_image
|
||
img2gray = cv2.cvtColor(temp_print, cv2.COLOR_BGR2GRAY)
|
||
ret, mask_ = cv2.threshold(img2gray, 1, 255, cv2.THRESH_BINARY)
|
||
mask_inv = cv2.bitwise_not(mask_)
|
||
img1_bg = cv2.bitwise_and(print_background, print_background, mask=mask_inv)
|
||
img2_fg = cv2.bitwise_and(temp_print, temp_print, mask=mask_)
|
||
print_background = img1_bg + img2_fg
|
||
return print_background
|
||
|
||
def painting_collection(self, painting_dict, print_dict, print_trigger=False, is_single=False):
|
||
if print_trigger:
|
||
print_ = self.get_print(print_dict)
|
||
painting_dict['Trigger'] = not is_single
|
||
painting_dict['location'] = print_['location']
|
||
single_mask_inv_print = self.get_mask_inv(print_['image'])
|
||
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))
|
||
if not is_single:
|
||
self.random_seed = random.randint(0, 1000)
|
||
# 如果print 模式为overall 且 有角度的话 , 组合的print为正方形,方便裁剪
|
||
if "print_angle_list" in print_dict.keys() and print_dict['print_angle_list'][0] != 0:
|
||
painting_dict['mask_inv_print'] = self.tile_image(single_mask_inv_print, dim_pattern, print_['scale'], dim_max, dim_max, painting_dict['location'], trigger=True)
|
||
painting_dict['tile_print'] = self.tile_image(print_['image'], dim_pattern, print_['scale'], dim_max, dim_max, painting_dict['location'], trigger=True)
|
||
else:
|
||
painting_dict['mask_inv_print'] = self.tile_image(single_mask_inv_print, dim_pattern, print_['scale'], painting_dict['dim_image_h'], painting_dict['dim_image_w'], painting_dict['location'], trigger=True)
|
||
painting_dict['tile_print'] = self.tile_image(print_['image'], dim_pattern, print_['scale'], painting_dict['dim_image_h'], painting_dict['dim_image_w'], painting_dict['location'], trigger=True)
|
||
else:
|
||
painting_dict['mask_inv_print'] = self.tile_image(single_mask_inv_print, dim_pattern, print_['scale'], painting_dict['dim_image_h'], painting_dict['dim_image_w'], painting_dict['location'])
|
||
painting_dict['tile_print'] = self.tile_image(print_['image'], dim_pattern, print_['scale'], painting_dict['dim_image_h'], painting_dict['dim_image_w'], painting_dict['location'])
|
||
painting_dict['dim_print_h'], painting_dict['dim_print_w'] = dim_pattern
|
||
return painting_dict
|
||
|
||
def tile_image(self, pattern, dim, scale, dim_image_h, dim_image_w, location, trigger=False):
|
||
tile = None
|
||
if not trigger:
|
||
tile = cv2.resize(pattern, dim, interpolation=cv2.INTER_AREA)
|
||
else:
|
||
resize_pattern = cv2.resize(pattern, dim, interpolation=cv2.INTER_AREA)
|
||
if len(pattern.shape) == 2:
|
||
tile = np.tile(resize_pattern, (int((5 + 1) / scale) + 4, int((5 + 1) / scale) + 4))
|
||
if len(pattern.shape) == 3:
|
||
tile = np.tile(resize_pattern, (int((5 + 1) / scale) + 4, int((5 + 1) / scale) + 4, 1))
|
||
tile = self.crop_image(tile, dim_image_h, dim_image_w, location, resize_pattern.shape)
|
||
return tile
|
||
|
||
def get_mask_inv(self, print_):
|
||
if print_[0][0][0] == 255 and print_[0][0][1] == 255 and print_[0][0][2] == 255:
|
||
bg_color = cv2.cvtColor(print_, cv2.COLOR_BGR2LAB)[0][0]
|
||
print_tile = cv2.cvtColor(print_, cv2.COLOR_BGR2LAB)
|
||
bg_l, bg_a, bg_b = bg_color[0], bg_color[1], bg_color[2]
|
||
bg_L_high, bg_L_low = self.get_low_high_lab(bg_l, L=True)
|
||
bg_a_high, bg_a_low = self.get_low_high_lab(bg_a)
|
||
bg_b_high, bg_b_low = self.get_low_high_lab(bg_b)
|
||
lower = np.array([bg_L_low, bg_a_low, bg_b_low])
|
||
upper = np.array([bg_L_high, bg_a_high, bg_b_high])
|
||
mask_inv = cv2.inRange(print_tile, lower, upper)
|
||
return mask_inv
|
||
else:
|
||
# bg_color = cv2.cvtColor(print_, cv2.COLOR_BGR2LAB)[0][0]
|
||
# print_tile = cv2.cvtColor(print_, cv2.COLOR_BGR2LAB)
|
||
# bg_l, bg_a, bg_b = bg_color[0], bg_color[1], bg_color[2]
|
||
# bg_L_high, bg_L_low = self.get_low_high_lab(bg_l, L=True)
|
||
# bg_a_high, bg_a_low = self.get_low_high_lab(bg_a)
|
||
# bg_b_high, bg_b_low = self.get_low_high_lab(bg_b)
|
||
# lower = np.array([bg_L_low, bg_a_low, bg_b_low])
|
||
# upper = np.array([bg_L_high, bg_a_high, bg_b_high])
|
||
|
||
# print_tile = cv2.cvtColor(print_, cv2.COLOR_BGR2LAB)
|
||
# mask_inv = cv2.cvtColor(print_tile, cv2.COLOR_BGR2GRAY)
|
||
|
||
# mask_inv = cv2.cvtColor(print_, cv2.COLOR_BGR2GRAY)
|
||
mask_inv = np.zeros(print_.shape[:2], dtype=np.uint8)
|
||
return mask_inv
|
||
|
||
@staticmethod
|
||
def printpaint(result, painting_dict, print_=False):
|
||
|
||
if print_ and painting_dict['Trigger']:
|
||
print_mask = cv2.bitwise_and(result['mask'], cv2.bitwise_not(painting_dict['mask_inv_print']))
|
||
img_fg = cv2.bitwise_and(painting_dict['tile_print'], painting_dict['tile_print'], mask=print_mask)
|
||
else:
|
||
print_mask = result['mask']
|
||
img_fg = result['final_image']
|
||
if print_ and not painting_dict['Trigger']:
|
||
index_ = None
|
||
try:
|
||
index_ = len(painting_dict['location'])
|
||
except:
|
||
assert f'there must be parameter of location if choose IfSingle'
|
||
|
||
for i in range(index_):
|
||
start_h, start_w = int(painting_dict['location'][i][1]), int(painting_dict['location'][i][0])
|
||
|
||
length_h = min(start_h + painting_dict['dim_print_h'], img_fg.shape[0])
|
||
length_w = min(start_w + painting_dict['dim_print_w'], img_fg.shape[1])
|
||
|
||
change_region = img_fg[start_h: length_h, start_w: length_w, :]
|
||
# problem in change_mask
|
||
change_mask = print_mask[start_h: length_h, start_w: length_w]
|
||
# get real part into change mask
|
||
_, change_mask = cv2.threshold(change_mask, 220, 255, cv2.THRESH_BINARY)
|
||
mask = cv2.bitwise_not(painting_dict['mask_inv_print'])
|
||
img_fg[start_h:start_h + painting_dict['dim_print_h'], start_w:start_w + painting_dict['dim_print_w'], :] = change_region
|
||
|
||
clothes_mask_print = cv2.bitwise_not(print_mask)
|
||
|
||
img_bg = cv2.bitwise_and(result['pattern_image'], result['pattern_image'], mask=clothes_mask_print)
|
||
mask_mo = np.expand_dims(print_mask, axis=2).repeat(3, axis=2)
|
||
gray_mo = np.expand_dims(result['gray'], axis=2).repeat(3, axis=2)
|
||
img_fg = (img_fg * (mask_mo / 255) * (gray_mo / 255)).astype(np.uint8)
|
||
print_image = cv2.add(img_bg, img_fg)
|
||
return print_image
|
||
|
||
@staticmethod
|
||
def get_print(print_dict):
|
||
if 'print_scale_list' not in print_dict.keys() or print_dict['print_scale_list'][0] < 0.3:
|
||
print_dict['scale'] = 0.3
|
||
else:
|
||
print_dict['scale'] = print_dict['print_scale_list'][0]
|
||
|
||
bucket_name = print_dict['print_path_list'][0].split("/", 1)[0]
|
||
object_name = print_dict['print_path_list'][0].split("/", 1)[1]
|
||
image = oss_get_image(bucket=bucket_name, object_name=object_name, data_type="PIL")
|
||
# 判断图片格式,如果是RGBA 则贴在一张纯白图片上 防止透明转黑
|
||
if image.mode == "RGBA":
|
||
new_background = Image.new('RGB', image.size, (255, 255, 255))
|
||
new_background.paste(image, mask=image.split()[3])
|
||
image = new_background
|
||
print_dict['image'] = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
|
||
return print_dict
|
||
|
||
def crop_image(self, image, image_size_h, image_size_w, location, print_shape):
|
||
print_w = print_shape[1]
|
||
print_h = print_shape[0]
|
||
|
||
random.seed(self.random_seed)
|
||
# logging.info(f'overall print location : {location}')
|
||
# x_offset = random.randint(0, image.shape[0] - image_size_h)
|
||
# y_offset = random.randint(0, image.shape[1] - image_size_w)
|
||
|
||
# 1.拿到偏移量后和resize后的print宽高取余 得到真正偏移量
|
||
x_offset = print_w - int(location[0][1] % print_w)
|
||
y_offset = print_w - int(location[0][0] % print_h)
|
||
|
||
# y_offset = int(location[0][0])
|
||
# x_offset = int(location[0][1])
|
||
|
||
if len(image.shape) == 2:
|
||
image = image[x_offset: x_offset + image_size_h, y_offset: y_offset + image_size_w]
|
||
elif len(image.shape) == 3:
|
||
image = image[x_offset: x_offset + image_size_h, y_offset: y_offset + image_size_w, :]
|
||
return image
|
||
|
||
@staticmethod
|
||
def get_low_high_lab(Lab_value, L=False):
|
||
if L:
|
||
high = Lab_value + 30 if Lab_value + 30 < 255 else 255
|
||
low = Lab_value - 30 if Lab_value - 30 > 0 else 0
|
||
else:
|
||
high = Lab_value + 30 if Lab_value + 30 < 255 else 255
|
||
low = Lab_value - 30 if Lab_value - 30 > 0 else 0
|
||
return high, low
|
||
|
||
@staticmethod
|
||
def img_rotate(image, angel, scale):
|
||
"""顺时针旋转图像任意角度
|
||
|
||
Args:
|
||
image (np.array): [原始图像]
|
||
angel (float): [逆时针旋转的角度]
|
||
|
||
Returns:
|
||
[array]: [旋转后的图像]
|
||
"""
|
||
|
||
h, w = image.shape[:2]
|
||
center = (w // 2, h // 2)
|
||
# if type(angel) is not int:
|
||
# angel = 0
|
||
M = cv2.getRotationMatrix2D(center, -angel, scale)
|
||
# 调整旋转后的图像长宽
|
||
rotated_h = int((w * np.abs(M[0, 1]) + (h * np.abs(M[0, 0]))))
|
||
rotated_w = int((h * np.abs(M[0, 1]) + (w * np.abs(M[0, 0]))))
|
||
M[0, 2] += (rotated_w - w) // 2
|
||
M[1, 2] += (rotated_h - h) // 2
|
||
# 旋转图像
|
||
rotated_img = cv2.warpAffine(image, M, (rotated_w, rotated_h))
|
||
|
||
return rotated_img, ((rotated_img.shape[1] - image.shape[1] * scale) // 2, (rotated_img.shape[0] - image.shape[0] * scale) // 2)
|
||
# return rotated_img, (0, 0)
|
||
|
||
@staticmethod
|
||
def rotate_crop_image(img, angle, crop):
|
||
"""
|
||
angle: 旋转的角度
|
||
crop: 是否需要进行裁剪,布尔向量
|
||
"""
|
||
crop_image = lambda img, x0, y0, w, h: img[y0:y0 + h, x0:x0 + w]
|
||
w, h = img.shape[:2]
|
||
# 旋转角度的周期是360°
|
||
angle %= 360
|
||
# 计算仿射变换矩阵
|
||
M_rotation = cv2.getRotationMatrix2D((w / 2, h / 2), angle, 1)
|
||
# 得到旋转后的图像
|
||
img_rotated = cv2.warpAffine(img, M_rotation, (w, h))
|
||
|
||
# 如果需要去除黑边
|
||
if crop:
|
||
# 裁剪角度的等效周期是180°
|
||
angle_crop = angle % 180
|
||
if angle > 90:
|
||
angle_crop = 180 - angle_crop
|
||
# 转化角度为弧度
|
||
theta = angle_crop * np.pi / 180
|
||
# 计算高宽比
|
||
hw_ratio = float(h) / float(w)
|
||
# 计算裁剪边长系数的分子项
|
||
tan_theta = np.tan(theta)
|
||
numerator = np.cos(theta) + np.sin(theta) * np.tan(theta)
|
||
|
||
# 计算分母中和高宽比相关的项
|
||
r = hw_ratio if h > w else 1 / hw_ratio
|
||
# 计算分母项
|
||
denominator = r * tan_theta + 1
|
||
# 最终的边长系数
|
||
crop_mult = numerator / denominator
|
||
|
||
# 得到裁剪区域
|
||
w_crop = int(crop_mult * w)
|
||
h_crop = int(crop_mult * h)
|
||
x0 = int((w - w_crop) / 2)
|
||
y0 = int((h - h_crop) / 2)
|
||
|
||
img_rotated = crop_image(img_rotated, x0, y0, w_crop, h_crop)
|
||
|
||
return img_rotated
|
||
|
||
@staticmethod
|
||
def read_image(image_url):
|
||
image = oss_get_image(bucket=image_url.split("/", 1)[0], object_name=image_url.split("/", 1)[1], data_type="cv2")
|
||
if image.shape[2] == 4:
|
||
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA)
|
||
image = Image.fromarray(image_rgb)
|
||
image_mode = "RGBA"
|
||
else:
|
||
image_mode = "RGB"
|
||
return image, image_mode
|
||
|
||
@staticmethod
|
||
def resize_and_crop(img, target_width, target_height):
|
||
# 获取原始图像的尺寸
|
||
original_height, original_width = img.shape[:2]
|
||
|
||
# 计算目标尺寸的宽高比
|
||
target_ratio = target_width / target_height
|
||
|
||
# 计算原始图像的宽高比
|
||
original_ratio = original_width / original_height
|
||
|
||
# 调整尺寸
|
||
if original_ratio > target_ratio:
|
||
# 原始图像更宽,按高度resize,然后裁剪宽度
|
||
new_height = target_height
|
||
new_width = int(original_width * (target_height / original_height))
|
||
resized_img = cv2.resize(img, (new_width, new_height))
|
||
# 裁剪宽度
|
||
start_x = (new_width - target_width) // 2
|
||
cropped_img = resized_img[:, start_x:start_x + target_width]
|
||
else:
|
||
# 原始图像更高,按宽度resize,然后裁剪高度
|
||
new_width = target_width
|
||
new_height = int(original_height * (target_width / original_width))
|
||
resized_img = cv2.resize(img, (new_width, new_height))
|
||
# 裁剪高度
|
||
start_y = (new_height - target_height) // 2
|
||
cropped_img = resized_img[start_y:start_y + target_height, :]
|
||
|
||
return cropped_img
|