〽️ Image Ops Spherize
Fisheye, barrel, and 360-pano warps — one node, no external tools
- image
- mask
- image
- mask
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:
strengthonly goes 0→2, and 1.0 is "full projection." There's no negative slider - that's whatinvertis 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
maskoutput 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_inputkeeps the source dimensions;customresizes to explicitwidth × heightfirst, 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.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| bypass | BOOLEAN | false | — |
| mode | COMBO | spherize | 5 options: spherize, fisheye, defisheye, latlong, unlatlong |
| strength | FLOAT | 1.000–2 | Effect intensity. 1.0 = full projection. Values > 1 push beyond the normal range. |
| invert | BOOLEAN | false | Invert the mapping direction (e.g. barrel ↔ pincushion, latlong ↔ unlatlong). |
| filter | COMBO | bilinear | 3 options: nearest, bilinear, bicubic |
| edge_mode | COMBO | border | 3 options: border, reflection, zeros |
| size_mode | COMBO | from_input | from_input: use input image dimensions. custom: resize to width × height before applying spherize. |
| width | INT | 51264–8192 | — |
| height | INT | 51264–8192 | — |
| imageopt | IMAGE,VIDEO | Images/Video input. | |
| maskopt | MASK | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| mask | MASK | — |