Nodes/ComfyUI CV/CV Permute Axes
ComfyUI Node

CV Permute Axes

HWC to CHW without writing numpy in your head

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
CV Permute Axes
  • nparray
  • nparray
◄source-1►
◄dest0►

The most boring node in this pack and one of the most used, in the way that adapters always are. CV Permute Axes reorders an ndarray's axes - it's numpy.moveaxis as a node. You need it the moment two libraries disagree about where the channel dimension goes.

OpenCV and ComfyUI images are (H, W, C). Most deep-learning runtimes want (C, H, W), and a DNN blob wants (1, C, H, W). In a DNN workflow - the pack's ONNX examples, or anything going through cv2.dnn - you'll hit this the first time a blob comes out with the wrong shape for the model, and the answer is one of these nodes rather than a Python node you maintain.

The mechanism is exactly moveaxis

Two inputs beyond the array: source (default -1, the axis to move from - the channel axis in an HWC image) and dest (default 0, the axis to move to - making channels leading, i.e. NCHW). Every other axis keeps its relative order.

So the default pair -1 → 0 is precisely the HWC→CHW conversion, and running it again with 0 → -1 puts it back. If that seems too simple, that's the point: the classic hand-rolled version of this in every custom node pack is a np.transpose with a hand-typed permutation tuple, and the classic bug is getting the tuple wrong for a 3-channel vs 4-channel input. Moveaxis inverts cleanly, which transpose-with-a-tuple does not.

Output is a single nparray, the same data with axes reordered (made contiguous, so downstream cv2 calls that want a real buffer are happy).

When you actually need it

  • Into a DNN: HWC array → (C, H, W) → the blob node. The pack also ships CV To Blob, which does the 4-D (1, C, H, W) conversion in one step and accepts float32 directly so pre-normalized data isn't cast to uint8 on the way; if that's your target, use it instead.
  • Out of a DNN: a (1, C, H, W) output back to HWC so an image node can display it.
  • Batch/stack juggling: any time an array has picked up a singleton or a batch axis somewhere and a consumer expects it flattened.
  • LATENT arrays: the pack passes latents through as float32 arrays, and their axis order is nobody's convention but the VAE's - permuting is sometimes the only way to make two latent arrays line up.

Install

Manager → search ComfyUI CV, or:

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
cd comfyui_cv && pip install "opencv-contrib-python-headless~=5.0.0.93"

Restart. Python ≥ 3.12 and a ComfyUI on the V3 node API. Nothing here needs contrib OpenCV, but the pack installs the pinned contrib headless wheel regardless.

Common issues

  • "Cannot move axis N to M on an array of shape …" - good news, this node raises with the shape in the message rather than doing something surprising. source/dest are clamped to -4..4, so on an array with fewer dimensions than the axis you named, that's the error you get.
  • Shapes look right but the image comes out wrong - you permuted a 3-channel array that was actually grayscale-repeat or RGBA. Check the actual channel count; moveaxis can't tell you.
  • cv2 throws about a non-contiguous array downstream - shouldn't happen here, the node makes the result contiguous. If it does, something else in the chain is slicing.
  • You're looking for a shape readout - that's not this node; use CV Array Size or Inspect CV Data to see what you actually have before permuting blindly.

The pack-level caveat stands: LLM-assisted, personal project, not production-grade, updates whenever the author feels like it. For a one-line numpy reorder, the risk is negligible - the interesting question is just whether you permuted the right axis.

Categoryimage/CV/low-level

Inputs (3)

NameTypeDefaultDescription
nparrayNPARRAYArray whose axes to permute.
sourceINT-1-4–4Axis to move FROM (-1 = last, e.g. the channel axis in an HWC image).
destINT0-4–4Axis to move TO (0 = first, e.g. making channels the leading dimension for NCHW).

Outputs (1)

NameTypeDescription
nparrayNPARRAYThe same data with axes reordered.