python生成psd文件实例

Written by

in

文章目录
  • import os from PIL import Image from psd_tools import PSDImage import cv2 import numpy as np import os from psd_tools.api.layers import PixelLayer from Skps import FaceAna def generate_eye_ellipse_mask(image_shape, landmarks, indices, scale_x=2, scale_y=1.25): “”” 使用最小外接椭圆生成眼睛 mask “”” mask = np.zeros(image_shape[:2], dtype=np.uint8) pts = landmarks[indices].astype(np.int32) if pts.shape[0] < 5: return mask ellipse = cv2.fitEllipse(pts) (cx, cy), (w, h), angle = ellipse w *= scale_x h *= scale_y cv2.ellipse( mask, ((int(cx), int(cy)), (int(w), int(h)), angle), 255, -1 ) return mask def generate_part_mask(image_shape, landmarks, indices): “”” 根据关键点索引生成对应部位的二进制遮罩。 Args: image_shape: 原图尺寸 (H, W) landmarks: 人脸关键点坐标数组 indices: 特定部位的关键点索引列表 Returns: mask: 二值化遮罩 (0/255) “”” mask = np.zeros(image_shape[:2], dtype=np.uint8) pts = landmarks[indices].astype(np.int32) # 使用凸包或最小矩形来定义区域 if len(indices) > 2: # 对于眼睛、嘴巴等轮廓点 hull = cv2.convexHull(pts) cv2.fillConvexPoly(mask, hull, 255) else: # 对于可能需要矩形定义的部位 x, y, w, h = cv2.boundingRect(pts) cv2.rectangle(mask, (x, y), (x + w, y + h), 255, -1) return mask def masks_to_psd(base_image_path, masks_dict, output_psd_path): # 1. 读取基础图像作为背景层 base_img = Image.open(base_image_path).convert(“RGBA”) # 2. 创建一个以基础图像为画布的PSD对象[citation:4][citation:9] psd = PSDImage.frompil(base_img) # 3. 为每个部位创建图层[citation:4][citation:9] for layer_name, mask in masks_dict.items(): # 将二值mask (0/255) 转换为RGBA图像 rgba_array = np.array(base_img).copy() # 形状为 (H, W, 4) rgba_array[mask == 0, 3] = 0 # 索引3代表RGBA中的A(Alpha)通道 part_img = Image.fromarray(rgba_array, mode=’RGBA’) # 第一个图层 layer0 = PixelLayer.frompil(part_img, psd) layer0.name = layer_name layer0.visible = True psd.append(layer0) # 4. 保存PSD文件[citation:4] psd.save(output_psd_path) print(f”PSD文件已生成: {output_psd_path}”) def generate_face_outer_mask(image_shape, landmarks, indices): “”” 生成头部轮廓以外的 mask “”” h, w = image_shape[:2] mask_face = np.zeros((h, w), np.uint8) pts = landmarks[indices].astype(np.int32) hull = cv2.convexHull(pts) cv2.fillConvexPoly(mask_face, hull, 255) # 反转:脸外 = 255 mask_outer = cv2.bitwise_not(mask_face) return mask_outer def generate_brow_mask(image_shape, landmarks, indices, scale_x=1.2, scale_y=1.5): “”” 生成眉毛 mask(扁椭圆 / 拉长) “”” mask = np.zeros(image_shape[:2], dtype=np.uint8) pts = landmarks[indices].astype(np.int32) if pts.shape[0] < 3: return mask hull = cv2.convexHull(pts) # 计算中心 cx = np.mean(hull[:, 0, 0]) cy = np.mean(hull[:, 0, 1]) # 缩放 hull(手动仿射) scaled = [] for p in hull[:, 0, :]: x = cx + (p[0] – cx) * scale_x y = cy + (p[1] – cy) * scale_y scaled.append([int(x), int(y)]) scaled = np.array(scaled, np.int32) cv2.fillConvexPoly(mask, scaled, 255) return mask def process_single_image(image_path, facer, output_dir=”output”): “”” 处理单张图片的主流程。 “”” # 1. 读取图片并运行关键点检测 image = cv2.imread(image_path) result = facer.run(image) # 假设只处理检测到的第一张脸 if len(result) == 0: print(f”未检测到人脸: {image_path}”) return landmarks = result[0][‘kps’] # 形状应为 (98, 2) # 2. 定义各部位的关键点索引 (需根据你的98点模型调整) # 以下索引为示例,请务必根据你的模型定义进行核对和修改 PARTS_INDEX = { “Face_Outline”: list(range(0, 32)), # 脸部轮廓示例索引 “Left_Eye”: list(range(60, 68)), # 左眼 “Right_Eye”: list(range(68, 76)), # 右眼 “Nose”: list(range(51, 60)), # 鼻子 “Mouth”: list(range(76, 96)), # 嘴巴 “Left_Brow” : list(range(33, 41)), “Right_Brow” : list(range(42, 50)) # 你可以根据需要添加更多部位,如眉毛: list(range(33, 51)) } # 3. 为每个部位生成遮罩 masks = {} for part_name, indices in PARTS_INDEX.items(): if part_name == “Face_Outline”: mask = generate_face_outer_mask(image.shape, landmarks, indices) elif part_name in [“Left_Eye”, “Right_Eye”]: mask = generate_eye_ellipse_mask(image.shape, landmarks, indices) elif part_name in [“Left_Brow”, “Right_Brow”]: mask = generate_brow_mask(image.shape, landmarks, indices) else: mask = generate_part_mask(image.shape, landmarks, indices) masks[part_name] = mask # 可选:保存每个部位的遮罩为PNG以供检查 # cv2.imwrite(os.path.join(output_dir, f”{part_name}.png”), mask) # 4. 生成PSD os.makedirs(output_dir, exist_ok=True) base_name = os.path.splitext(os.path.basename(image_path))[0] psd_path = os.path.join(output_dir, f”{base_name}_layers.psd”) masks_to_psd(image_path, masks, psd_path) if __name__ == “__main__”: # 初始化你的关键点检测器 facer = FaceAna() image_path = r”D:project_2025live2dtalking-head-anime-4-demo-maindemodataimageslambda_02.png” process_single_image(image_path, facer, output_dir=”psd_output”)
  • 以上为个人经验,希望能给大家一个参考,也希望大家多多支持风君子博客。 您可能感兴趣的文章: Python通过psd-tools解析PSD文件的实现 Python通过psd-tools解析PSD文件
  • 目录
    • python生成psd文件
      • 多个图层,方便ps打开编辑
      • 创建多个图层
    • 关键点分割人脸,生成多图层
      • 总结

        gen_psd.py

        from PIL import Image
        
        from psd_tools import PSDImage
        from psd_tools.api.layers import PixelLayer
        
        def image_to_psd(image_obj: Image, save_path):
            # 确保图像模式为 RGBA
            if image_obj.mode != "RGBA":
                image_obj = image_obj.convert("RGBA")
        
            # 将PIL图像转换为PSD格式
            psd = PSDImage.frompil(image_obj)
        
            # 创建一个新图层
            pixel_layer = PixelLayer.frompil(image_obj, psd)
            pixel_layer.visible = True  # 设置图层为可见
        
            psd.append(pixel_layer)  # 将图层添加到PSD中
            psd.save(save_path)  # 保存为PSD文件
        
        if __name__ == "__main__":
            image_obj = Image.open(r"D:project_2025live2dtalking-head-anime-4-demo-maindemocharacter_modelcharacter.png")
            save_path = 'demo.psd'
            image_to_psd(image_obj, save_path)

        from PIL import Image
        from psd_tools import PSDImage
        from psd_tools.api.layers import PixelLayer
        
        
        def image_to_psd(image_paths, save_path):
            # 读取第一张图,作为 PSD 画布
            base_img = Image.open(image_paths[0]).convert("RGBA")
            psd = PSDImage.frompil(base_img)
        
            # 第一个图层
            layer0 = PixelLayer.frompil(base_img, psd)
            layer0.name = "Base"
            layer0.visible = True
            psd.append(layer0)
        
            # 后续图片作为新图层
            for i, img_path in enumerate(image_paths[1:], start=1):
                img = Image.open(img_path).convert("RGBA")
                layer = PixelLayer.frompil(img, psd)
                layer.name = f"Layer_{i}"
                layer.visible = True
                psd.append(layer)
        
            # 保存 PSD
            psd.save(save_path)
        
        
        if __name__ == "__main__":
            image_paths = [
                r"D:project_2025live2dtalking-head-anime-4-demo-maindemodataimageslambda_02_face_mask.png",
                r"D:project_2025live2dtalking-head-anime-4-demo-maindemodataimageslambda_02.png",
            ]
        
            image_to_psd(image_paths, "demo.psd")
        

        import os
        from PIL import Image
        from psd_tools import PSDImage
        
        import cv2
        import numpy as np
        import os
        
        from psd_tools.api.layers import PixelLayer
        
        from Skps import FaceAna
        
        def generate_eye_ellipse_mask(image_shape, landmarks, indices, scale_x=2, scale_y=1.25):
            """
            使用最小外接椭圆生成眼睛 mask
            """
            mask = np.zeros(image_shape[:2], dtype=np.uint8)
            pts = landmarks[indices].astype(np.int32)
        
            if pts.shape[0] < 5:
                return mask
        
            ellipse = cv2.fitEllipse(pts)
            (cx, cy), (w, h), angle = ellipse
        
            w *= scale_x
            h *= scale_y
        
            cv2.ellipse(
                mask,
                ((int(cx), int(cy)), (int(w), int(h)), angle),
                255,
                -1
            )
            return mask
        
        def generate_part_mask(image_shape, landmarks, indices):
            """
            根据关键点索引生成对应部位的二进制遮罩。
            Args:
                image_shape: 原图尺寸 (H, W)
                landmarks: 人脸关键点坐标数组
                indices: 特定部位的关键点索引列表
            Returns:
                mask: 二值化遮罩 (0/255)
            """
            mask = np.zeros(image_shape[:2], dtype=np.uint8)
            pts = landmarks[indices].astype(np.int32)
            # 使用凸包或最小矩形来定义区域
            if len(indices) > 2:  # 对于眼睛、嘴巴等轮廓点
                hull = cv2.convexHull(pts)
                cv2.fillConvexPoly(mask, hull, 255)
            else:  # 对于可能需要矩形定义的部位
                x, y, w, h = cv2.boundingRect(pts)
                cv2.rectangle(mask, (x, y), (x + w, y + h), 255, -1)
            return mask
        
        
        def masks_to_psd(base_image_path, masks_dict, output_psd_path):
        
            # 1. 读取基础图像作为背景层
            base_img = Image.open(base_image_path).convert("RGBA")
            # 2. 创建一个以基础图像为画布的PSD对象[citation:4][citation:9]
            psd = PSDImage.frompil(base_img)
        
            # 3. 为每个部位创建图层[citation:4][citation:9]
            for layer_name, mask in masks_dict.items():
                # 将二值mask (0/255) 转换为RGBA图像
        
                rgba_array = np.array(base_img).copy()  # 形状为 (H, W, 4)
                rgba_array[mask == 0, 3] = 0  # 索引3代表RGBA中的A(Alpha)通道
        
                part_img = Image.fromarray(rgba_array, mode='RGBA')
                # 第一个图层
                layer0 = PixelLayer.frompil(part_img, psd)
                layer0.name = layer_name
                layer0.visible = True
                psd.append(layer0)
        
            # 4. 保存PSD文件[citation:4]
            psd.save(output_psd_path)
            print(f"PSD文件已生成: {output_psd_path}")
        
        def generate_face_outer_mask(image_shape, landmarks, indices):
            """
            生成头部轮廓以外的 mask
            """
            h, w = image_shape[:2]
            mask_face = np.zeros((h, w), np.uint8)
        
            pts = landmarks[indices].astype(np.int32)
            hull = cv2.convexHull(pts)
            cv2.fillConvexPoly(mask_face, hull, 255)
        
            # 反转:脸外 = 255
            mask_outer = cv2.bitwise_not(mask_face)
            return mask_outer
        
        def generate_brow_mask(image_shape, landmarks, indices, scale_x=1.2, scale_y=1.5):
            """
            生成眉毛 mask(扁椭圆 / 拉长)
            """
            mask = np.zeros(image_shape[:2], dtype=np.uint8)
            pts = landmarks[indices].astype(np.int32)
        
            if pts.shape[0] < 3:
                return mask
        
            hull = cv2.convexHull(pts)
        
            # 计算中心
            cx = np.mean(hull[:, 0, 0])
            cy = np.mean(hull[:, 0, 1])
        
            # 缩放 hull(手动仿射)
            scaled = []
            for p in hull[:, 0, :]:
                x = cx + (p[0] - cx) * scale_x
                y = cy + (p[1] - cy) * scale_y
                scaled.append([int(x), int(y)])
        
            scaled = np.array(scaled, np.int32)
            cv2.fillConvexPoly(mask, scaled, 255)
            return mask
        
        def process_single_image(image_path, facer, output_dir="output"):
            """
            处理单张图片的主流程。
            """
            # 1. 读取图片并运行关键点检测
            image = cv2.imread(image_path)
            result = facer.run(image)
            # 假设只处理检测到的第一张脸
            if len(result) == 0:
                print(f"未检测到人脸: {image_path}")
                return
            landmarks = result[0]['kps']  # 形状应为 (98, 2)
        
            # 2. 定义各部位的关键点索引 (需根据你的98点模型调整)
            # 以下索引为示例,请务必根据你的模型定义进行核对和修改
            PARTS_INDEX = {
                "Face_Outline": list(range(0, 32)),  # 脸部轮廓示例索引
                "Left_Eye": list(range(60, 68)),  # 左眼
                "Right_Eye": list(range(68, 76)),  # 右眼
                "Nose": list(range(51, 60)),  # 鼻子
                "Mouth": list(range(76, 96)),  # 嘴巴
                "Left_Brow" : list(range(33, 41)),
                "Right_Brow" : list(range(42, 50))
                # 你可以根据需要添加更多部位,如眉毛: list(range(33, 51))
            }
        
            # 3. 为每个部位生成遮罩
            masks = {}
            for part_name, indices in PARTS_INDEX.items():
        
                if part_name == "Face_Outline":
                    mask = generate_face_outer_mask(image.shape, landmarks, indices)
        
                elif part_name in ["Left_Eye", "Right_Eye"]:
                    mask = generate_eye_ellipse_mask(image.shape, landmarks, indices)
                elif part_name in ["Left_Brow", "Right_Brow"]:
                    mask = generate_brow_mask(image.shape, landmarks, indices)
                else:
                    mask = generate_part_mask(image.shape, landmarks, indices)
        
                masks[part_name] = mask
                # 可选:保存每个部位的遮罩为PNG以供检查
                # cv2.imwrite(os.path.join(output_dir, f"{part_name}.png"), mask)
        
            # 4. 生成PSD
            os.makedirs(output_dir, exist_ok=True)
            base_name = os.path.splitext(os.path.basename(image_path))[0]
            psd_path = os.path.join(output_dir, f"{base_name}_layers.psd")
            masks_to_psd(image_path, masks, psd_path)
        
        
        if __name__ == "__main__":
            # 初始化你的关键点检测器
            facer = FaceAna()
        
            image_path = r"D:project_2025live2dtalking-head-anime-4-demo-maindemodataimageslambda_02.png"
            process_single_image(image_path, facer, output_dir="psd_output")
        
        

        以上为个人经验,希望能给大家一个参考,也希望大家多多支持风君子博客。

        您可能感兴趣的文章:

        • Python通过psd-tools解析PSD文件的实现
        • Python通过psd-tools解析PSD文件

        站内搜索