Nodes/ComfyUI CV/cv2.ximgproc.qunitary
ComfyUI Node

cv2.ximgproc.qunitary

Keep the phase, throw away the magnitude (in colour)

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
cv2.ximgproc.qunitary
  • qimg
  • nparray

qunitary normalises every quaternion in a 4-channel array to unit length - divide each pixel's quaternion by its own modulus. That's it. One input, no parameters, one output.

The reason a vision library wants it: once every value is a unit quaternion, only phase information survives, and magnitude is gone. That's the quaternion-domain version of phase-only filtering, which is how you get correlation peaks that are sharp and insensitive to brightness or exposure. If you're heading towards phase correlation between two colour images, or a quaternion colour-edge operator, this is the normalisation step in the middle of the recipe.

Inputs and outputs

  • qimg - a 4-channel quaternion array, i.e. the output of the generated cv2.ximgproc.createQuaternionImage wrapper (BGR in, (real, B, G, R) out). A normal three-channel IMAGE isn't valid input; the whole q* family is defined over four planes.
  • nparray - the unit-quaternion array, same shape and layout, as a plain NPARRAY. It is not an image and there's no channel for an image converter to use correctly; keep it in the quaternion lane (another q* node, or CV Slice Array plus CV Array → Image if you only want to eyeball one plane).

Watch out for the all-zero pixel case: normalising a quaternion whose modulus is zero has nothing to normalise. Black areas of a frame are exactly that, so if you see odd values in the shadows, that's where they came from - not from the wrapper misbehaving.

Where it fits

Typical chain: createQuaternionImage → qdft forward → qunitary on the spectrum (whitening it) or on one operand → qmultiply with the other side's transform → qdft with DFT_INVERSE, using the same sideLeft you used going forward, or the round trip doesn't close → take the real part or a magnitude → CV Array → Image.

The sideLeft pairing rule applies to the whole family, and it's the single most common way a quaternion pipeline silently produces the wrong answer: left- and right-sided transforms are genuinely different operators, and each has to be undone by its own inverse.

Install

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

Restart ComfyUI, or install ComfyUI CV through ComfyUI Manager. Python ≥3.12, a recent ComfyUI on the V3 node API, opencv-contrib-python-headless~=5.0.0.93 - no model files. qunitary is contrib, so it only exists in a contrib OpenCV build: if a plain opencv-python wheel has been installed over the contrib one, the node disappears from the menu and tools/repair_opencv_contrib.py --check is how you confirm that's the cause.

Common issues

No visible change. You normalised something that was already unit-length, or you're looking at a preview of the wrong plane.

Blown-out pixels where the image is black. Zero-modulus quaternions - see above. Mask or clamp before normalising if your downstream maths can't tolerate it.

You wanted colour edges and this feels like a detour. It is one. The pack also ships the simple versions of these jobs: plain Canny, Sobel, Laplacian and the curated detect-lines/contours nodes are all present and all easier. Reach for the quaternion family only when a specific algorithm calls for it - the nodes exist because the pack wraps substantially all of cv2 and ximgproc, not because anyone thinks a colour edge map needs a hypercomplex transform.

Categoryimage/CV/low-level/ximgproc

Inputs (1)

NameTypeDefaultDescription
qimgNPARRAY,IMAGE,MASK - - - 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 (1)

NameTypeDescription
nparrayNPARRAY—