python生成psd文件實(shí)例
更新時(shí)間:2026年01月17日 09:47:36 作者:AI算法網(wǎng)奇
文章介紹了如何使用Python生成包含多個(gè)圖層的PSD文件,通過腳本`gen_psd.py`實(shí)現(xiàn)關(guān)鍵點(diǎn)分割人臉并生成多圖層效果,作者分享了自己的經(jīng)驗(yàn),希望能為讀者提供參考并支持腳本之家
python生成psd文件
多個(gè)圖層,方便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圖像轉(zhuǎn)換為PSD格式
psd = PSDImage.frompil(image_obj)
# 創(chuàng)建一個(gè)新圖層
pixel_layer = PixelLayer.frompil(image_obj, psd)
pixel_layer.visible = True # 設(shè)置圖層為可見
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)創(chuàng)建多個(gè)圖層
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)
# 第一個(gè)圖層
layer0 = PixelLayer.frompil(base_img, psd)
layer0.name = "Base"
layer0.visible = True
psd.append(layer0)
# 后續(xù)圖片作為新圖層
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")
關(guān)鍵點(diǎn)分割人臉,生成多圖層
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):
"""
根據(jù)關(guān)鍵點(diǎn)索引生成對(duì)應(yīng)部位的二進(jìn)制遮罩。
Args:
image_shape: 原圖尺寸 (H, W)
landmarks: 人臉關(guān)鍵點(diǎn)坐標(biāo)數(shù)組
indices: 特定部位的關(guān)鍵點(diǎn)索引列表
Returns:
mask: 二值化遮罩 (0/255)
"""
mask = np.zeros(image_shape[:2], dtype=np.uint8)
pts = landmarks[indices].astype(np.int32)
# 使用凸包或最小矩形來定義區(qū)域
if len(indices) > 2: # 對(duì)于眼睛、嘴巴等輪廓點(diǎn)
hull = cv2.convexHull(pts)
cv2.fillConvexPoly(mask, hull, 255)
else: # 對(duì)于可能需要矩形定義的部位
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. 讀取基礎(chǔ)圖像作為背景層
base_img = Image.open(base_image_path).convert("RGBA")
# 2. 創(chuàng)建一個(gè)以基礎(chǔ)圖像為畫布的PSD對(duì)象[citation:4][citation:9]
psd = PSDImage.frompil(base_img)
# 3. 為每個(gè)部位創(chuàng)建圖層[citation:4][citation:9]
for layer_name, mask in masks_dict.items():
# 將二值mask (0/255) 轉(zhuǎn)換為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')
# 第一個(gè)圖層
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)
# 反轉(zhuǎn):臉外 = 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)
# 計(jì)算中心
cx = np.mean(hull[:, 0, 0])
cy = np.mean(hull[:, 0, 1])
# 縮放 hull(手動(dòng)仿射)
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. 讀取圖片并運(yùn)行關(guān)鍵點(diǎn)檢測(cè)
image = cv2.imread(image_path)
result = facer.run(image)
# 假設(shè)只處理檢測(cè)到的第一張臉
if len(result) == 0:
print(f"未檢測(cè)到人臉: {image_path}")
return
landmarks = result[0]['kps'] # 形狀應(yīng)為 (98, 2)
# 2. 定義各部位的關(guān)鍵點(diǎn)索引 (需根據(jù)你的98點(diǎn)模型調(diào)整)
# 以下索引為示例,請(qǐng)務(wù)必根據(jù)你的模型定義進(jìn)行核對(duì)和修改
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))
# 你可以根據(jù)需要添加更多部位,如眉毛: list(range(33, 51))
}
# 3. 為每個(gè)部位生成遮罩
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
# 可選:保存每個(gè)部位的遮罩為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__":
# 初始化你的關(guān)鍵點(diǎn)檢測(cè)器
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")
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Pandas?時(shí)間序列分析中的resample函數(shù)
這篇文章主要介紹了Pandas?時(shí)間序列分析中的resample函數(shù),Pandas?中的resample函數(shù)用于各種頻率的轉(zhuǎn)換工作,下面我們就來看看其的參數(shù)、相關(guān)資料等,需要的小伙伴可以參考一下,希望給你帶來幫助2022-02-02
Python類的動(dòng)態(tài)綁定實(shí)現(xiàn)原理
這篇文章主要介紹了Python類的動(dòng)態(tài)綁定實(shí)現(xiàn)原理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
Python代碼實(shí)現(xiàn)為Word文檔加上專業(yè)水印
在日常辦公中,為 Word 文檔添加水印是一項(xiàng)常見需求,本文將介紹如何使用 Spire.Doc for Python 庫,通過簡潔的 Python 代碼輕松為 Word 文檔添加文字水印和圖片水印,有需要的可以了解下2026-03-03
Python?DataFrame處理缺失值的完整指南與實(shí)戰(zhàn)技巧
在數(shù)據(jù)分析工作中,缺失值(Missing?Values)是不可避免的挑戰(zhàn),本文將系統(tǒng)介紹DataFrame缺失值的識(shí)別、處理策略和實(shí)戰(zhàn)技巧,希望對(duì)大家有所幫助2026-02-02
python2爬取百度貼吧指定關(guān)鍵字和圖片代碼實(shí)例
這篇文章主要介紹了python2爬取百度貼吧指定關(guān)鍵字和圖片代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
python實(shí)現(xiàn)RabbitMQ的消息隊(duì)列的示例代碼
這篇文章主要介紹了python實(shí)現(xiàn)RabbitMQ的消息隊(duì)列的示例代碼,總結(jié)了RabbitMQ中三種exchange模式的實(shí)現(xiàn),分別是fanout, direct和topic。感興趣的小伙伴們可以參考一下2018-11-11
Python使用asyncio.Queue進(jìn)行任務(wù)調(diào)度的實(shí)現(xiàn)
本文主要介紹了Python使用asyncio.Queue進(jìn)行任務(wù)調(diào)度的實(shí)現(xiàn),它可以用于任務(wù)調(diào)度和數(shù)據(jù)交換,文中通過示例代碼介紹的非常詳細(xì),感興趣的可以了解一下2024-02-02

