Nodes/ComfyUI CV/cv2.convertPointsFromHomogeneous
ComfyUI Node

cv2.convertPointsFromHomogeneous

Get real pixels back out of homogeneous maths

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.convertPointsFromHomogeneous
  • src
  • nparray
◄dtypesame as input►

The half of projective geometry nobody enjoys

Homogeneous coordinates are how projective maths works: a 2D point becomes (x, y, 1), a 3D point becomes (x, y, z, 1), and a homography or a fundamental matrix can act on them by plain matrix multiplication. The catch is that the result is also homogeneous, and its last component is generally not 1. Until you divide through by it, you're holding coordinates in a space where your point isn't anywhere recognisable.

cv2.convertPointsFromHomogeneous does that division. For each point (x1, x2, …, xn) it returns (x1/xn, x2/xn, …, x(n-1)/xn) - perspective projection, one line of arithmetic, absolutely essential. It's the step everyone forgets when they first apply a homography by hand to a point set.

It's a raw wrapper from ComfyUI CV (bmad4ever/comfyui_cv), category image/CV/low-level/cv2 C. Its mirror image is cv2.convertPointsToHomogeneous, which appends the 1 in the first place.

How it works

Input is an N-dimensional point vector in homogeneous form; output is the same points projected back to Euclidean space. The dtype widget controls the output depth, and its default is "same as input" - which is the author's modelling of OpenCV's -1 sentinel, meaning "pick CV_32F or CV_64F to match the input". Leave it there unless you have a reason.

One behaviour to know about: when the last component is zero, the output coordinates are zeros ((0, 0, 0, …)), not infinities or an error. That's the correct limit for a point at infinity, but in practice it means a degenerate input silently produces points sitting at the origin. If your point cloud suddenly has a clump at (0,0), that's the fingerprint.

Inputs and outputs that matter

  • src - required, and NPARRAY only. The tooltip says it flatly: this is a data array (points / matrix), not an image, so an IMAGE or MASK link is rejected.
  • dtype - optional COMBO, default same as input; the other options are the usual depth list, of which OpenCV supports CV_32F and CV_64F here.
  • nparray - the Euclidean points.

Where it fits in a real graph

This is glue, and glue is most of a ComfyUI graph - the plumbing layer comfyui-node-plumbing.md maps out. The pattern it enables:

  1. Take pixel points (from CV Contour To Points, CV Annotate Points, a feature node, or findNonZero).
  2. Make them homogeneous - cv2.convertPointsToHomogeneous, or cv2.triangulatePoints/solvePnP which hand you homogeneous data directly.
  3. Multiply by your 3×3 or 3×4 (CV Matrix Multiply).
  4. Come back to Euclidean space with this node.
  5. Draw or measure the result.

Step 3 without step 4 is the classic bug: you'll see coordinates in the millions, or a shape that's almost right and slightly cursed, because the w-divide never happened. The pair of conversion nodes exists precisely so you can do that four-step dance in the graph without writing Python.

Installing the pack

Manager → search ComfyUI CV, or:

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

Restart. Requirements: Python ≥ 3.12, a ComfyUI with the V3 node API, and opencv-contrib-python-headless~=5.0.0.93.

Where people get burned

  • Shape. OpenCV expects N×1×C or N×C. A flat (3,) row or a squeezed array is the most common cause of an opaque overload-resolution error. CV Reshape Array exists in this pack for exactly this, and its own docs list "required before cv2 arithmetic on (3,) rows" as the reason.
  • Forgetting it, not misusing it. The failure mode is downstream, not here: points that are still homogeneous look numerically fine until you compare them to something in pixels.
  • w = 0 points landing silently at the origin. If a batch of points collapses to (0, 0), check the last component of the input before you check anything else.
  • The last column must actually be the scale. If you concatenated arrays and your homogeneous block isn't the trailing one, this divides by the wrong number. That's a data-shape mistake, not a node setting - inspect with Preview CV Array before trusting the result.
  • The pack's own record. The README states it was written with heavy LLM assistance, flags a real overfitting incident (the Hu-moment case) and advises against production use without independent review; updates are not planned. For a node this small and this well-specified you're unlikely to hit a problem - but for geometry you intend to stake a pipeline on, run one known example (a point at (100, 200, 2) should come back as (50, 100)) rather than assuming. There's no community corpus for the pack to compare notes with; a Reddit search returns nothing.
Categoryimage/CV/low-level/cv2 C

Inputs (2)

NameTypeDefaultDescription
srcNPARRAYInput vector of N-dimensional points. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.
dtypeoptCOMBOsame as inputThe desired output array depth (either CV_32F or CV_64F are currently supported). If it's -1, then it's set automatically to CV_32F or CV_64F, depending on the input depth. The function converts points homogeneous to Euclidean space using perspective projection. That is, each point (x1, x2, ... x(n-1), xn) is converted to (x1/xn, x2/xn, ..., x(n-1)/xn). When xn=0, the output point coordinates will be (0,0,0,...).

Outputs (1)

NameTypeDescription
nparrayNPARRAY—