Nodes/ComfyUI CV/cv2.cartToPolar
ComfyUI Node

cv2.cartToPolar

Turn 'how much left and how much down' into 'how far and which way'

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.cartToPolar
  • x
  • y
  • magnitude
  • angle
◄angleInDegreesfalse►

Two arrays of numbers in, magnitude and angle out. Per pixel: magnitude = sqrt(x² + y²), angle = atan2(y, x). It's the last step of a gradient computation, or of a dense optical flow field, and it's the step that turns a pair of "how much in each direction" images into something you can threshold, colour, or reason about.

It's a raw wrapper in comfyui_cv - the pack of ~470 cv2.* nodes - and it's a pure array operation: no images required, no visualisation, and the outputs aren't displayable until you convert them.

Why the pair matters more than the sum

A gradient or a flow field arrives as two channels, and two channels are awkward. You can't threshold "when the image changes" on (dx, dy) directly - a strong edge going right and a strong edge going down are the same strength but opposite signs in different arrays. Convert and you get two clean, independent questions:

  • magnitude - how strong. Threshold this for a motion mask, a gradient-strength map, an "is this region changing" field. This is the output people actually use.
  • angle - which direction. This is hue, or an arrow's orientation, or "is the motion leftward". Less used, occasionally the whole point.

The pack has curated nodes on top of this for the visual case - CV Flow To Color renders a flow field's angle as an HSV colour wheel, CV Draw Flow Grid draws arrows, CV Flow Map adds a flow field to a map image. If you want to look at flow, use those. cartToPolar is for when you want the numbers.

Inputs and outputs

  • x (required) - the x components. Single- or double-precision float only; OpenCV is explicit about that, and an integer array is rejected.
  • y (required) - the y components, same size and type.
  • angleInDegrees (optional, default false) - radians (0 to 2π) or degrees (0 to 360). Default stays in radians.

Two NPARRAY outputs: magnitude and angle.

Getting x and y from a flow field is the one plumbing step you'll need. A dense flow array is [H, W, 2], so pull the channels apart with the pack's cv2.extractChannel (coi 0 and 1). From a pair of Sobel images you already have them as separate arrays; just remember Sobel's output in this pack is NPARRAY, not IMAGE, which matches what this node wants.

Where do the outputs go? Preview CV Array (with its normalize/heatmap modes) or CV Array → Image to look at them, cv2.compare or cv2.threshold to cut a magnitude into a mask, CV Array → Mask to land it on a mask socket. And note the convention thing, because it will confuse you once: image coordinates put y downward, so an angle of 90° means "toward the bottom of the frame". The maths is correct and the picture looks upside down compared to how you're picturing it.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv

Restart, or install through ComfyUI Manager (search "comfyui_cv"). Python ≥ 3.12, a recent ComfyUI on the V3 node API, and one real dependency:

pip install "opencv-contrib-python-headless~=5.0.0.93"

No models; nothing to download.

Common issues

cv2 rejects the inputs. They must be float32 or float64. Arrays straight from an IMAGE conversion are uint8; Sobel with ddepth=CV_32F or a flow field is the correct provenance.

The magnitude map looks black or blown out. Magnitudes from a real flow field or an unscaled Sobel can run into the hundreds or thousands, and a viewer expecting 0–255 will show you nothing useful. Normalise it - Preview CV Array's normalize mode does this for you, or use cv2.normalize.

You tried to average two angles and got nonsense. Inherent to the representation, not the node: angles wrap, so 359° and 1° average to 180°, which is exactly backwards. Average the vectors, or the magnitudes, and derive the angle last.

"Sizes of input arguments do not match." x and y have to be the identical shape. Mixing a cropped magnitude with a full-frame derivative is the usual cause.

Categoryimage/CV/low-level/cv2 C

Inputs (3)

NameTypeDefaultDescription
xNPARRAY,IMAGE,MASKarray of x-coordinates; this must be a single-precision or double-precision floating-point array. 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.
yNPARRAY,IMAGE,MASKarray of y-coordinates, that must have the same size and same type as x. 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.
angleInDegreesoptBOOLEANfalsea flag, indicating whether the angles are measured in radians (which is by default), or in degrees. Preset to the OpenCV default (False).

Outputs (2)

NameTypeDescription
magnitudeNPARRAY—
angleNPARRAY—