cv2.flip
Mirror an image, a mask or a latent in one node
- src
- result
Mirroring sounds too trivial to need a node, right up until you have a mask that must stay aligned with the image it belongs to, a latent you want to flip without a decode/encode round trip, or an NPARRAY in the middle of a cv2 chain that you'd rather not convert back to a tensor and back again. cv2.flip handles all three through one socket, and returns the value in the format it arrived in.
That "echoes the input's format" behaviour is the pack's own version of the core Resize node pattern: an IMAGE link comes back as IMAGE, a MASK as MASK, an NPARRAY stays an NPARRAY, and a LATENT comes back as a LATENT. It's part of ComfyUI CV (bmad4ever), the pack that turns OpenCV 5.0 into ComfyUI nodes - around 470 auto-generated cv2.* wrappers plus curated high-level nodes, GPL-3.0, built on ComfyUI's V3 node API.
Inputs and outputs
Two inputs, one output.
src is the match-type socket: IMAGE, MASK, NPARRAY, or LATENT. This is where the pack's conversion conventions matter. An IMAGE tensor becomes a uint8 BGR ndarray (frame 0 of a batch unless the function is on the pack's per-frame list, which this one is), a MASK becomes a single-channel uint8 array, and a LATENT becomes a float32 [H,W,C] array with the values untouched - no uint8 quantisation, so flipping a latent doesn't damage it.
flipCode is a dropdown with three friendly labels - and they exist precisely because OpenCV's own documentation wording trips everyone up. The default is horizontal (around y-axis), which is code 1 and mirrors the image left-to-right. vertical (around x-axis) is code 0 and mirrors top-to-bottom. both is -1, a 180° rotation. If you've ever written flipCode=1 expecting a vertical flip because the docs say "flipping around the y-axis", this dropdown is the fix: it tells you what the picture will do, not which mathematical axis is involved.
result echoes the input's format. IMAGE in, previewable IMAGE out. MASK in, MASK out - which is the feature you actually want when you mirror an image and have to mirror its mask with it, since a mask that flips differently from its image is one of the more confusing bugs to chase down.
Where it earns its place in a workflow
Three real cases, all of them boring and all of them why the node exists:
- Keeping a mask in lockstep with its image. Same
flipCodeon both, and the pair stays aligned. - Flipping in the middle of a cv2 pipeline. If you're already working in NPARRAY land - contours, keypoints, geometry - converting to a tensor just to use a flip node and converting back is pure friction. NPARRAY in, NPARRAY out.
- Latent-space flipping. Feed a LATENT and the flip happens in latent space, values untouched. Note the pack's own documentation of this path: spatial ops like this one take frame 0 of a latent batch (only the pure arithmetic ops in the pack pass a whole latent batch through). So for a batch of latents you're flipping one frame per execution, which is often still cheaper than a decode.
Masks are single-channel and processed per-frame for an IMAGE/MASK batch, so a batch of masks comes back as a batch of flipped masks with the order preserved.
Install
ComfyUI Manager → search ComfyUI CV, or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install -r comfyui_cv/requirements.txt
Python ≥3.12 and a modern ComfyUI (V3 node API). Restart ComfyUI after installing. The pack declares opencv-contrib-python-headless~=5.0.0.93; flip is core imgproc, so this node works on any OpenCV build - but you won't know whether other categories are missing unless you check, because they simply don't appear in the node search:
python ComfyUI/custom_nodes/comfyui_cv/tools/repair_opencv_contrib.py --check
Common issues
It feels backwards. It's the flipCode semantics, not you. Say out loud "horizontal flip = mirror left-right" and set the label that matches, rather than reasoning about axes.
A latent flip looks subtle. Latents aren't pictures; a mirrored latent doesn't show you anything useful until it's decoded. What this gets you is symmetry in the generation - a mirror-consistent latent for a symmetric subject - not a preview.
Nothing comes out of the batch you expected. If you handed it an IMAGE batch, every frame is flipped individually (frames stay in order). If you wanted the order of frames reversed - play it backwards - that's a different axis operation, and cv2.flipND is where you'd look.
Contrib categories missing. As above: one shared site-packages/cv2 across all four OpenCV pip distributions means installing opencv-python on top of the contrib wheel empties the contrib submodules silently. --check diagnoses, --apply repairs (stop ComfyUI first).
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| src | COMFY_MATCHTYPE_V3 | input array. The image output(s) echo this input's format. A LATENT link is processed in latent space: frame 0 becomes a float32 [H,W,C] array (any channel count), values untouched. Arithmetic ops (add, multiply, etc.) also accept a full LATENT batch ({samples: [B,C,H,W]}) — the whole batch flows through when both inputs have the same batch size. 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. | |
| flipCode | COMBO | horizontal (around y-axis) | a flag to specify how to flip the array; 0 means flipping around the x-axis and positive value (for example, 1) means flipping around y-axis. Negative value (for example, -1) means flipping around both axes. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| result | COMFY_MATCHTYPE_V3 | Echoes the 'src' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY. |