Nodes/comfyui-jz/jz Seam Carve
ComfyUI Node

jz Seam Carve

Resize without stretching the subject

By j-zhang19·Created about a month ago·Updated 6 days ago· 2
jz Seam Carve
  • image
  • protect_mask
  • remove_mask
  • IMAGE
target_width0
target_height0
energyforward
use_lumatrue

Regular resizing has exactly two tools: scale (which squishes your subject) and crop (which cuts it off). jz Seam Carve is the third option: content-aware resize that removes or inserts "low-energy" paths through the image - seams - so you can change the dimensions while the important stuff barely moves. If you've ever seen a photo narrowed to fit a layout without the people in it looking like they were run through a pasta machine, that's seam carving doing its thing (Avidan-Shamir, the classic 2007 method, with the forward-energy refinement). This node brings it into ComfyUI as a first-class image op.

It's not a replacement for an upscaler - it won't add detail, and the README is upfront that carving through flat uniform regions (a plain sky, an empty wall) is exactly where the algorithm cuts, because there's no visual energy to preserve there. The node gives you masks to fight that: protect_mask says "seams must avoid these pixels," remove_mask says "eat these pixels first." That's the difference between using this successfully and using it once.

The inputs that matter

  • target_width / target_height - the size you want. 0 means "keep this dimension." Smaller carves (removes seams), larger inserts (adds seams), and you can do width and height independently. Range goes to 16384.
  • energy - forward (default) or backward. Forward energy judges seams by the edges they'd create, which tends to look cleaner; backward uses the classic gradient-magnitude criterion. Start with forward; switch if you see artifacts.
  • use_luma - energy computed on BT.601 luma (default) instead of per-channel RGB gradients. Luma is usually the right call; RGB can pick up color edges you don't care about.
  • protect_mask / remove_mask (optional) - the safety valves, described above. To fully remove an object, the README's advice: carve at least the object's width, then enlarge back to your target. The seams will eat the masked region first.

The single output is the resized IMAGE. Batches carve in parallel, and if you've got numba installed the node JIT-compiles its DP routine for a large speedup - it's fully optional, it just makes big carves tolerable.

Why you'd reach for it

Fitting a generated image into a fixed aspect slot (a cover, a banner) without cropping the subject; tightening a composition by shaving width; or extending a background by inserting content-aware seams instead of plain edge padding. Where an upscaler adds fake detail, this reallocates real pixels - genuinely different failure modes.

Installing it

Same pack, same clone:

cd ComfyUI/custom_nodes
git clone https://github.com/j-zhang19/comfyui-jz

Restart ComfyUI (or Manager → search "comfyui-jz"), find it under jz/image. Core deps are the pack's usual requests, pillow, numpy; numba is optional but recommended if you'll carve large images. No model downloads, no GPU requirement.

Common issues

The number-one gotcha is exactly what the README warns about: forward energy carves through flat uniform regions, so a sky-heavy image can lose sky instead of subject. Protect the subject with a mask when it matters. Second: enlarging a lot at once degrades toward plain scaling - the node handles this internally by doing enlargement in passes capped at 50% per pass, so large targets are slow, not wrong. And mask sizing: protect/remove masks must match the image dimensions or you'll get a mismatch error. Finally, don't expect detail where there was none - this reuses pixels, it doesn't invent them.

Personal-pack caveat as always: solo author, zero community footprint (no reddit threads on this node at all), README as documentation. Seam carving in ComfyUI is rare enough that you're early - which means you're also the one debugging it.

Categoryjz/image

Inputs (7)

NameTypeDefaultDescription
imageIMAGE
target_widthINT00–163840 = keep width; smaller carves, larger inserts
target_heightINT00–163840 = keep height
energyCOMBOforward2 options: forward, backward
use_lumaBOOLEANtrueenergy on BT.601 luma (off = RGB gradients)
protect_maskoptMASKseams avoid these pixels
remove_maskoptMASKseams eat these pixels first (carve at least the object's width)

Outputs (1)

NameTypeDescription
IMAGEIMAGE