LTX Cleanplate for VFX
Prompt an object, and SAM3 + LTX 2.3 mask-conditioned inpainting remove it and rebuild the clean background plate."
查看工作流内部
源模板的只读预览。在 Cloud 中打开,即可查看节点并进行修改。
Loading the graph
Open full-size workflow preview- 输出
- 视频
- 作者
- ComfyUI
从代码中调用该模型
以下请求使用与体验区相同的预设图和设置。每次提交都可能开始一次付费运行;如果提交结果未知,请勿自动重试。
What you need
- Runs on
- Comfy Cloud
- 密钥
- COMFY_API_KEY
- 你的文件
- 由代码根据链接上传
需要付费的 Cloud 方案和额度。
# Python 3.10+: pip install comfy-sdk==0.4.0
import os
from comfy_sdk import Comfy
api_key = os.environ.get("COMFY_API_KEY", "").strip()
if not api_key: raise RuntimeError("Set COMFY_API_KEY")
os.environ.setdefault("COMFY_BASE_URL", "https://cloud.comfy.org")
client = Comfy(api_key=api_key)
workflow = client.workflows.from_json({
"52": {
"class_type": "SaveVideo",
"inputs": {
"codec": "auto",
"filename_prefix": "cleanplate_compare",
"format": "auto",
"format.codec": "auto",
"video": [
"54:31",
0
]
},
"_meta": {
"title": "Save Video Compared"
}
},
"53": {
"class_type": "SaveVideo",
"inputs": {
"codec": "auto",
"filename_prefix": "cleanplate_ltx_inpaint",
"format": "auto",
"format.codec": "auto",
"video": [
"54:36",
0
]
},
"_meta": {
"title": "Save Video"
}
},
"58": {
"class_type": "GetVideoComponents",
"inputs": {
"video": [
"117",
0
]
},
"_meta": {
"title": "Plate frames"
}
},
"59": {
"class_type": "GetVideoComponents",
"inputs": {
"video": [
"54:36",
0
]
},
"_meta": {
"title": "LTX inpaint frames"
}
},
"63": {
"class_type": "VHS_GetImageCount",
"inputs": {
"images": [
"58",
0
]
},
"_meta": {
"title": "n"
}
},
"64": {
"class_type": "ComfyMathExpression",
"inputs": {
"expression": "(int((a - 1) / 8)) * 8 + 1",
"values.a": [
"63",
0
]
},
"_meta": {
"title": "L = valid LTX length"
}
},
"65": {
"class_type": "GetImageRangeFromBatch",
"inputs": {
"images": [
"58",
0
],
"num_frames": [
"64",
1
],
"start_index": 0
},
"_meta": {
"title": "Trim plate to L"
}
},
"66": {
"class_type": "LTXVDilateVideoMask",
"inputs": {
"mask": [
"73",
0
],
"spatial_radius": 10,
"temporal_radius": 1
},
"_meta": {
"title": "Dilate matte"
}
},
"67": {
"class_type": "GrowMaskWithBlur",
"inputs": {
"blur_radius": 4,
"decay_factor": 1,
"expand": 0,
"fill_holes": False,
"flip_input": False,
"incremental_expandrate": 0,
"lerp_alpha": 1,
"mask": [
"66",
0
],
"tapered_corners": True
},
"_meta": {
"title": "Feather"
}
},
"68": {
"class_type": "LTXVInpaintPreprocess",
"inputs": {
"images": [
"65",
0
],
"mask": [
"67",
0
]
},
"_meta": {
"title": "Green-fill masked region"
}
},
"69": {
"class_type": "CreateVideo",
"inputs": {
"bit_depth": 8,
"codec": "none",
"color_space": "sRGB",
"fps": [
"58",
2
],
"images": [
"68",
0
]
},
"_meta": {
"title": "-> subgraph guide"
}
},
"70": {
"class_type": "LoadSAM3Model",
"inputs": {
"model_path": "models/sam3/sam3.pt"
},
"_meta": {
"title": "(down)Load SAM3 Model"
}
},
"71": {
"class_type": "SAM3VideoSegmentation",
"inputs": {
"frame_idx": 0,
"prompt_mode": "text",
"score_threshold": 0.3,
"text_prompt": [
"130",
0
],
"video_frames": [
"65",
0
]
},
"_meta": {
"title": "SAM3 (object prompt)"
}
},
"72": {
"class_type": "SAM3Propagate",
"inputs": {
"direction": "both",
"end_frame": -1,
"offload_model": False,
"sam3_model": [
"70",
0
],
"start_frame": 0,
"video_state": [
"71",
0
]
},
"_meta": {
"title": "SAM3 Propagate"
}
},
"73": {
"class_type": "SAM3VideoOutput",
"inputs": {
"masks": [
"72",
0
],
"obj_id": -1,
"plot_all_masks": True,
"scores": [
"72",
1
],
"video_state": [
"72",
2
]
},
"_meta": {
"title": "SAM3 Video Output"
}
},
"75": {
"class_type": "MaskToImage",
"inputs": {
"mask": [
"67",
0
]
},
"_meta": {
"title": "Convert Mask to Image"
}
},
"76": {
"class_type": "CreateVideo",
"inputs": {
"bit_depth": 8,
"codec": "none",
"color_space": "sRGB",
"fps": [
"58",
2
],
"images": [
"75",
0
]
},
"_meta": {
"title": "Create Video"
}
},
"77": {
"class_type": "SaveVideo",
"inputs": {
"codec": "auto",
"filename_prefix": "cleanplate_matte",
"format": "auto",
"format.codec": "auto",
"video": [
"76",
0
]
},
"_meta": {
"title": "Save Matte (Nuke)"
}
},
"116": {
"class_type": "VHS_LoadVideo",
"inputs": {
"custom_height": 0,
"custom_width": 0,
"force_rate": 0,
"format": "LTXV",
"frame_load_cap": 0,
"select_every_nth": 1,
"skip_first_frames": 0,
"video": "UPLOADED_video_FILENAME"
},
"_meta": {
"title": "Load Video (Upload) 🎥🅥🅗🅢"
}
},
"117": {
"class_type": "CreateVideo",
"inputs": {
"audio": [
"116",
2
],
"bit_depth": 8,
"codec": "none",
"color_space": "sRGB",
"fps": [
"118",
0
],
"images": [
"116",
0
]
},
"_meta": {
"title": "Create Video"
}
},
"118": {
"class_type": "VHS_VideoInfo",
"inputs": {
"video_info": [
"116",
3
]
},
"_meta": {
"title": "Video Info 🎥🅥🅗🅢"
}
},
"130": {
"class_type": "PrimitiveString",
"inputs": {
"value": "cart"
},
"_meta": {
"title": "What do you want to remove?"
}
},
"133": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"134",
0
]
},
"_meta": {
"title": "Final prompt"
}
},
"134": {
"class_type": "StringConcatenate",
"inputs": {
"delimiter": " ",
"string_a": [
"135",
0
],
"string_b": "removed"
},
"_meta": {
"title": "+ suffix"
}
},
"135": {
"class_type": "StringConcatenate",
"inputs": {
"delimiter": " ",
"string_a": "background plate, the scene with the",
"string_b": [
"130",
0
]
},
"_meta": {
"title": "prefix + object"
}
},
"54:1": {
"class_type": "VAELoaderKJ",
"inputs": {
"device": "main_device",
"vae_name": "LTX23_video_vae_bf16.safetensors",
"weight_dtype": "bf16"
},
"_meta": {
"title": "VAELoader KJ"
}
},
"54:10": {
"class_type": "EmptyLTXVLatentVideo",
"inputs": {
"batch_size": 1,
"height": [
"54:6",
1
],
"length": [
"54:45",
1
],
"width": [
"54:6",
0
]
},
"_meta": {
"title": "Empty LTXV Latent Video"
}
},
"54:11": {
"class_type": "LTXVConditioning",
"inputs": {
"frame_rate": [
"54:49",
0
],
"negative": [
"54:22",
0
],
"positive": [
"54:9",
0
]
},
"_meta": {
"title": "LTXVConditioning"
}
},
"54:12": {
"class_type": "LTXAddVideoICLoRAGuide",
"inputs": {
"crop": "disabled",
"frame_idx": 0,
"image": [
"54:41",
0
],
"latent": [
"54:10",
0
],
"latent_downscale_factor": 1,
"negative": [
"54:11",
1
],
"positive": [
"54:11",
0
],
"strength": 1,
"tile_frames": 97,
"tile_overlap": 64,
"tile_size": 256,
"use_streaming": False,
"use_tiled_encode": False,
"vae": [
"54:1",
0
]
},
"_meta": {
"title": "🅛🅣🅧 Add Video IC-LoRA Guide"
}
},
"54:126": {
"class_type": "ComfyNumberConvert",
"inputs": {
"value": [
"58",
2
]
},
"_meta": {
"title": "Convert Number"
}
},
"54:13": {
"class_type": "LTXVAudioVAEDecode",
"inputs": {
"audio_vae": [
"54:2",
0
],
"samples": [
"54:18",
1
]
},
"_meta": {
"title": "LTXV Audio VAE Decode"
}
},
"54:14": {
"class_type": "LoraLoaderModelOnly",
"inputs": {
"lora_name": "ltx-2.3-22b-distilled-lora-384-1.1.safetensors",
"model": [
"54:15",
0
],
"strength_model": 0.4
},
"_meta": {
"title": "Load LoRA"
}
},
"54:15": {
"class_type": "LoraLoaderModelOnly",
"inputs": {
"lora_name": "ltx-2.3-22b-ic-lora-in-outpainting-0.9.safetensors",
"model": [
"54:5",
0
],
"strength_model": 1
},
"_meta": {
"title": "Load LoRA"
}
},
"54:16": {
"class_type": "VAEDecode",
"inputs": {
"samples": [
"54:17",
2
],
"vae": [
"54:1",
0
]
},
"_meta": {
"title": "VAE Decode"
}
},
"54:17": {
"class_type": "LTXVCropGuides",
"inputs": {
"latent": [
"54:18",
0
],
"negative": [
"54:12",
1
],
"positive": [
"54:12",
0
]
},
"_meta": {
"title": "LTXVCropGuides"
}
},
"54:18": {
"class_type": "LTXVSeparateAVLatent",
"inputs": {
"av_latent": [
"54:19",
0
]
},
"_meta": {
"title": "Separate AV Latent"
}
},
"54:19": {
"class_type": "KSampler",
"inputs": {
"cfg": 1,
"denoise": 1,
"latent_image": [
"54:20",
0
],
"model": [
"54:14",
0
],
"negative": [
"54:12",
1
],
"positive": [
"54:12",
0
],
"sampler_name": "euler_ancestral_cfg_pp",
"scheduler": "linear_quadratic",
"seed": 511332212712579,
"steps": 8
},
"_meta": {
"title": "KSampler"
}
},
"54:2": {
"class_type": "VAELoaderKJ",
"inputs": {
"device": "main_device",
"vae_name": "LTX23_audio_vae_bf16.safetensors",
"weight_dtype": "bf16"
},
"_meta": {
"title": "VAELoader KJ"
}
},
"54:20": {
"class_type": "LTXVConcatAVLatent",
"inputs": {
"audio_latent": [
"54:21",
0
],
"video_latent": [
"54:12",
2
]
},
"_meta": {
"title": "Concat AV Latent"
}
},
"54:21": {
"class_type": "LTXVEmptyLatentAudio",
"inputs": {
"audio_vae": [
"54:2",
0
],
"batch_size": 1,
"frame_rate": [
"54:50",
0
],
"frames_number": [
"54:45",
1
]
},
"_meta": {
"title": "Empty LTXV Latent Audio"
}
},
"54:22": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"54:4",
0
],
"text": "blurry, low resolution, ugly, garbled mess, compression artifacts, glitch, stop motion, still image, pixelated, robotic voice, oversaturated"
},
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"54:25": {
"class_type": "ImageFromBatch",
"inputs": {
"batch_index": 0,
"image": [
"54:41",
0
],
"length": 1
},
"_meta": {
"title": "Get Image from Batch"
}
},
"54:26": {
"class_type": "ImageStitch",
"inputs": {
"direction": "down",
"image1": [
"54:41",
0
],
"image2": [
"54:16",
0
],
"match_image_size": True,
"spacing_color": "white",
"spacing_width": 0
},
"_meta": {
"title": "Stitch Images"
}
},
"54:3": {
"class_type": "VHS_GetImageCount",
"inputs": {
"images": [
"54:38",
0
]
},
"_meta": {
"title": "Get Image Count 🎥🅥🅗🅢"
}
},
"54:31": {
"class_type": "CreateVideo",
"inputs": {
"bit_depth": 8,
"codec": "none",
"color_space": "sRGB",
"fps": [
"54:49",
0
],
"images": [
"54:26",
0
]
},
"_meta": {
"title": "Create Video"
}
},
"54:36": {
"class_type": "CreateVideo",
"inputs": {
"audio": [
"54:38",
1
],
"bit_depth": 8,
"codec": "none",
"color_space": "sRGB",
"fps": [
"54:49",
0
],
"images": [
"54:16",
0
]
},
"_meta": {
"title": "Create Video"
}
},
"54:38": {
"class_type": "GetVideoComponents",
"inputs": {
"video": [
"69",
0
]
},
"_meta": {
"title": "Get Video Components"
}
},
"54:4": {
"class_type": "DualCLIPLoader",
"inputs": {
"clip_name1": "gemma_3_12B_it_fp4_mixed.safetensors",
"clip_name2": "ltx-2.3_text_projection_bf16.safetensors",
"device": "default",
"type": "ltxv"
},
"_meta": {
"title": "Load CLIP (Dual)"
}
},
"54:41": {
"class_type": "ResizeImageMaskNode",
"inputs": {
"input": [
"54:38",
0
],
"resize_type": "scale dimensions",
"resize_type.crop": "disabled",
"resize_type.height": [
"118",
4
],
"resize_type.width": [
"118",
3
],
"scale_method": "area"
},
"_meta": {
"title": "Resize Image/Mask (s1 size)"
}
},
"54:43": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"54:45",
1
]
},
"_meta": {
"title": "Preview as Text"
}
},
"54:45": {
"class_type": "ComfyMathExpression",
"inputs": {
"expression": "(int((a - 1) / 8)) * 8 + 1",
"values.a": [
"54:3",
0
]
},
"_meta": {
"title": "Math Expression"
}
},
"54:49": {
"class_type": "ComfyNumberConvert",
"inputs": {
"value": [
"54:50",
0
]
},
"_meta": {
"title": "Convert Number"
}
},
"54:5": {
"class_type": "UNETLoader",
"inputs": {
"unet_name": "ltx-2.3-22b-dev_transformer_only_bf16.safetensors",
"weight_dtype": "default"
},
"_meta": {
"title": "Load Diffusion Model"
}
},
"54:50": {
"class_type": "PrimitiveInt",
"inputs": {
"value": [
"54:126",
1
]
},
"_meta": {
"title": "fps"
}
},
"54:6": {
"class_type": "GetImageSize",
"inputs": {
"image": [
"54:25",
0
]
},
"_meta": {
"title": "Get Image Size"
}
},
"54:9": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"54:4",
0
],
"text": [
"133",
0
]
},
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
}
})
workflow.set_input("116", "video", client.assets.from_url("https://comfy.org/catalog-media/9c45ce1c-1805-4be7-ac67-11f7bb6d02fa/40969461-d6a9-41e2-9e20-eb8d27b27314"))
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)
for output in job.get_outputs("53"):
output.to_file(output.name)
for output in job.get_outputs("52"):
output.to_file(output.name)
for output in job.get_outputs("77"):
output.to_file(output.name)试试一个示例
关于此工作流
This ComfyUI workflow builds a clean background plate by removing an object from video using SAM3-driven masks and a mask-conditioned LTX-2.3 In‑Outpainting IC‑LoRA. The pipeline loads your clip with VHS_LoadVideo/VHS_VideoInfo, extracts frames via GetVideoComponents, and uses LoadSAM3Model → SAM3VideoSegmentation to seed a mask for the object you want to remove. SAM3Propagate tracks that mask across the shot, and SAM3VideoOutput provides a per‑frame OBJECT_MASK. To ensure seamless fills, LTXVDilateVideoMask expands the mask (e.g., s10/t1) and GrowMaskWithBlur feathers the edges.
The masked region is then green‑filled by LTXVInpaintPreprocess, and CreateVideo re‑encodes those preprocessed frames. That green plate, together with the OBJECT_MASK and your minimal background‑only prompt, feeds the LTX 2.3 In‑Outpainting IC‑LoRA (packaged here as a subgraph node), which is explicitly mask‑conditioned to generate only inside the masked area. Utility nodes like VHS_GetImageCount, ComfyMathExpression, and GetImageRangeFromBatch let you preview limited frame ranges before a full run. Finally, SaveVideo writes the cleanplate result for downstream compositing.
常见问答
Keep it empty or describe only the background inside the masked area (e.g., “asphalt road with painted lines, soft shadow”). Avoid mentioning the removed object or unrelated foreground items—this can cause duplication or hallucinations.
Increase LTXVDilateVideoMask size to cover motion blur and expand beyond the object, then raise GrowMaskWithBlur feather radius to soften transitions. Also re‑seed SAM3 on a clearer frame and re‑propagate if the tracked mask drifts.
Yes. Use VHS_GetImageCount to see the total frames and GetImageRangeFromBatch (optionally with ComfyMathExpression) to select a small frame window for quick iterations, then switch back to the full range once satisfied.
SaveVideo typically outputs a silent file. If you need audio, re‑mux the original track in your NLE or a tool like ffmpeg. If your setup routes audio via GetVideoComponents, you can also handle pass‑through externally after render.