Nodes/ComfyUI CV/cv2.phase
ComfyUI Node

cv2.phase

The angle of a vector field, when you only have the components

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
cv2.phase
  • x
  • y
  • nparray
◄angleInDegreesfalse►

Feed it an x array and a y array, get back atan2(y, x) for every element. That's the node. It's the sibling of cv2.magnitude (the length) and cv2.cartToPolar (both at once), and it's what you use when a pipeline has already given you flow or gradient components and you need the direction field rather than the displacement.

Two required inputs, x and y, both image-ish (NPARRAY, IMAGE or MASK - with the usual caveat below), and one optional angleInDegrees boolean, preset to false. One output: nparray, the angles. That's the whole API surface.

What it's for in ComfyUI

Direction fields are how you visualise and reason about motion and structure:

  • Optical flow. The pack's dense flow nodes emit (dx, dy) components. phase turns that into an angle map, which is what a hue-wheel visualisation wants - the pack already ships CV Flow To Color for that, and this is the underlying operation if you want to do something of your own with the angles (histogram the dominant motion direction, mask "everything moving left", and so on).
  • Image gradients. Feed Sobel-style derivative fields in as x and y and you get gradient orientation, which is the first step of a lot of structure analysis. CV HOG Features and the corner detectors do this internally; the wrapper is for when you're building something the curated nodes don't cover.
  • Phase from a Fourier transform. The dft wrappers in this pack expose the real/imaginary parts; the "phase" of a frequency-domain array is literally this call on those two planes.

For the common "I have flow, show me the angles" job, use CV Flow To Color. Reach for this node when you want the numbers, not the picture.

The inputs that will bite you

The node's own tooltips describe both inputs as "floating-point arrays", and that is a hard requirement, not a suggestion - cv2's phase computes an arctangent and won't take integers. Meanwhile a ComfyUI IMAGE resolves to an 8-bit BGR array inside this pack. So linking a Load Image output straight into x gives you a uint8 array and an OpenCV assertion, not a nice error message about dtypes.

The path that works:

Image → CV Array            (uint8 BGR, NPARRAY)
      → cv2.cvtColor        (or skip if you already have planes)
      → CV Cast Array       (float32)
      → cv2.phase

CV Cast Array is the node everyone forgets; it's in the pack's IO group, it takes uint8/uint16/int16/int32/float32/float64, and it saturates like cv2.convertTo. For anything downstream of a math wrapper in this pack, assume you need it.

The other requirement, straight from the tooltip: y "must have the same size and the same type as x". No broadcasting, no automatic promotion. If your two component arrays came from different branches, check them with CV Array Shape and CV DType before you start blaming the math.

Degrees or radians

angleInDegrees is false by default and lives behind "show advanced inputs". Radians or degrees changes everything downstream: an angle in radians is roughly -π..π, in degrees roughly -180..180, and if you scale, threshold or feed one into a node expecting the other, you get numbers that are wrong by a factor of 57 and perfectly well-formed. Pick one convention at the top of the graph and note it on the canvas, because ComfyUI's canvas has no types to tell you.

Worth knowing about the range: atan2 returns angles in the half-open interval (-π, π], so "straight up" and "straight down" sit at the two ends of the range. If you're averaging angles or building a histogram, a wrap-around bug is waiting for you there - that's a math problem, not a node problem, but it's the one that catches people.

Output format

nparray, always. This wrapper isn't in the pack's type-preserving list - and deliberately so, because an angle map is not a picture: if the pack echoed an IMAGE here it would run the result through an 8-bit normalisation and quietly destroy any value it didn't scale into 0-255. So the output is a float array on an NPARRAY socket, and if you do want to look at it, that's CV Flow To Color or your own normalise-then-preview, not a direct image echo.

Also: no batch handling. This is one of the wrappers the pack documents as taking "frame 0 of a batch", so a 30-frame IMAGE batch in gives you a 1-frame answer out. Pair frames explicitly if you're working a clip.

Installing

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

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 a rewrite on the V3 node API, and Python 3.12 is a hard floor, not a preference. phase is core cv2, no contrib and no model files needed. Node category: image/CV/low-level/cv2 P.

Categoryimage/CV/low-level/cv2 P

Inputs (3)

NameTypeDefaultDescription
xNPARRAY,IMAGE,MASKinput floating-point array of x-coordinates 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.
yNPARRAY,IMAGE,MASKinput array of y-coordinates of 2D vectors; it must have the same size and the 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.
angleInDegreesoptBOOLEANfalsewhen true, the function calculates the angle in degrees, otherwise, they are measured in radians. Preset to the OpenCV default (False).

Outputs (1)

NameTypeDescription
nparrayNPARRAY—