File size: 6,106 Bytes
cd47a59 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | import os
import subprocess
import shutil
import argparse
# ==========================================
# 設定區
# ==========================================
BASE_DIR = "."
# 自動偵測作業系統,決定 Blender 的執行檔路徑
if os.name == 'nt': # Windows 系統 (本機)
BLENDER_EXE = os.path.join(BASE_DIR, "blender-3.6.0-windows-x64", "blender.exe")
else: # Linux 系統 (Hugging Face Docker)
BLENDER_EXE = os.path.join(BASE_DIR, "blender", "blender")
def run_cmd(cmd, cwd=BASE_DIR):
"""印出指令並執行"""
print(f"\n[執行指令]: {' '.join(cmd)}")
env = os.environ.copy()
env['PYTHONPATH'] = BASE_DIR + os.pathsep + env.get('PYTHONPATH', '')
subprocess.run(cmd, cwd=cwd, env=env, check=True)
def main():
parser = argparse.ArgumentParser(description="Process a single video for CHAMP pipeline")
parser.add_argument("--video", type=str, default="input_video/sample.mp4", help="Path to input video")
parser.add_argument("--ref", type=str, default="reference_imgs/images/sample.jpg", help="Path to reference image")
args = parser.parse_args()
INPUT_VIDEO = args.video
REF_IMAGE = args.ref
# ---------------------------------------------------------
# 0. 解析檔案名稱與路徑
# ---------------------------------------------------------
video_basename = os.path.basename(INPUT_VIDEO)
video_name = os.path.splitext(video_basename)[0]
ref_basename = os.path.basename(REF_IMAGE)
ref_name = os.path.splitext(ref_basename)[0]
driving_dir = os.path.join("driving_videos", video_name)
images_dir = os.path.join(driving_dir, "images")
smpl_results_dir = os.path.join(driving_dir, "smpl_results")
# 參考圖的父資料夾 (例如: reference_imgs)
ref_dir = os.path.dirname(os.path.dirname(REF_IMAGE))
ref_npy_path = os.path.join(ref_dir, "smpl_results", f"{ref_name}.npy")
transfer_dir = os.path.join("transferd_result", video_name)
print("==================================================")
print(f"正在處理單一影片: {video_name}")
print(f"使用的參考圖片: {ref_name}")
print("==================================================")
# ---------------------------------------------------------
# 1. 抽取影格 (ffmpeg)
# ---------------------------------------------------------
print("\n[步驟 1] 影片抽幀 (轉換為 24fps)...")
images_abs_path = os.path.join(BASE_DIR, images_dir)
os.makedirs(images_abs_path, exist_ok=True)
out_pattern = os.path.join(images_abs_path, "%04d.png")
if len(os.listdir(images_abs_path)) == 0:
run_cmd([
"ffmpeg", "-y", "-i", INPUT_VIDEO,
"-vf", "fps=24,scale=640:-1",
out_pattern
])
else:
print("影格圖片已存在,跳過抽幀。")
# ---------------------------------------------------------
# 2. 生成 SMPL (fit SMPL)
# ---------------------------------------------------------
print("\n[步驟 2] 為動作影片與參考圖生成 SMPL 骨架...")
smpls_group_path = os.path.join(smpl_results_dir, "smpls_group.npz")
if not os.path.exists(os.path.join(BASE_DIR, smpls_group_path)):
run_cmd([
"python", "-m", "scripts.data_processors.smpl.generate_smpls",
"--reference_imgs_folder", ref_dir,
"--driving_video_path", driving_dir
])
else:
print("smpls_group.npz 已存在,跳過生成。")
# ---------------------------------------------------------
# 3. 平滑化 SMPL (Smooth SMPL)
# ---------------------------------------------------------
print("\n[步驟 3] 使用 Blender 平滑化 SMPL 參數...")
run_cmd([
BLENDER_EXE, "--background",
"--python", "scripts/data_processors/smpl/smooth_smpls.py",
"--",
"--smpls_group_path", smpls_group_path,
"--smoothed_result_path", smpls_group_path
])
# ---------------------------------------------------------
# 4. 轉換 SMPL (Transfer SMPL)
# ---------------------------------------------------------
print("\n[步驟 4] 融合參考圖身型與影片動作 (Transfer SMPL)...")
run_cmd([
"python", "-m", "scripts.data_processors.smpl.smpl_transfer",
"--reference_path", ref_npy_path,
"--driving_path", driving_dir,
"--output_folder", transfer_dir,
"--figure_transfer",
"--view_transfer"
])
# ---------------------------------------------------------
# 5. 渲染條件圖 (Render SMPL via Blender)
# ---------------------------------------------------------
print("\n[步驟 5] 渲染 3D 條件影像 (Depth, Normal, Mask 等)...")
transfer_smpl_results = os.path.join(transfer_dir, "smpl_results")
# 斷點續傳檢查:如果已經有足夠的 depth 圖片就不重跑 Blender
depth_dir = os.path.join(BASE_DIR, transfer_dir, "depth")
skip_blender = False
if os.path.exists(depth_dir) and len(os.listdir(depth_dir)) > 0:
print("渲染圖片似乎已存在,Blender 將會自動跳過已完成的部分。")
run_cmd([
BLENDER_EXE, "scripts/data_processors/smpl/blend/smpl_rendering.blend",
"--background",
"--python", "scripts/data_processors/smpl/render_condition_maps.py",
"--",
"--driving_path", transfer_smpl_results,
"--reference_path", REF_IMAGE,
"--device", "0"
])
# ---------------------------------------------------------
# 6. 生成 DWPose 骨架圖
# ---------------------------------------------------------
print("\n[步驟 6] 生成 DWPose 2D 骨架特徵圖...")
transfer_normal = os.path.join(transfer_dir, "normal")
transfer_dwpose = os.path.join(transfer_dir, "dwpose")
run_cmd([
"python", "-m", "scripts.data_processors.dwpose.generate_dwpose",
"--input", transfer_normal,
"--output", transfer_dwpose
])
print("\n 完成 motions 轉換")
if __name__ == "__main__":
main()
|