CV Relative Identity Map
The map that outputs zero, and why that's not useless
- image
- map_x
- map_y
Start a remap chain with CV Identity Map and you get a map where map_x[y][x] = x and map_y[y][x] = y - the do-nothing grid that cv2.remap reads as "absolute source coordinate". That's the right start for most chains. This node is the other one: it emits (0, 0) everywhere, and that's correct - because you intend to sample it with WARP_RELATIVE_MAP, where cv2 reads the maps as relative offsets (dx, dy) instead of absolute source positions. Zero offset is identity.
Why that distinction matters
With WARP_RELATIVE_MAP in the flags, cv2.remap samples src(x + map_x, y + map_y) rather than src(map_x, map_y). That changes which map nodes you can chain and how:
- Every distortion node in the pack that adds a displacement -
CV Wave Map,CV Vector Displacement Map,CV Flow Map,CV Displacement Map- composes naturally, because adding offsets is exactly what they do. Chain five of them and each one's contribution sums. - The absolute-position nodes don't.
CV Radial Lens Maprewrites coordinates as a function of distance from a centre; that math assumes it owns the coordinate system, so it doesn't meaningfully compose in relative mode.
So the choice of starting node is really a choice of chain type. Absolute mode composes projective and radial warps; relative mode composes displacements. Mixing them gives you a warp that isn't either, which is a hard bug to see because the output still looks like a warp.
image is the only input, and it's purely for dimensions - only its width and height are used. It accepts an IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY from anywhere upstream, which means the map automatically matches whatever's flowing through the graph. Outputs are map_x and map_y, both HxW float32 zero-filled.
What you actually build with it
The pack's workflows/44_relative_remap.json is the clearest demonstration, and it's a good one: two branches, a Sobel edge magnitude driving a displacement, and a normal map driving a displacement, both going RelativeIdentityMap → CV Vector Displacement Map → cv2_remap(INTER_LINEAR | WARP_RELATIVE_MAP). That's a normal-map-driven emboss/lit-relief effect built out of three nodes and no model - the kind of thing that would otherwise be a Photoshop filter or a shader.
The same pattern covers flow-based retiming (warp a frame along an optical flow field to synthesise an intermediate frame), texture displacement for stylised renders, and lens-like breathing effects where you want the displacement to be a smooth field rather than a polynomial.
Install
Ships in ComfyUI CV (bmad4ever/comfyui_cv), a GPL-3.0 fork of opencv-comfyui:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
# restart ComfyUI
Manager: search the pack title. Python ≥ 3.12 and a V3-API ComfyUI. The pack's generated flag node (CV Warp Flags) is where you author WARP_RELATIVE_MAP for the raw cv2_remap wrapper - it's a bit-flag builder, not a dropdown, so it's one of the few places in this pack where you'll deliberately go and check what bits you're setting.
Two warnings
Forget the flag and the output is a flat smear. Zero-offset maps with normal cv2.remap semantics tell the sampler to read pixel (0,0) for the entire frame, so you get a solid rectangle of the top-left pixel. It's the single most common symptom of wiring this node into the wrong remap call, and it's instantly diagnosable: if your output is a flat colour, check the flags.
It's a copy of the frame's dimensions, not the frame. If you resize the image after building the map - or build the map from an IMAGE node while the rest of the graph works at another resolution - the map is the wrong shape and cv2 will either complain or clamp. Build the chain at the resolution you intend to warp at.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| image | NPARRAY,IMAGE,MASK | Only its width/height are used. 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. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| map_x | NPARRAY | HxW float32 zero-filled map (relative dx). |
| map_y | NPARRAY | HxW float32 zero-filled map (relative dy). |