Nodes/ComfyUI CV/cv2.polarToCart
ComfyUI Node

cv2.polarToCart

Angle plus magnitude, back into x and y

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.polarToCart
  • magnitude
  • angle
  • nparray_0
  • nparray_1
◄angleInDegreesfalse►

The inverse of cartToPolar: give it a magnitude array and an angle array and it hands back the x and y components, element-wise. x = magnitude · cos(angle), y = magnitude · sin(angle). Two inputs, two outputs, one optional boolean - the smallest node in this batch, and the one that closes the loop on every polar representation the other nodes produce.

Why it exists in a graph

Polar form is what you get from a lot of measurements, and Cartesian form is what a lot of consumers want:

  • A second look at an angle field. Threshold or smooth the angles and magnitudes separately - filtering direction independently of magnitude is something you can't do to (dx, dy) directly - then rebuild components with this node. The pack's CV Array Statistic, cv2.medianBlur and the arithmetic wrappers all work on each field independently; that's the workflow.
  • Reconstructing flow. cv2.cartToPolar splits a flow field into magnitude and angle (the pack's curated CV Optical Flow (Farneback) node exposes exactly those two as magnitude and angle outputs). This node is the way back, and it's the pairing you'd use to clean or clamp a magnitude field before rebuilding the displacement - then CV Flow Map → cv2.remap to actually warp with it.
  • Unit vectors from angles. Feed in angles and a matching array of ones and you get a direction field with unit length: the sampling kernel for a directional filter, or the geometry behind ray-casting from a point (CV Draw Rays and CV Draw Flow Vectors in the pack's visualisation group draw similar things).

Inputs and outputs

magnitude and angle are the two required inputs, both image-ish: NPARRAY, or an IMAGE/MASK (which the pack converts to an 8-bit array, frame 0 of a batch). The tooltip for angle is the strict one: "input floating-point array of angles of 2D vectors" - float, not 8-bit. Linking a Load Image output straight in gets you uint8 and an OpenCV assertion, so the path through this node starts with CV Cast Array on both sides. If you're splicing in a magnitude that came off a curated node, check CV DType while you're learning rather than after it breaks.

The magnitude tooltip carries a piece of OpenCV lore: "it can be an empty matrix (=Mat()), in this case, the function assumes that all the magnitudes are =1; if it is not empty, it must have the same size and type as angle." Note the second half - same size and type as angle, no broadcasting. The empty-matrix shortcut is awkward to reach through a required socket, but the workaround is genuinely cheap: cv2.divide an array by itself and you've got an array of ones at exactly the right shape, which is the unit-vector case. (Zeros in that array will give you 0/0 = NaN, which is what cv2.patchNaNs is for.)

angleInDegrees is a boolean, false by default, and collapsed behind "show advanced inputs": false means radians, true means degrees. It has to match how your angles were produced. A field built in radians and read as degrees gives you a spiral; a field in degrees read as radians gives you a mess that's mostly one direction. Pick one convention and stick to it across phase, cartToPolar and this node, because nothing in ComfyUI will check.

The two outputs are the auto-generated nparray_0 and nparray_1 - in cv2's return order, x then y. Since the names carry no meaning, comment the canvas or wire one straight into CV Split Point-adjacent plumbing so the next person can tell them apart. Both are NPARRAY: this wrapper isn't in the pack's type-preserving list, and that's correct - these are signed float components, not a picture, and echoing them as an IMAGE would 8-bit-normalise them into garbage.

Things to know

Angles wrap, and there's no arithmetic that knows it. Averaging or smoothing a (-π, π] angle field will produce spikes wherever it wraps from +π to -π. The trick is to smooth the (x, y) pair and convert back to an angle, not to smooth the angle - which is a decent argument for doing your filtering in Cartesian and using this node at the edges.

Frame 0, always. No batch handling in the pure math wrappers; a batch in gives you one frame out. Walk a clip with CV Index Batch if you need per-frame fields.

It's one of a pair. cv2.cartToPolar is the reverse, cv2.magnitude gives length without the angle, cv2.phase gives the angle without the length. If you only need one of the two, those two nodes are less work than this one and a discarded output.

Installing

ComfyUI Manager → search ComfyUI CV → Install → restart, or:

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"

Python ≥ 3.12 and a recent ComfyUI; the pack is built on the V3 node API and generates its raw cv2 wrappers at import time from the functions your OpenCV build exposes. polarToCart is core cv2 - every wheel has it, including the headless contrib wheel the pack declares - and there are no models involved. Search the Add Node menu for cv2.polarToCart or dig into image/CV/low-level/cv2 P.

Categoryimage/CV/low-level/cv2 P

Inputs (3)

NameTypeDefaultDescription
magnitudeNPARRAY,IMAGE,MASKinput floating-point array of magnitudes of 2D vectors; it can be an empty matrix (=Mat()), in this case, the function assumes that all the magnitudes are =1; if it is not empty, it must have the same size and type as angle. Accepts a ComfyUI IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY. Arithmetic ops (add, multiply, etc.) process the full IMAGE batch when both inputs have the same batch size.
angleNPARRAY,IMAGE,MASKinput floating-point array of angles of 2D vectors. Accepts a ComfyUI IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY. Arithmetic ops (add, multiply, etc.) process the full IMAGE batch when both inputs have the same batch size.
angleInDegreesoptBOOLEANfalsewhen true, the input angles are measured in degrees, otherwise, they are measured in radians. Preset to the OpenCV default (False).

Outputs (2)

NameTypeDescription
nparray_0NPARRAY—
nparray_1NPARRAY—