CV Homography Map
Perspective as one entry in a longer distortion chain
- map_x
- map_y
- matrix
- map_x
- map_y
You already had cv2.warpPerspective. This node is that operation re-expressed as a coordinate map, which sounds like a downgrade until you realise what it buys: the perspective change stops being its own resampling pass and becomes one more term in a chain of distortions that collapses into a single cv2.remap. Lens correction, a wave, a pinch and a homography - one interpolation, one soft image edge, done.
What it does with your matrix
matrix is a 3×3 homography. The node multiplies the incoming map coordinates through it, divides by the homogeneous component, and hands back new map_x/map_y. It also protects the divide: near-zero w is clamped to a tiny epsilon rather than producing infinities that would scatter your sampling, and the node raises a clear error if matrix isn't 3×3 or if the matrix turns out to be non-invertible - the message literally asks whether detection failed upstream, which is the right diagnosis in practice.
The invert boolean is the one a beginner will get wrong. On by default, and that default is for the normal case: you computed a source→destination homography (CV Find Homography with RANSAC, or getPerspectiveTransform), and a remap wants the opposite direction - destination pixel asking which source pixel it came from. So leave invert on and feed the homography you found. Turn it off only if the matrix you're holding is already the dst→src mapping, e.g. you inverted it yourself earlier in the graph.
How the chain is wired
Start with CV Identity Map on your image (it only reads width/height), feed map_x/map_y into this node's matching inputs, and pass the outputs on to whatever comes next - another distortion map, or the terminal cv2_remap. Both inputs must share a shape, because they came from the same chain. The invert widget is a genuine convenience and not a formality: getting the direction backwards produces an image that's subtly wrong rather than obviously broken, which is the worst kind of wrong.
Nice property of doing it this way: an object outline can be projected with the same matrix via cv2.perspectiveTransform - grab the corners with CV Image Corners - so the overlay and the warped image stay in agreement by construction rather than by eyeballing.
If all you want is a plain perspective warp with nothing attached, the low-level cv2_warpPerspective wrapper is fewer nodes and you should just use that. This node pays off when the perspective is one of several corrections.
Install
ComfyUI Manager, search the pack title comfyui_cv (bmad4ever/comfyui_cv). Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
Restart ComfyUI. Python ≥ 3.12 and a ComfyUI new enough for the V3 node API are required - this pack uses io.ComfyNode/io.Schema and has no NODE_CLASS_MAPPINGS, so older builds won't load it at all. Dependency:
pip install "opencv-contrib-python-headless~=5.0.0.93"
It's pinned because behaviour is curated against that build, and it's contrib because the pack wants the contrib submodules. Installing a non-contrib OpenCV wheel at any point silently empties them (they all share one site-packages/cv2), and contrib nodes vanish from the menu with no error message. tools/repair_opencv_contrib.py --check / --apply are the pack's own repair tools.
Where people get burned
- "The homography is not invertible (degenerate matrix) - did detection fail upstream?" That's the node doing you a favour. A degenerate H almost always means CV Find Homography gave you a bad fit, so check its
foundoutput and its inlier count instead of tuning this node. - The warp is mirrored or reversed. Flip
invert, or check whether your matrix is src→dst after all. - Maps from different chains.
map_xandmap_ymust be the same shape and same origin; if you built one from a different image size, you get a shape error or nonsense. - Nothing renders. Maps aren't pixels - the chain needs a final
cv2_remap.
Standard pack caveat, straight from its README: heavy LLM involvement in the code, some example workflows overfitted to their sample data, no promised support, and a stated recommendation not to use it in production without reviewing the source. The maths here is small and verifiable, which is the good case; treat the surrounding pipeline with the scepticism it asks for.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| map_x | NPARRAY | Incoming source-x coordinate map to distort. Start the chain with 'CV Identity Map'; further remap nodes compose onto it. | |
| map_y | NPARRAY | Incoming source-y coordinate map (must share map_x's shape - both come from the same chain). | |
| matrix | NPARRAY | 3x3 homography. | |
| invert | BOOLEAN | true | Invert the matrix (on for src->dst homographies; off if you already have the dst->src mapping). |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| map_x | NPARRAY | — |
| map_y | NPARRAY | — |