Roop Batch Image Folder
Swap one face across a whole folder of images
- source_image
The plain swap node is fine for a single image. Now imagine fifty, or five hundred - a cast of characters you want to re-face, a dataset you're building, a photo shoot you're normalizing. Doing that by hand, one node at a time, is miserable. This node takes one source image and runs the swap against every .jpg and .png in a folder, writing the results out to another folder.
This is the least glamorous node in the pack and arguably the most useful if your work is actually repetitive. It's also the one with the most "read the README first" energy, because everything it does is path-based.
What it does
It saves your source tensor, globs the input folder for *.jpg and *.png, then runs roop's run.py once per image - same CLI wrapper as the basic node, just looped. Each result lands in the output folder as out_<original_filename> so nothing collides and nothing overwrites. There's no output tensor; the node is a side-effect machine. When it's done, your files are just there.
The inputs that matter
- source_image - the face you want everywhere.
- input_dir - folder of images to swap. Absolute path, and it's read at execution time: drop new files in, hit run, done.
- output_dir - where results go. The node creates it if missing.
- use_enhancer - true adds the face enhancer pass to each image (the same trade-off as the enhancer node: slower, smoother, occasionally waxy).
- many_faces - swap every face in each image rather than just the first detected.
- roop_dir - your roop checkout. Default
/content/roop; update it or nothing runs.
Gotchas that will bite you
- It only reads the top level of the folder. No subdirectories, and only
.jpg/.png- no.jpeg, no.webp, no.bmp. Convert first or the node silently ignores them. - NSFW filter drops images without telling you. roop's safety filter can refuse a frame and produce no output; the node logs
[Skipped] NSFW or error: <file>to the console and moves on. If your output folder has fewer files than your input folder, this is why - check the log before assuming a crash. - It's one subprocess per image. There's no batching, no GPU pipelining, so a large folder is slow. Each image pays the full roop startup cost. Don't queue five hundred images and walk away expecting a quick result.
- Same shared traps as the rest of the pack: the bare
pythoncall resolves to whatever's on your PATH, CUDA is mandatory, and the first run still downloads the inswapper model.
A practical note on paths
Because every path is a plain string, this node is genuinely happy living on a remote box - a Colab, a cloud VM - where it can crunch a mounted folder and dump results somewhere you can grab them. On a local Windows install, absolute paths like C:/data/faces are fine; just don't leave the defaults (/input/images, /output/images), which assume a Linux container root.
If you're doing this locally and often, one folder-in/folder-out tool is usually enough. But if your pipeline needs the results somewhere else - a server, an API, a Discord bot - pair it with the pack's webhook nodes (RoopSendWebhookImage or RoopSendWebhookFile) to push the finished folder's contents off-box instead of hunting for them.
Install is the same as every node in this pack: clone the repo into custom_nodes, restart ComfyUI, and point roop_dir at a real roop checkout.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| source_image | IMAGE | — | |
| input_dir | STRING | /input/images | — |
| output_dir | STRING | /output/images | — |
| roop_dir | STRING | /content/roop | — |
| use_enhancer | BOOLEAN | false | — |
| many_faces | BOOLEAN | false | — |
Outputs (0)
No outputs