当前位置: 代码网 > it编程>前端脚本>Python > python生成psd文件实例

python生成psd文件实例

2026年01月17日 Python 我要评论
python生成psd文件多个图层,方便ps打开编辑gen_psd.pyfrom pil import imagefrom psd_tools import psdimagefrom psd_tool

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_2025\live2d\talking-head-anime-4-demo-main\demo\character_model\character.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_2025\live2d\talking-head-anime-4-demo-main\demo\data\images\lambda_02_face_mask.png",
        r"d:\project_2025\live2d\talking-head-anime-4-demo-main\demo\data\images\lambda_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_2025\live2d\talking-head-anime-4-demo-main\demo\data\images\lambda_02.png"
    process_single_image(image_path, facer, output_dir="psd_output")

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com