cv2.ximgproc.qmultiply
The quaternion product, which is how you convolve a colour image
- src1
- src2
- nparray
Two inputs, one output, no parameters - and it's the load-bearing node of the quaternion family. qmultiply computes the quaternion product of two 4-channel arrays pixel by pixel. In the frequency domain, that is convolution: transform your image, transform your kernel (or your other image), multiply the transforms, transform back, and you've filtered a colour image as a single object instead of three independent planes. The familiar "multiply in frequency = convolve in space" rule, in a form that keeps the channels coupled.
It's the step where you'd otherwise be doing cv2.mulSpectrums on a greyscale image. Here it's qmultiply on a quaternion one.
Inputs
- src1 - a 4-channel quaternion array, from the generated
cv2.ximgproc.createQuaternionImagewrapper. The author's tooltip names the format and then adds the sentence that matters: quaternion multiplication does not commute. - src2 - the other quaternion array. Same shape and layout. Depending on your recipe this is a
qdft'd kernel, a second image's transform, or a spectrum you've masked with the pack's array nodes.
Output is a plain NPARRAY. It stays in quaternion space, so the next stop is qdft with DFT_INVERSE - and it must use the same sideLeft setting as the forward transform, or the round trip doesn't close. Then you take the real part or a magnitude (the generated cv2.magnitude wrapper applied to the planes, or a CV Slice Array plane) and only then does CV Array → Image make sense.
Swapping src1 and src2 gives you a genuinely different result. That's not a quirk of the node, it's the algebra - and it's why the family also ships qconj: conjugating one operand is how you flip convolution into correlation, so the peak lands on the match rather than its mirror.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
Restart ComfyUI, or install ComfyUI CV from ComfyUI Manager. Python ≥3.12, a recent ComfyUI on the V3 node API, opencv-contrib-python-headless~=5.0.0.93. Nothing to download. It's a contrib function, so a non-contrib OpenCV wheel sharing site-packages/cv2 will hide it from the menu - tools/repair_opencv_contrib.py --check diagnoses that, --apply repairs it.
Common issues
Shape mismatch. Both operands must be 4-channel arrays of the same size. Multiplying an image by a spectrum that came from a different-sized kernel is the classic mistake, and it fails inside cv2 rather than at the socket - the wrapper re-raises it as cv2.ximgproc.qmultiply failed: … with the input shapes printed, which is at least a decent breadcrumb.
Wrong result, no error. Check sideLeft on the inverse qdft, then check the operand order. Those two account for most silently-wrong quaternion pipelines.
Nothing to preview. Everything between the first qdft and the final real-part extraction is not displayable, by design. Build the chain with Inspect CV Data on each wire; debugging a quaternion pipeline by looking at previews is how people conclude the whole thing is broken.
Expect thin documentation. OpenCV's page for this function is a signature and a line. The pack wraps it because it wraps essentially everything top-level in cv2 and ximgproc; the README's own disclaimers (LLM-assisted development, generated-and-uncurated wrappers, no production guarantee, updates not planned) apply with full force here.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| src1 | NPARRAY,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. | |
| src2 | NPARRAY,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)
| Name | Type | Description |
|---|---|---|
| nparray | NPARRAY | — |