""" 步骤: 1、整理需要处理的款号图-输出款号图文件夹 2、整理所有相关的图片作为素材图 3、按要求进行拼接 """ import cv2 import numpy as np from PIL import Image, ImageFont import os import settings from module.base_mode.image_pic_deal import OnePicDeal from collections import defaultdict from module.view_control.generate_goods_no_detail_pic.detail_generate_base import DetailBase from module.view_control.generate_goods_no_detail_pic.pic_deal import PictureProcessing class DetailPicGet备份(DetailBase): def __init__(self, goods_no, goods_no_value: dict, out_put_dir, ): super().__init__(goods_no, goods_no_value, out_put_dir) self.goods_no = goods_no self.out_put_dir = out_put_dir self.goods_no_value = goods_no_value self.data = {} for goods_art_no_value in goods_no_value["货号资料"]: self.data[goods_art_no_value["货号"]] = {} for pic_name, pic_path in goods_art_no_value["pics"].items(): pic_name = pic_name.replace("俯视图", "俯视") pic_name = pic_name.replace("侧视图", "侧视") pic_name = pic_name.replace("后跟图", "后跟") pic_name = pic_name.replace("鞋底图", "鞋底") pic_name = pic_name.replace("内里图", "内里") print(pic_name) self.data[goods_art_no_value["货号"]][pic_name] = pic_path self.run() pass def to_resize(self, _im, width=None, high=None): _im_x, _im_y = _im.size if width and high: if _im_x >= _im_y: high = None else: width = None if width: re_x = int(width) re_y = int(_im_y * re_x / _im_x) else: re_y = int(high) re_x = int(_im_x * re_y / _im_y) _im = _im.resize((re_x, re_y)) return _im def image_init(self): name_size_dict = {"俯视": 1600, "侧视": 1600, "后跟": 800, "鞋底": 1600, "内里": 1600, } # 制作一批素材图,添加背景色,并保留阴影,以及处理成最小尺寸 bg_color = (246, 246, 246) for _goods_art_no, value in self.data.items(): name_list = ["俯视", "侧视", "后跟", "鞋底", "内里"] for _name in name_list: # 打开第一张图 im1 = Image.open(self.data[_goods_art_no]["{name}-阴影".format(name=_name)]) im2 = Image.open(self.data[_goods_art_no]["{name}-抠图".format(name=_name)]) im = self.get_overlay_pic(im1, im2, bg_color) im = self.to_resize(im, width=name_size_dict[_name]) # 保留最小区域 # im = self.get_goods_pos(im, im2) self.data[_goods_art_no][_name] = im def run(self): self.image_init() bg_color = (246, 246, 246) detailed_images = [] """ 制作主图 """ goods_art_no_list = list(self.data.keys()) # if len(goods_art_no_list) > 1: # im_1 = self.data[goods_art_no_list[0]]["侧视"] # im_2 = self.data[goods_art_no_list[1]]["俯视"] # else: im_1 = self.data[goods_art_no_list[0]]["侧视"] im_2 = self.data[goods_art_no_list[0]]["俯视"] data = [] data.append({"command": "resize", "plugins_mode": "relative", # pixel 相对(宽度、高度、其他参考图),或绝对像素 "base_im": {"im": Image.new("RGB", (550, 340), (248, 248, 248))}, # 参考基于其他图 PIL格式 "base": "by_im", # base:pixel,width,height,by_im 基于长边、基于短边 (基于短边时,则缩放到指定尺寸)by_im确保能塞进参考图内 "value": 0, # 固定值,如果为百分比,则为0 "percentage": 0, }) image = self.deal_one_pic(img=im_1, data=data) data = [] data.append({ "command": "paste_img", "img": {"im": image}, "pos": {"plugins_mode": "pixel", # pixel "base": "center", # nw,nc,ne,ec ... 各个方向参考点 "value": (0, 0), "percentage": (0, 0), }, "margins": (0, 0, 0, 0), # 上下左右边距 }) image = self.deal_one_pic(img=Image.new("RGB", (550, 340), bg_color), data=data) data = [] bg_img = Image.open(r"resources\detail_image_2\image (1).jpg") data.append({ "command": "paste_img", "img": {"im": image}, "pos": {"plugins_mode": "pixel", # pixel "base": "nw", # nw,nc,ne,ec ... 各个方向参考点 "value": (26, 263), "percentage": (0, 0), }, "margins": (0, 0, 0, 0), # 上下左右边距 }) bg_img = self.deal_one_pic(img=bg_img, data=data) # ---------- 第二张图处理 data = [] data.append({"command": "resize", "plugins_mode": "relative", # pixel 相对(宽度、高度、其他参考图),或绝对像素 "base_im": {"im": Image.new("RGB", (550, 340), (248, 248, 248))}, # 参考基于其他图 PIL格式 "base": "by_im", # base:pixel,width,height,by_im 基于长边、基于短边 (基于短边时,则缩放到指定尺寸)by_im确保能塞进参考图内 "value": 0, # 固定值,如果为百分比,则为0 "percentage": 0, }) # 百分比 image = self.deal_one_pic(img=im_2, data=data) data = [] data.append({ "command": "paste_img", "img": {"im": image}, "pos": {"plugins_mode": "pixel", # pixel "base": "center", # nw,nc,ne,ec ... 各个方向参考点 "value": (0, 0), "percentage": (0, 0), }, "margins": (0, 0, 0, 0), # 上下左右边距 }) image = self.deal_one_pic(img=Image.new("RGB", (550, 340), bg_color), data=data) data = [] data.append({ "command": "paste_img", "img": {"im": image}, "pos": {"plugins_mode": "pixel", # pixel "base": "nw", # nw,nc,ne,ec ... 各个方向参考点 "value": (26, 626), "percentage": (0, 0), }, "margins": (0, 0, 0, 0), # 上下左右边距 }) font = ImageFont.truetype(r'resources\ttf\simhei.ttf', 30) _d = [("商品款号", self.goods_no_value["款号"], 700, 297), ("商品面料", self.goods_no_value["商品面料"], 700, 380), ("商品内里", self.goods_no_value["商品内里"], 700, 469), ("商品鞋底", self.goods_no_value["商品鞋底"], 700, 549), ("后帮高", self.goods_no_value["后帮高"], 700, 667), ("前掌宽", self.goods_no_value["前掌宽"], 700, 751), ("鞋跟高", self.goods_no_value["鞋跟高"], 700, 828), ] for i in _d: if i[1]: data.append({ "command": "add_text", "pos": {"plugins_mode": "pixel", # pixel relative "value": (i[2], i[3]), }, "font": font, "text": "{}:{}".format(i[0], i[1]), "align": "center", "direction": "", "max_len_one_line": "", "spacing": 10, "fill": (17, 16, 16), }) image = self.deal_one_pic(img=bg_img, data=data) detailed_images.append(image) """ 设计师说展示图 """ # 设计师说 text = self.goods_no_value["FAB说明"] if text: detailed_images.append(Image.open(r"resources\detail_image_2\image (2).jpg")) data = [] text = text.replace(r"\n", "\n") _ = text.split("\n") bg_img = Image.new("RGB", (1200, len(_) * 100 + 30), (255, 255, 255)) data.append({ "command": "add_text", "pos": {"plugins_mode": "pixel", # pixel relative "value": (600, 50), }, "font": font, "text": text, "anchor": "ma", "align": "center", "direction": "", "max_len_one_line": "", "spacing": 50, "fill": (83, 83, 83), }) image = self.deal_one_pic(img=bg_img, data=data) detailed_images.append(image) # image.show() # raise 1 """ 制作角度展示图 """ # 角度展示 detailed_images.append(Image.open(r"resources\detail_image_2\image (3).jpg")) goods_art_no_list = list(self.data.keys()) for index, goods_art_no in enumerate(goods_art_no_list): if index == 0: name_list = ["侧视", "俯视", "后跟", "鞋底"] else: name_list = ["侧视", "俯视", ] for _name in name_list: # 处理图片,需要粘贴到背景等处理 _image = self.data[goods_art_no][_name] data = [] data.append({"command": "resize", "plugins_mode": "pixel", # pixel 相对(宽度、高度、其他参考图),或绝对像素 "base": "width", # base:pixel,width,height,by_im 基于长边、基于短边 (基于短边时,则缩放到指定尺寸)by_im确保能塞进参考图内 "value": 649 if _name == "后跟" else 1058, # 固定值,如果为百分比,则为0 }) # 百分比 _image = self.deal_one_pic(img=_image, data=data) data = [] data.append({ "command": "paste_img", "img": {"im": _image}, "pos": {"plugins_mode": "pixel", # pixel "base": "center", # nw,nc,ne,ec ... 各个方向参考点 "value": (0, 0), "percentage": (0, 0), }, "margins": (0, 0, 0, 0), # 上下左右边距 }) bg_img = Image.new("RGB", (1200, int(_image.height + 50)), bg_color) _image = self.deal_one_pic(img=bg_img, data=data) # _image.show() detailed_images.append(_image) detailed_images.append(Image.new("RGB", (1200, 50), (255, 255, 255))) """ 制作详细图 """ detailed_images.append(Image.open(r"resources\detail_image_2\image (4).jpg")) views = ["俯视", "内里", "后跟", "鞋底"] goods_art_no = list(self.data.keys())[0] for view in views: to_paste_img = self.data[goods_art_no][view] data = [] # 单图缩放处理 data.append({"command": "resize", "plugins_mode": "pixel", # pixel 相对(宽度、高度、其他参考图),或绝对像素 "base_im": {"im": ""}, # 参考基于其他图 PIL格式 "base": "width", # base:pixel,width,height,by_im 基于长边、基于短边 (基于短边时,则缩放到指定尺寸)by_im确保能塞进参考图内 "value": 1300 if view == "后跟" else 2200, # 固定值,如果为百分比,则为0 "percentage": 0, }) # 百分比 view_dict = {"俯视": (0, 0, 1100, 1200), "内里": (-1, -100, 1100, 1200), "后跟": (0, -100, 1100, 1200), "鞋底": (0, -100, 1100, 1200), } data.append({ "command": "crop_img", "img": "", "pos": {"plugins_mode": "pixel", # pixel "base": "sw", # nw,nc,ne,ec ... 各个方向参考点 "value": view_dict[view], }, "color_fill": bg_color, }) # 处理圆角 data.append({"command": "radius", # radius "plugins_mode": "relative", # pixel 相对(短边),或绝对像素 "circular_pos": (1, 0, 0, 1), # 从左上角顺时针,记录圆角数量 "value": 100, # 固定值,如果为百分比,则为0 "percentage": 0, }) # 百分比 to_paste_img = self.deal_one_pic(to_paste_img, data) # print(to_paste_img.size) # 粘贴到白底图上 img = Image.new("RGB", (1200, 1316), (255, 255, 255)) data = [] data.append({ "command": "paste_img", "img": {"im": to_paste_img}, "pos": {"plugins_mode": "pixel", # pixel relative "base": "wc", # nw,nc,ne,ec,... 各个方向参考点 "value": (100, 0), "percentage": "", }, "margins": (0, 0, 0, 0), # 上下左右边距 }) img = self.deal_one_pic(img, data) # if view == "后跟": # img.show() detailed_images.append(img) detailed_images.append(Image.open(r"resources\detail_image_2\image (5).jpg")) output_path = "{out_put_dir}/{goods_no}/details".format(out_put_dir=self.out_put_dir, goods_no=self.goods_no) self.create_folder(output_path) for index, im in enumerate(detailed_images): im.save("{}/{}({}).png".format(output_path, self.goods_no, str(index + 11).zfill(2))) # img = self.add_pic(detailed_images) # img.save("{}/0_{}_拼接图.png".format(self.out_put_dir, self.goods_no)) return True def add_pic(self, detailed_images): if not detailed_images: return page_len = 0 for index, im in enumerate(detailed_images): page_len += im.height bg_im = Image.new("RGB", (im.width, page_len), (255, 255, 255)) n = 0 for index, im in enumerate(detailed_images): bg_im.paste(im, (0, n)) n += im.height # bg_im.show() return bg_im def get_goods_pos(self, im, cut_image): # 保留多余内容 old_x, old_y = im.size x1, y1, x2, y2 = cut_image.getbbox() goods_w, goods_h = x2 - x1, y2 - y1 _w, _h = int(goods_w / 10), int(goods_h / 10) # 上下左右扩展位置 new_x1, new_y1, new_x2, new_y2 = x1 - _w, y1 - _h, x2 + _w, y2 + _h # 防止超限 new_x1 = 0 if new_x1 < 0 else new_x1 new_y1 = 0 if new_y1 < 0 else new_y1 new_x2 = old_x if new_x2 > old_x else new_x2 new_y2 = old_y if new_y2 > old_y else new_y2 # 剪切掉多余的内容,保留阴影 im = im.crop((new_x1, new_y1, new_x2, new_y2)) # 切图 return im def set_dict(self, one_dict): _ = defaultdict(str) for i, v in one_dict.items(): if isinstance(v, dict): v = self.set_dict(v) _[i] = v return _ def deal_one_pic(self, img: Image, data=None): """ 通用图片处理器 1、基于某原始图,进行加工,包括粘贴、单图处理等逻辑 """ data = [self.set_dict(x) for x in data] for command in data: if command["command"] == "resize": img = OnePicDeal().resize(img, command) continue if command["command"] == "paste_img": img = OnePicDeal().paste_img(img, command) continue if command["command"] == "crop_img": img = OnePicDeal().crop_img(img, command) continue if command["command"] == "radius": img = OnePicDeal().radius(img, command) continue if command["command"] == "add_text": img = OnePicDeal().add_text(img, command) continue return img def get_overlay_pic(self, pil_img_1, pil_img_2, color): im_w, im_h = pil_img_1.size cv_im = cv2.cvtColor(np.asarray(pil_img_1), cv2.COLOR_RGB2BGR) # 创建一张纯色底图 image_white = Image.new("RGB", (im_w, im_h), color) cv_image_white = cv2.cvtColor(np.asarray(image_white), cv2.COLOR_RGB2BGR) new_im = self.to_color_2(cv_image_white, cv_im) # new_im = cv2.addWeighted(new_im, 0.7, cv_im_2, 0.3, 0) # new_im = cv2.add(new_im, cv_im_2) new_im = Image.fromarray(cv2.cvtColor(new_im, cv2.COLOR_BGR2RGB)) new_im.paste(pil_img_2, (0, 0), pil_img_2) return new_im def to_color_2(self, target, blend): # 正片叠底 return np.array(np.multiply(target / 256, blend / 256) * 256, dtype=np.uint8) def to_color_1(self, img1, img2): # PS颜色模式 img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV) img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV) img2[:, :, 0] = img1[:, :, 0] img2[:, :, 1] = img1[:, :, 1] res = cv2.cvtColor(img2, cv2.COLOR_HSV2BGR) return res class DetailPicGetHqt(DetailBase): def __init__(self, goods_no, goods_no_value: dict, out_put_dir, ): super().__init__(goods_no, goods_no_value, out_put_dir) def run(self): bg_color = (246, 246, 246) self.image_init(bg_color) detailed_images = [] """ 制作主图 """ goods_art_no_list = list(self.data.keys()) # if len(goods_art_no_list) > 1: # im_1 = self.data[goods_art_no_list[0]]["侧视"] # im_2 = self.data[goods_art_no_list[1]]["俯视"] # else: pp_1 = self.data[goods_art_no_list[0]]["pic_is_deal"]["侧视"] pp_2 = self.data[goods_art_no_list[0]]["pic_is_deal"]["俯视"] pp_image = pp_1.resize(mode="relative", base="by_im", value=0, base_im=PictureProcessing("RGB", (550, 340), (248, 248, 248)), percentage=0) pp_image = PictureProcessing("RGB", (550, 340), bg_color).paste_img( mode="pixel", top_img=pp_image, base="center" ) pp_image = PictureProcessing("RGB", (550, 340), bg_color).paste_img( mode="pixel", top_img=pp_image, base="nw",value= (26, 263), ) bg_img = PictureProcessing(r"resources\detail_image_2\image (1).jpg").paste_img( mode="pixel", top_img=pp_image, base="nw",value= (26, 263)) bg_img.show() return # ---------- 第二张图处理 data = [] data.append({"command": "resize", "plugins_mode": "relative", # pixel 相对(宽度、高度、其他参考图),或绝对像素 "base_im": {"im": Image.new("RGB", (550, 340), (248, 248, 248))}, # 参考基于其他图 PIL格式 "base": "by_im", # base:pixel,width,height,by_im 基于长边、基于短边 (基于短边时,则缩放到指定尺寸)by_im确保能塞进参考图内 "value": 0, # 固定值,如果为百分比,则为0 "percentage": 0, }) # 百分比 image = self.deal_one_pic(img=im_2, data=data) data = [] data.append({ "command": "paste_img", "img": {"im": image}, "pos": {"plugins_mode": "pixel", # pixel "base": "center", # nw,nc,ne,ec ... 各个方向参考点 "value": (0, 0), "percentage": (0, 0), }, "margins": (0, 0, 0, 0), # 上下左右边距 }) image = self.deal_one_pic(img=Image.new("RGB", (550, 340), bg_color), data=data) data = [] data.append({ "command": "paste_img", "img": {"im": image}, "pos": {"plugins_mode": "pixel", # pixel "base": "nw", # nw,nc,ne,ec ... 各个方向参考点 "value": (26, 626), "percentage": (0, 0), }, "margins": (0, 0, 0, 0), # 上下左右边距 }) font = ImageFont.truetype(r'resources\ttf\simhei.ttf', 30) _d = [("商品款号", self.goods_no_value["款号"], 700, 297), ("商品面料", self.goods_no_value["商品面料"], 700, 380), ("商品内里", self.goods_no_value["商品内里"], 700, 469), ("商品鞋底", self.goods_no_value["商品鞋底"], 700, 549), ("后帮高", self.goods_no_value["后帮高"], 700, 667), ("前掌宽", self.goods_no_value["前掌宽"], 700, 751), ("鞋跟高", self.goods_no_value["鞋跟高"], 700, 828), ] for i in _d: if i[1]: data.append({ "command": "add_text", "pos": {"plugins_mode": "pixel", # pixel relative "value": (i[2], i[3]), }, "font": font, "text": "{}:{}".format(i[0], i[1]), "align": "center", "direction": "", "max_len_one_line": "", "spacing": 10, "fill": (17, 16, 16), }) image = self.deal_one_pic(img=bg_img, data=data) detailed_images.append(image) """ 设计师说展示图 """ # 设计师说 text = self.goods_no_value["FAB说明"] if text: detailed_images.append(Image.open(r"resources\detail_image_2\image (2).jpg")) data = [] text = text.replace(r"\n", "\n") _ = text.split("\n") bg_img = Image.new("RGB", (1200, len(_) * 100 + 30), (255, 255, 255)) data.append({ "command": "add_text", "pos": {"plugins_mode": "pixel", # pixel relative "value": (600, 50), }, "font": font, "text": text, "anchor": "ma", "align": "center", "direction": "", "max_len_one_line": "", "spacing": 50, "fill": (83, 83, 83), }) image = self.deal_one_pic(img=bg_img, data=data) detailed_images.append(image) # image.show() # raise 1 """ 制作角度展示图 """ # 角度展示 detailed_images.append(Image.open(r"resources\detail_image_2\image (3).jpg")) goods_art_no_list = list(self.data.keys()) for index, goods_art_no in enumerate(goods_art_no_list): if index == 0: name_list = ["侧视", "俯视", "后跟", "鞋底"] else: name_list = ["侧视", "俯视", ] for _name in name_list: # 处理图片,需要粘贴到背景等处理 _image = self.data[goods_art_no][_name] data = [] data.append({"command": "resize", "plugins_mode": "pixel", # pixel 相对(宽度、高度、其他参考图),或绝对像素 "base": "width", # base:pixel,width,height,by_im 基于长边、基于短边 (基于短边时,则缩放到指定尺寸)by_im确保能塞进参考图内 "value": 649 if _name == "后跟" else 1058, # 固定值,如果为百分比,则为0 }) # 百分比 _image = self.deal_one_pic(img=_image, data=data) data = [] data.append({ "command": "paste_img", "img": {"im": _image}, "pos": {"plugins_mode": "pixel", # pixel "base": "center", # nw,nc,ne,ec ... 各个方向参考点 "value": (0, 0), "percentage": (0, 0), }, "margins": (0, 0, 0, 0), # 上下左右边距 }) bg_img = Image.new("RGB", (1200, int(_image.height + 50)), bg_color) _image = self.deal_one_pic(img=bg_img, data=data) # _image.show() detailed_images.append(_image) detailed_images.append(Image.new("RGB", (1200, 50), (255, 255, 255))) """ 制作详细图 """ detailed_images.append(Image.open(r"resources\detail_image_2\image (4).jpg")) views = ["俯视", "内里", "后跟", "鞋底"] goods_art_no = list(self.data.keys())[0] for view in views: to_paste_img = self.data[goods_art_no][view] data = [] # 单图缩放处理 data.append({"command": "resize", "plugins_mode": "pixel", # pixel 相对(宽度、高度、其他参考图),或绝对像素 "base_im": {"im": ""}, # 参考基于其他图 PIL格式 "base": "width", # base:pixel,width,height,by_im 基于长边、基于短边 (基于短边时,则缩放到指定尺寸)by_im确保能塞进参考图内 "value": 1300 if view == "后跟" else 2200, # 固定值,如果为百分比,则为0 "percentage": 0, }) # 百分比 view_dict = {"俯视": (0, 0, 1100, 1200), "内里": (-1, -100, 1100, 1200), "后跟": (0, -100, 1100, 1200), "鞋底": (0, -100, 1100, 1200), } data.append({ "command": "crop_img", "img": "", "pos": {"plugins_mode": "pixel", # pixel "base": "sw", # nw,nc,ne,ec ... 各个方向参考点 "value": view_dict[view], }, "color_fill": bg_color, }) # 处理圆角 data.append({"command": "radius", # radius "plugins_mode": "relative", # pixel 相对(短边),或绝对像素 "circular_pos": (1, 0, 0, 1), # 从左上角顺时针,记录圆角数量 "value": 100, # 固定值,如果为百分比,则为0 "percentage": 0, }) # 百分比 to_paste_img = self.deal_one_pic(to_paste_img, data) # print(to_paste_img.size) # 粘贴到白底图上 img = Image.new("RGB", (1200, 1316), (255, 255, 255)) data = [] data.append({ "command": "paste_img", "img": {"im": to_paste_img}, "pos": {"plugins_mode": "pixel", # pixel relative "base": "wc", # nw,nc,ne,ec,... 各个方向参考点 "value": (100, 0), "percentage": "", }, "margins": (0, 0, 0, 0), # 上下左右边距 }) img = self.deal_one_pic(img, data) # if view == "后跟": # img.show() detailed_images.append(img) detailed_images.append(Image.open(r"resources\detail_image_2\image (5).jpg")) output_path = "{out_put_dir}/{goods_no}/details".format(out_put_dir=self.out_put_dir, goods_no=self.goods_no) self.create_folder(output_path) for index, im in enumerate(detailed_images): im.save("{}/{}({}).png".format(output_path, self.goods_no, str(index + 11).zfill(2))) # img = self.add_pic(detailed_images) # img.save("{}/0_{}_拼接图.png".format(self.out_put_dir, self.goods_no)) return True def add_pic(self, detailed_images): if not detailed_images: return page_len = 0 for index, im in enumerate(detailed_images): page_len += im.height bg_im = Image.new("RGB", (im.width, page_len), (255, 255, 255)) n = 0 for index, im in enumerate(detailed_images): bg_im.paste(im, (0, n)) n += im.height # bg_im.show() return bg_im def get_goods_pos(self, im, cut_image): # 保留多余内容 old_x, old_y = im.size x1, y1, x2, y2 = cut_image.getbbox() goods_w, goods_h = x2 - x1, y2 - y1 _w, _h = int(goods_w / 10), int(goods_h / 10) # 上下左右扩展位置 new_x1, new_y1, new_x2, new_y2 = x1 - _w, y1 - _h, x2 + _w, y2 + _h # 防止超限 new_x1 = 0 if new_x1 < 0 else new_x1 new_y1 = 0 if new_y1 < 0 else new_y1 new_x2 = old_x if new_x2 > old_x else new_x2 new_y2 = old_y if new_y2 > old_y else new_y2 # 剪切掉多余的内容,保留阴影 im = im.crop((new_x1, new_y1, new_x2, new_y2)) # 切图 return im def set_dict(self, one_dict): _ = defaultdict(str) for i, v in one_dict.items(): if isinstance(v, dict): v = self.set_dict(v) _[i] = v return _ def deal_one_pic(self, img: Image, data=None): """ 通用图片处理器 1、基于某原始图,进行加工,包括粘贴、单图处理等逻辑 """ data = [self.set_dict(x) for x in data] for command in data: if command["command"] == "resize": img = OnePicDeal().resize(img, command) continue if command["command"] == "paste_img": img = OnePicDeal().paste_img(img, command) continue if command["command"] == "crop_img": img = OnePicDeal().crop_img(img, command) continue if command["command"] == "radius": img = OnePicDeal().radius(img, command) continue if command["command"] == "add_text": img = OnePicDeal().add_text(img, command) continue return img def get_overlay_pic(self, pil_img_1, pil_img_2, color): im_w, im_h = pil_img_1.size cv_im = cv2.cvtColor(np.asarray(pil_img_1), cv2.COLOR_RGB2BGR) # 创建一张纯色底图 image_white = Image.new("RGB", (im_w, im_h), color) cv_image_white = cv2.cvtColor(np.asarray(image_white), cv2.COLOR_RGB2BGR) new_im = self.to_color_2(cv_image_white, cv_im) # new_im = cv2.addWeighted(new_im, 0.7, cv_im_2, 0.3, 0) # new_im = cv2.add(new_im, cv_im_2) new_im = Image.fromarray(cv2.cvtColor(new_im, cv2.COLOR_BGR2RGB)) new_im.paste(pil_img_2, (0, 0), pil_img_2) return new_im def to_color_2(self, target, blend): # 正片叠底 return np.array(np.multiply(target / 256, blend / 256) * 256, dtype=np.uint8) def to_color_1(self, img1, img2): # PS颜色模式 img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV) img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV) img2[:, :, 0] = img1[:, :, 0] img2[:, :, 1] = img1[:, :, 1] res = cv2.cvtColor(img2, cv2.COLOR_HSV2BGR) return res class DetailPicGetHLM(object): def __init__(self, goods_no, goods_no_value: dict, out_put_dir, windows=None): self.windows = windows self.goods_no = goods_no self.out_put_dir = out_put_dir self.goods_no_value = goods_no_value self.data = {} for goods_art_no_value in goods_no_value["货号资料"]: self.data[goods_art_no_value["货号"]] = {} for pic_name, pic_path in goods_art_no_value["pics"].items(): self.data[goods_art_no_value["货号"]][pic_name] = pic_path self.run() pass def to_resize(self, _im, width=None, high=None): _im_x, _im_y = _im.size if width and high: if _im_x >= _im_y: high = None else: width = None if width: re_x = int(width) re_y = int(_im_y * re_x / _im_x) else: re_y = int(high) re_x = int(_im_x * re_y / _im_y) _im = _im.resize((re_x, re_y)) return _im def image_init(self): name_size_dict = {"俯视": 1600, "侧视": 1600, "后跟": 800, "鞋底": 1600, "内里": 1600, } # 制作一批素材图,添加背景色,并保留阴影,以及处理成最小尺寸 bg_color = (246, 246, 246) for _goods_art_no, value in self.data.items(): if settings.PROJECT == "红蜻蜓": name_list = ["俯视", "侧视", "后跟", "鞋底", "内里"] elif settings.PROJECT == "惠利玛": name_list = ["俯视", "侧视", "后跟", "鞋底", "内里"] else: name_list = ["俯视", "侧视", "后跟", "鞋底", "内里"] for _name in name_list: # 打开第一张图 try: im1 = Image.open(self.data[_goods_art_no]["{name}-阴影".format(name=_name)]) im2 = Image.open(self.data[_goods_art_no]["{name}-抠图".format(name=_name)]) im = self.get_overlay_pic(im1, im2, bg_color) im = self.to_resize(im, width=name_size_dict[_name]) # 保留最小区域 # im = self.get_goods_pos(im, im2) self.data[_goods_art_no][_name] = im except BaseException as e: print(e) pass def run(self): self.image_init() bg_color = (246, 246, 246) detailed_images = [] """ 头部信息 """ detailed_images.append(Image.open(r"resources\detail_image_3\image (1).jpg")) """ 制作主图 """ goods_art_no_list = list(self.data.keys()) im_1 = self.data[goods_art_no_list[0]]["俯视"] im_2 = self.data[goods_art_no_list[0]]["侧视"] data = [] data.append({"command": "resize", "plugins_mode": "relative", # pixel 相对(宽度、高度、其他参考图),或绝对像素 "base_im": {"im": Image.new("RGB", (604, 418), (248, 248, 248))}, # 参考基于其他图 PIL格式 "base": "by_im", # base:pixel,width,height,by_im 基于长边、基于短边 (基于短边时,则缩放到指定尺寸)by_im确保能塞进参考图内 "value": 0, # 固定值,如果为百分比,则为0 "percentage": 0, }) image = self.deal_one_pic(img=im_1, data=data) data = [] data.append({ "command": "paste_img", "img": {"im": image}, "pos": {"plugins_mode": "pixel", # pixel "base": "center", # nw,nc,ne,ec ... 各个方向参考点 "value": (0, 0), "percentage": (0, 0), }, "margins": (0, 0, 0, 0), # 上下左右边距 }) image = self.deal_one_pic(img=Image.new("RGB", (604, 418), bg_color), data=data) data = [] bg_img = Image.new("RGB", (1200, 918), (255, 255, 255)) data.append({ "command": "paste_img", "img": {"im": image}, "pos": {"plugins_mode": "pixel", # pixel "base": "nw", # nw,nc,ne,ec ... 各个方向参考点 "value": (26, 26), "percentage": (0, 0), }, "margins": (0, 0, 0, 0), # 上下左右边距 }) bg_img = self.deal_one_pic(img=bg_img, data=data) # ---------- 第二张图处理 data = [] data.append({"command": "resize", "plugins_mode": "relative", # pixel 相对(宽度、高度、其他参考图),或绝对像素 "base_im": {"im": Image.new("RGB", (604, 418), (248, 248, 248))}, # 参考基于其他图 PIL格式 "base": "by_im", # base:pixel,width,height,by_im 基于长边、基于短边 (基于短边时,则缩放到指定尺寸)by_im确保能塞进参考图内 "value": 0, # 固定值,如果为百分比,则为0 "percentage": 0, }) # 百分比 image = self.deal_one_pic(img=im_2, data=data) data = [] data.append({ "command": "paste_img", "img": {"im": image}, "pos": {"plugins_mode": "pixel", # pixel "base": "center", # nw,nc,ne,ec ... 各个方向参考点 "value": (0, 0), "percentage": (0, 0), }, "margins": (0, 0, 0, 0), # 上下左右边距 }) image = self.deal_one_pic(img=Image.new("RGB", (604, 418), bg_color), data=data) data = [] data.append({ "command": "paste_img", "img": {"im": image}, "pos": {"plugins_mode": "pixel", # pixel "base": "nw", # nw,nc,ne,ec ... 各个方向参考点 "value": (26, 26 + 26 + 418), "percentage": (0, 0), }, "margins": (0, 0, 0, 0), # 上下左右边距 }) font = ImageFont.truetype(r'resources\ttf\simhei.ttf', 30) _d = [("款号", self.goods_no_value["款号"], 722, 26), ("面料", self.goods_no_value["商品面料"], 722, 106), ("内里", self.goods_no_value["商品内里"], 722, 186), ("鞋底", self.goods_no_value["商品鞋底"], 722, 266), ] for i in _d: if i[1]: data.append({ "command": "add_text", "pos": {"plugins_mode": "pixel", # pixel relative "value": (i[2], i[3]), }, "font": font, "text": "{}:{}".format(i[0], i[1]), "align": "center", "direction": "", "max_len_one_line": "", "spacing": 10, "fill": (17, 16, 16), }) image = self.deal_one_pic(img=bg_img, data=data) detailed_images.append(image) """ 尺码表 """ detailed_images.append(Image.open(r"resources\detail_image_3\image (2).jpg")) """ 细节图展示 """ view_dict = {"俯视": {"crop_img_value": (0, 0, 1086, 752), "crop_img_base": "sw", "paste_img_value": (0, 0), "paste_img_base": "center", }, "侧视": {"crop_img_value": (888, 0, 1086, 752), "crop_img_base": "sw", "paste_img_value": (0, 0), "paste_img_base": "center", }, } goods_art_no = list(self.data.keys())[0] for view in view_dict: to_paste_img = self.data[goods_art_no][view] data = [] # 单图缩放处理 data.append({"command": "resize", "plugins_mode": "pixel", # pixel 相对(宽度、高度、其他参考图),或绝对像素 "base_im": {"im": ""}, # 参考基于其他图 PIL格式 "base": "width", # base:pixel,width,height,by_im 基于长边、基于短边 (基于短边时,则缩放到指定尺寸)by_im确保能塞进参考图内 "value": 1800, # 固定值,如果为百分比,则为0 "percentage": 0, }) # 百分比 data.append({ "command": "crop_img", "img": "", "pos": {"plugins_mode": "pixel", # pixel "base": view_dict[view]["crop_img_base"], # nw,nc,ne,ec ... 各个方向参考点 "value": view_dict[view]["crop_img_value"], }, "color_fill": bg_color, }) # 处理圆角 data.append({"command": "radius", # radius "plugins_mode": "relative", # pixel 相对(短边),或绝对像素 "circular_pos": (1, 1, 1, 1), # 从左上角顺时针,记录圆角数量 "value": 100, # 固定值,如果为百分比,则为0 "percentage": 0, }) # 百分比 to_paste_img = self.deal_one_pic(to_paste_img, data) # 粘贴到白底图上 data = [] data.append({ "command": "paste_img", "img": {"im": to_paste_img}, "pos": {"plugins_mode": "pixel", # pixel "base": view_dict[view]["paste_img_base"], # nw,nc,ne,ec ... 各个方向参考点 "value": view_dict[view]["paste_img_value"], }, "color_fill": bg_color, }) bg_c = Image.new("RGB", (1200, 848), (255, 255, 255)) bg_c_img = self.deal_one_pic(bg_c, data) to_paste_img = self.deal_one_pic(bg_c_img, data) detailed_images.append(to_paste_img) """ 制作角度展示图 """ # 角度展示 goods_art_no_list = list(self.data.keys()) for index, goods_art_no in enumerate(goods_art_no_list): if index == 0: name_list = ["俯视", "侧视", "后跟", "鞋底"] else: name_list = ["俯视", ] for _name in name_list: # 处理图片,需要粘贴到背景等处理 if _name not in self.data[goods_art_no]: continue _image = self.data[goods_art_no][_name] data = [] data.append({"command": "resize", "plugins_mode": "pixel", # pixel 相对(宽度、高度、其他参考图),或绝对像素 "base": "width", # base:pixel,width,height,by_im 基于长边、基于短边 (基于短边时,则缩放到指定尺寸)by_im确保能塞进参考图内 "value": 500 if _name == "后跟" else 1058, # 固定值,如果为百分比,则为0 }) # 百分比 _image = self.deal_one_pic(img=_image, data=data) data = [] data.append({ "command": "paste_img", "img": {"im": _image}, "pos": {"plugins_mode": "pixel", # pixel "base": "center", # nw,nc,ne,ec ... 各个方向参考点 "value": (0, 0), "percentage": (0, 0), }, "margins": (0, 0, 0, 0), # 上下左右边距 }) bg_img = Image.new("RGB", (1200, int(_image.height + 50)), bg_color) _image = self.deal_one_pic(img=bg_img, data=data) # _image.show() detailed_images.append(_image) detailed_images.append(Image.new("RGB", (1200, 50), (255, 255, 255))) detailed_images.append(Image.open(r"resources\detail_image_3\image (3).jpg")) """ 制作详细图 """ output_path = "{out_put_dir}/{goods_no}/details".format(out_put_dir=self.out_put_dir, goods_no=self.goods_no) self.create_folder(output_path) for index, im in enumerate(detailed_images): im.save("{}/{}({}).png".format(output_path, self.goods_no, str(index + 11).zfill(2))) img = self.add_pic(detailed_images) img.save("{}/0_{}_拼接图.png".format(self.out_put_dir, self.goods_no)) return True def create_folder(self, path): def check_folder(__path): if not os.path.exists(__path): os.makedirs(__path) return False return True # 文件夹不存在,创建货号子集文件夹 if not check_folder(path): pass # for name in ["原始图", "原始图_已抠图", "800x800", "200images"]: # other_path = path + "/" + name # check_folder(other_path) def add_pic(self, detailed_images): if not detailed_images: return page_len = 0 for index, im in enumerate(detailed_images): page_len += im.height bg_im = Image.new("RGB", (im.width, page_len), (255, 255, 255)) n = 0 for index, im in enumerate(detailed_images): bg_im.paste(im, (0, n)) n += im.height # bg_im.show() return bg_im def get_goods_pos(self, im, cut_image): # 保留多余内容 old_x, old_y = im.size x1, y1, x2, y2 = cut_image.getbbox() goods_w, goods_h = x2 - x1, y2 - y1 _w, _h = int(goods_w / 10), int(goods_h / 10) # 上下左右扩展位置 new_x1, new_y1, new_x2, new_y2 = x1 - _w, y1 - _h, x2 + _w, y2 + _h # 防止超限 new_x1 = 0 if new_x1 < 0 else new_x1 new_y1 = 0 if new_y1 < 0 else new_y1 new_x2 = old_x if new_x2 > old_x else new_x2 new_y2 = old_y if new_y2 > old_y else new_y2 # 剪切掉多余的内容,保留阴影 im = im.crop((new_x1, new_y1, new_x2, new_y2)) # 切图 return im def set_dict(self, one_dict): _ = defaultdict(str) for i, v in one_dict.items(): if isinstance(v, dict): v = self.set_dict(v) _[i] = v return _ def deal_one_pic(self, img: Image, data=None): """ 通用图片处理器 1、基于某原始图,进行加工,包括粘贴、单图处理等逻辑 """ data = [self.set_dict(x) for x in data] for command in data: if command["command"] == "resize": img = OnePicDeal().resize(img, command) continue if command["command"] == "paste_img": img = OnePicDeal().paste_img(img, command) continue if command["command"] == "crop_img": img = OnePicDeal().crop_img(img, command) continue if command["command"] == "radius": img = OnePicDeal().radius(img, command) continue if command["command"] == "add_text": img = OnePicDeal().add_text(img, command) continue return img def get_overlay_pic(self, pil_img_1, pil_img_2, color): im_w, im_h = pil_img_1.size cv_im = cv2.cvtColor(np.asarray(pil_img_1), cv2.COLOR_RGB2BGR) # 创建一张纯色底图 image_white = Image.new("RGB", (im_w, im_h), color) cv_image_white = cv2.cvtColor(np.asarray(image_white), cv2.COLOR_RGB2BGR) new_im = self.to_color_2(cv_image_white, cv_im) # new_im = cv2.addWeighted(new_im, 0.7, cv_im_2, 0.3, 0) # new_im = cv2.add(new_im, cv_im_2) new_im = Image.fromarray(cv2.cvtColor(new_im, cv2.COLOR_BGR2RGB)) new_im.paste(pil_img_2, (0, 0), pil_img_2) return new_im def to_color_2(self, target, blend): # 正片叠底 return np.array(np.multiply(target / 256, blend / 256) * 256, dtype=np.uint8) def to_color_1(self, img1, img2): # PS颜色模式 img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV) img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV) img2[:, :, 0] = img1[:, :, 0] img2[:, :, 1] = img1[:, :, 1] res = cv2.cvtColor(img2, cv2.COLOR_HSV2BGR) return res if __name__ == '__main__': _path = r"D:\MyDocuments\PythonCode\MyPython\red_dragonfly\deal_pics\auto_capture\IPC\output\2023-11-06" goods_no_dict = {} for goods_art_no in os.listdir(_path): if not os.path.isdir("{}/{}".format(_path, goods_art_no)): continue if len(goods_art_no) < 10: print("{}--长度异常".format(goods_art_no)) continue # print(goods_art_no) goods_no = goods_art_no[:9] if goods_no not in goods_no_dict: goods_no_dict[goods_no] = {} goods_no_dict[goods_no][goods_art_no] = {} # 获取该货号下所有素材图 阴影图处理 source_material_path = "{}/{}/阴影图处理".format(_path, goods_art_no) if not os.path.exists(source_material_path): print("{}--缺少 阴影图处理 文件夹".format(goods_art_no)) continue _ = {} if len(os.listdir(source_material_path)) % 2 != 0: print("{}--阴影图处理 文件错误".format(goods_art_no)) continue name_list = ["俯视", "侧视", "后跟", "鞋底", "内里"] for pic in os.listdir(source_material_path): # print(pic) _pic = pic.replace(".png", "") _pic = _pic.split("_") if len(_pic) != 3: continue _["{}-{}".format(_pic[1], _pic[2])] = "{}/{}".format(source_material_path, pic) goods_no_dict[goods_no][goods_art_no] = _ # print(_) # 准备拼接处理 for goods_no, goods_no_value in goods_no_dict.items(): # if goods_no == "AC5200054": print("开始处理-----{}".format(goods_no)) GenerateDetailPic(goods_no, goods_no_value) # raise 1 # print(goods_no_dict)