Nodes/ComfyUI CV/cv2.img_hash.marrHildrethHash
ComfyUI Node

cv2.img_hash.marrHildrethHash

Hashing the edges, for when \u201cclose\u201d isn\u2019t close enough

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.img_hash.marrHildrethHash
  • inputArr
  • nparray
◄alpha2.0000►
◄scale1.0000►

This one hashes the output of a Marr–Hildreth edge filter - a Laplacian-of-Gaussian pass, the classic "where is the structure in this picture" detector - rather than raw pixel means or DCT coefficients. The author's tooltip calls it the family's "most sensitive to structural change," and that is precisely the point: this is the hash you use when you want to know whether the content moved, not just whether the file looks the same.

Two jobs it does well. First, change detection in a generation pipeline: you ran a pass with a slightly different setting, did the edges move, or did you just re-encode the same picture? Second, distinguishing near-identical outputs that the coarser hashes happily conflate - two renders from the same prompt where the difference is a changed silhouette, a moved hand, a different pose rather than a different palette. If pHash says "same picture" and your eyes say "no it isn't," this is the algorithm that will agree with your eyes.

It cuts the other way too. LoG response is sensitive to blur, sharpening, noise and rescale, so this is a poor choice for "is this the same photo at a different size?" - pHash wins that test comfortably. Pick per question: pHash for sameness, Marr–Hildreth for change.

How the parameters work

  • inputArr - 8-bit, 1/3/4 channels; IMAGE, MASK or NPARRAY socket. It is in the pack's per-frame list, so a batch is hashed frame by frame and comes back stacked, which is what you want when you are scanning a sequence for the frame where something changed.
  • alpha - the scale ratio between successive filter levels, default 2. Raise it to spread the analysis over a wider band of edge scales.
  • scale - the base scale of the filter, default 1. Smaller values key on fine detail (and on noise); larger values key on coarse structure. If your results are jittery, this is the knob to raise - you are currently fingerprinting detail your pipeline is not preserving consistently.
  • Output nparray - the byte hash.

Comparing two hashes is a Hamming distance over bits (cv2.norm with NORM_HAMMING), or use the curated CV Image Hash Compare node, which exposes "Marr-Hildreth" as an option, applies your threshold, and returns distance, similar, and both raw hashes. That node also normalises the direction of comparison across the family, which is worth having - cv2's own hash comparison is not consistent between algorithms.

Because it is a bit-based hash, the same scale rules apply as for pHash: single-digit bit distances are "the same picture", tens are unrelated. Expect your phone-a-friend threshold for this algorithm to sit tighter than pHash's on any pipeline that rescales - that is not a tuning failure, it is the sensitivity you asked for.

Install

Manager → search comfyui_cv (bmad4ever), or by hand:

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. No models, one pinned dependency. img_hash is an OpenCV contrib module: a non-contrib build has no such node, and since all four OpenCV distributions share one site-packages/cv2, another pack installing plain opencv-python can quietly strip it. The repo's tools/repair_opencv_contrib.py --check / --apply is the diagnostic and the fix.

When it goes wrong

  • A rescaled copy reads as a different image. Documented behaviour of an edge-based hash, not a bug. Use pHash when sameness across scale is the question.
  • Everything looks different. Input noise is the usual cause; a low-quality JPEG or a noisy generation has spurious edges at the base scale. Raise scale, or denoise first - cv2.medianBlur and the pack's curated edge-preserving filters are both cheap pre-passes.
  • A threshold lifted from pHash misbehaves. Same units, different sensitivity. Measure a known pair through CV Image Hash Compare and set the number from that.
  • You are hashing a float or 16-bit array. Cast to 8-bit first; the tooltip wants 1/3/4-channel 8-bit data.
  • The node is missing from the UI. Contrib wheel drift or an OpenCV build without img_hash - the registry is generated from the installed cv2 and skips entries the build does not expose.
Categoryimage/CV/low-level/img_hash

Inputs (3)

NameTypeDefaultDescription
inputArrNPARRAY,IMAGE,MASKinput image want to compute hash value, type should be CV_8UC4, CV_8UC3, 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.
alphaoptFLOAT2.0000-1e+38–1e+38int scale factor for marr wavelet (default=2). Preset to the OpenCV default (2.0).
scaleoptFLOAT1.0000-1e+38–1e+38int level of scale factor (default = 1) Preset to the OpenCV default (1.0).

Outputs (1)

NameTypeDescription
nparrayNPARRAY—