Nodes/ComfyUI-Majoor-ImageOps/〽️ Image Ops Spherize
ComfyUI Node

〽️ Image Ops Spherize

Fisheye, barrel, and 360-pano warps — one node, no external tools

By MajoorWaldi·Created 8 months ago·Updated 8 days ago· 11
〽️ Image Ops Spherize
  • image
  • mask
  • image
  • mask
bypassfalse
modespherize
strength1.00
invertfalse
filterbilinear
edge_modeborder
size_modefrom_input
width512
height512

Lens distortion is one of those looks that reads instantly. A slight barrel bulge sells a CCTV or drone shot; a proper fisheye sells "action camera"; unwarping real GoPro footage is half the battle of working with it. ImageOps Spherize bundles five lens projections into a single GPU node - spherize, fisheye, defisheye, and the two equirectangular↔rectilinear directions - so you can fake or fix the whole family without leaving the graph or pulling in OpenCV gymnastics.

It's part of the ComfyUI-Majoor-ImageOps pack, which is built batch-first: every node treats IMAGE input as a frame sequence, so this warps all 24 frames of an animation in one pass. That's the differentiator. Core ComfyUI gives you almost nothing for lens distortion, and most solutions you'd find are script-based one-offs; this is a native node with proper per-frame handling, filter quality options, and a mask output.

How it works

The mechanism is a grid_sample remap, which is the compositor-standard way to do this. The node builds a normalized coordinate grid over the output, pushes each coordinate through the chosen projection's math (spherize maps radius through sin(r·π/2); fisheye uses the equidistant θ projection; defisheye runs it in reverse), then samples the source at the warped positions. filter (nearest/bilinear/bicubic) controls resampling quality, and edge_mode (border/reflection/zeros) decides what happens at the frame edges.

The two things worth understanding before you start:

  • strength only goes 0→2, and 1.0 is "full projection." There's no negative slider - that's what invert is for. Flipping it swaps barrel ↔ pincushion, fisheye ↔ defisheye, and latlong ↔ unlatlong. The tooltip spells it out and it's easy to miss.
  • The output mask is a circle. For the disk projections (spherize, fisheye, defisheye), pixels outside the unit circle are rendered black and the mask output is a unit-circle alpha - 1 inside the sphere, 0 outside, multiplied by any input mask you supply. latlong/unlatlong are the exceptions: they fill the whole canvas because they're rectangular projections. That circle matte is your free composite key: multiply it into the warped result to cut the sphere out cleanly over a new background.

Inputs that matter

  • mode - spherize (barrel/pincushion), fisheye, defisheye, latlong (equirectangular→rectilinear, i.e. extract a perspective view from a 360 pano), unlatlong (rectilinear→equirectangular, i.e. project into a pano).
  • strength - intensity; values above 1.0 exaggerate past the "correct" projection.
  • invert - direction swap (see above).
  • size_mode - from_input keeps the source dimensions; custom resizes to explicit width × height first, which is handy for regularizing mixed-size batches before warping.

Outputs

image and mask. The mask is the circle (or full rect for pano modes) - wire it into a merge node's alpha to composite the spherized disk back onto a flat background, which is the classic trick for faking a lens overlay.

Installing it

cd ComfyUI/custom_nodes
git clone https://github.com/MajoorWaldi/ComfyUI-Majoor-ImageOps

Or search "ComfyUI-Majoor-ImageOps" in ComfyUI Manager, restart, and hard-refresh the browser (Ctrl+F5 / Cmd+Shift+R on macOS). No extra pip packages and no model files - it's torch + F.grid_sample, nothing exotic. ComfyUI ≥ 0.13.0.

Where people get burned

The corners. Run spherize at full strength and the image shrinks into a circle with black corners - that's not a bug, that's the projection, and it's exactly why the circle mask exists. If you wanted a border-blurred look instead of hard black, you'll need to composite against something yourself; there's no background-fill option here. And if you're defisheyeing real footage, go easy on strength - real fisheye lenses aren't perfectly equidistant, so 1.0 can overcorrect. Start around 0.7–0.9 and nudge from there.

Categoryimage/imageops

Inputs (11)

NameTypeDefaultDescription
bypassBOOLEANfalse
modeCOMBOspherize5 options: spherize, fisheye, defisheye, latlong, unlatlong
strengthFLOAT1.000–2Effect intensity. 1.0 = full projection. Values > 1 push beyond the normal range.
invertBOOLEANfalseInvert the mapping direction (e.g. barrel ↔ pincushion, latlong ↔ unlatlong).
filterCOMBObilinear3 options: nearest, bilinear, bicubic
edge_modeCOMBOborder3 options: border, reflection, zeros
size_modeCOMBOfrom_inputfrom_input: use input image dimensions. custom: resize to width × height before applying spherize.
widthINT51264–8192
heightINT51264–8192
imageoptIMAGE,VIDEOImages/Video input.
maskoptMASK

Outputs (2)

NameTypeDescription
imageIMAGE
maskMASK