cv2.img_hash.averageHash
The fastest way to ask \u201chas this image changed?\u201d
- inputArr
- nparray
Perceptual hashing: turn an image into a small fingerprint that survives rescaling and re-compression. averageHash is the simplest member of the family - shrink the image to a tiny grid, average the pixel values, and emit one bit per cell depending on whether that cell is above or below the mean. The result is 8 bytes. Comparing two of them is a Hamming distance.
Why you would want 8 bytes instead of a picture: it makes "are these two images the same picture?" a cheap, cacheable, sortable question. The obvious ComfyUI use is skipping duplicate work - hash the output, compare against what you already generated, branch. The less obvious one is a change detector: hash the before and after of an img2img pass at low denoise and you get a number that tells you whether the sampler actually did anything. Same idea as the routine deduplication you would want before uploading a folder, just inside the graph - the same impulse behind the metadata and asset-tracking side of ComfyUI (image-io-metadata.md).
How it works, and its one weakness
The whole algorithm is a 2-D average. Which makes it fast, and it also makes it brightness-sensitive: shift the exposure of an image by a stop and enough cells cross the mean to change the bits, even though nothing in the picture moved. The author's own tooltip says this in as many words - "fastest and crudest; sensitive to brightness changes."
So use it where the lighting is constant: comparing outputs of the same pipeline, checking whether a pass changed an image, deduping a folder of renders from one setup. Do not use it to match a photo against a reference with different exposure.
Input and output
inputArr- the image. Type must be 8-bit, 1/3/4 channels. The socket takes an IMAGE, MASK or NPARRAY; grayscale and colour both work. It is in the pack's per-frame list, so a batch of 30 images is hashed frame by frame and the results come back stacked - you get 30 hashes from one node, which is exactly what a dedupe pass wants.- Output
nparray- the 8-byte hash. It is not an image, no matter how much it looks like a 1×8 array; do not wire it to a preview expecting pixels.
To compare two hashes: cv2.norm with NORM_HAMMING gives you a bit distance (~2 bits apart means the same picture rescaled or re-compressed; ~30 means unrelated). Or skip the arithmetic and use the pack's CV Image Hash Compare node, which hashes two images, offers this algorithm as an option, applies a threshold and returns distance, a similar boolean, and both raw hashes. That node is the sane default because it also tames a real inconsistency in cv2's hashing family - some algorithms return similarity where others return distance, and it normalises every algorithm to "0 = identical". Its bit-based threshold default is 10.
Because these hashes are deterministic and tiny, they are also good things to write out: CV Array To Text (or JSON format) gives you a string you can save or log, which is what turns a one-off comparison into a catalogue.
Install
Manager → search comfyui_cv (bmad4ever), or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
Python ≥ 3.12 and a recent ComfyUI on the V3 node API. img_hash is an OpenCV contrib module, so this node exists only on a contrib build. All four OpenCV distributions share one site-packages/cv2, and installing a non-contrib wheel over a contrib one silently empties the contrib submodules - at which point this node disappears rather than erroring. tools/repair_opencv_contrib.py --check diagnoses it, --apply repairs.
When it goes wrong
- Everything matches, or nothing does. Threshold in the wrong units. For this algorithm the distance is a Hamming bit count, not a 0–1 similarity. If you are rolling your own comparison, use
NORM_HAMMING. - The same image hashes differently after a re-save. It should not, at mild JPEG quality - but a heavy quality drop or an exposure change will move bits. That is the brightness sensitivity above.
- Crops break it. An average hash has no notion of the picture, only of a tiny grid of brightness. Crop the subject out and the hash is unrelated; that is expected, and the same is true for pHash.
- The hash is not small in the UI because you previewed it.
Preview CV Arraywill happily render 8 bytes as a 1×8 image and teach you nothing. Read it withCV Array To Textinstead. - Node missing entirely. Contrib wheel problem, or an OpenCV build without
img_hash- the registry probes the installed cv2 and skips what it cannot find.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| inputArr | NPARRAY,IMAGE,MASK | input image want to compute hash value, type should be CV_8UC4, CV_8UC3 or CV_8UC1. 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 | — |