Nodes/ComfyUI CV/CV Project To Plane
ComfyUI Node

CV Project To Plane

A flat look at a 3D cloud

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
CV Project To Plane
  • points
  • points
◄planeXZ (top-down)►

Three coordinates in, two out. This drops one axis so you can look at a 3D cloud or a camera trajectory as a flat drawing.

What it's for

Orthographic views of 3D data, rendered by nodes that only understand 2D points. A stereo point cloud, a triangulated set of features, a camera trajectory from CV Compose Pose - feed any of them here and you can draw the result with the pack's ordinary 2D plotting and drawing nodes. Top-down, front, side: the plane dropdown picks which pair of axes survives.

  • XZ (top-down) - the bird's-eye view. You keep x and z and throw away height. This is the default, and the right one for anything that happened on a floor plan: a vehicle's path, a person's walk around a room, a robot's trace.
  • XY (front) - the camera's own view direction, projected flat.
  • YZ (side) - looking along x.

The trajectory case is the one people underestimate. Visual odometry gives you poses in 3D camera space, but what you want to see is usually "did the camera go round the block in the right direction", and a top-down XZ plot answers that instantly. Pair it with CV Draw Path (ordered) and you get the route with direction and endpoints visible.

How it works, and what it isn't

It's a pure axis drop - no camera, no perspective, no rotation, no scale. Every point keeps two of its three coordinates verbatim. That's why it's exact and cheap, and also why it is not a way to render a 3D scene: two points at wildly different depths map to the same flat position, so a top-down view of a tall building looks like a single dot's worth of footprint unless you plot the footprint deliberately.

If you want a perspective render with a camera matrix, that's cv2.projectPoints - this node is orthographic by construction.

Inputs and outputs

points takes Nx3 or Nx1x3 - a triangulated cloud, a trajectory, anything with three columns. plane picks the two axes to keep. A None or empty input passes straight through as an empty array, so a pipeline that found no points on some frame doesn't explode.

The single output points is Nx1x2 float32, in the same row order as the input. That's exactly what the drawing nodes, CV Draw Path (ordered), CV Fit Points To Box and the plotting nodes consume - CV Fit Points To Box is worth knowing about here, because a raw top-down projection usually has coordinates in the thousands and needs a mapping into the image before anything is visible.

Installing

Standard for the pack. ComfyUI Manager → search "ComfyUI CV", or:

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

Python ≥ 3.12, a recent ComfyUI on the V3 node API, opencv-contrib-python-headless~=5.0.0.93, numpy, torch. This node has no model requirements at all.

Gotchas

Y is down in image coordinates, up in most 3D conventions. A top-down view where y grows downward makes a left turn look like a right one. The pack's plotting nodes take a y_axis toggle for exactly this, and its CV Fit Points To Box node flips the world axis that pixel rows would otherwise draw upside down. If your floor plan is mirrored, that's the fix, not the data.

Overplotting is invisible here. Because nothing is sorted by depth, nearer and farther points land on top of each other with no indication which is which. If that matters, keep the depth column and sort or colour by it before drawing.

Scale is preserved, which means it isn't framed. Nothing rescales the output, so you'll typically want a fit-to-box step between this node and anything that draws.

Categoryimage/CV/points

Inputs (2)

NameTypeDefaultDescription
pointsNPARRAY3D points, Nx3 or Nx1x3 (e.g. a triangulated cloud or a 'Compose Pose' trajectory). None/empty -> empty output.
planeCOMBOXZ (top-down)Which two axes to keep: XZ is the bird's-eye view (drops the height Y); XY is the front view; YZ the side view.

Outputs (1)

NameTypeDescription
pointsNPARRAY2D points, Nx1x2 float32.