Comparing hashes¶
Distances and similarities, one per kind of digest.
| Constants | |
|---|---|
PH_ |
The peak-of-cross-correlation threshold the radial hash's source uses, 0.9. |
| Functions | |
|---|---|
ph_ |
Number of differing bits between two 64-bit hashes, 0 to 64. |
ph_ |
Normalized similarity between two 64-bit hashes, in [0.0, 1.0]. |
| Comparing digests | |
|---|---|
ph_ |
Number of differing bits between two PH_DIGEST_KIND_BITS digests (mHash, BMH, or a 64-bit hash taken as a digest). |
ph_ |
Euclidean distance between two feature vectors: PH_DIGEST_KIND_VECTOR16 (ColorMoments, decoded from its 16-bit fixed point) or PH_DIGEST_KIND_VECTOR (one unsigned byte per feature). |
ph_ |
Normalized similarity between two digests, in [0.0, 1.0]. |
ph_ |
Compares two radial digests the way the algorithm's source specifies: by the peak of their cross-correlation over all cyclic shifts. |
ph_ |
Compares two color histograms by their intersection: sum(min(a_i, b_i)) over bins, each histogram normalized by its own total. |
Constants¶
PH_RADIAL_PCC_THRESHOLD¶
The peak-of-cross-correlation threshold the radial hash's source uses, 0.9.
pHash treats two radial digests correlating at or above this as the same image (Zauner, Diplomarbeit FH Hagenberg 2010, section 3.2.3). It is provided as a starting point with a citation behind it, not as a tuned recommendation for your corpus: ph_radial_similarity() hands back the raw score so that you can pick your own cut, measured on your own images. What 0.9 accepts on two corpora is measured in Comparing hashes.
Functions¶
ph_hamming_distance()¶
Number of differing bits between two 64-bit hashes, 0 to 64.
For aHash, dHash, pHash and wHash values. Only meaningful between two hashes of the same algorithm, computed with the same settings.
ph_similarity()¶
Normalized similarity between two 64-bit hashes, in [0.0, 1.0].
1.0 means identical hashes, 0.0 means every bit differs, and two unrelated images land near 0.5. The scale is shared with ph_similarity_digest() for digests of any length; a threshold is not, since how close a copy comes depends on the algorithm. See Comparing hashes.
Comparing digests¶
The contract shared by every function below that reads a ph_digest_t.
ph_digest_t is a flat struct callers (including FFI bindings) may fill in themselves, and size can hold values data cannot: a digest whose size exceeds PH_DIGEST_MAX_BYTES is rejected, never truncated.
The kind tag is checked too. Each comparison below states the kind it is for, and refuses a digest tagged as something else: Hamming distance over quantized DCT coefficients returns a plausible number that means nothing, and this is how that call fails instead. PH_DIGEST_KIND_UNSPECIFIED – the zero a hand-filled struct holds – is accepted everywhere, so a binding that does not set the field gets no protection but no error either. A digest that breaks the contract gets:
- functions returning
ph_error_t: PH_ERR_INVALID_ARGUMENT; - distance/similarity functions: -1 (also for a size of 0, which carries no bits to compare – reporting distance 0 there would read as "identical").
ph_hamming_distance_digest() and ph_similarity_digest() are for PH_DIGEST_KIND_BITS; ph_l2_distance() is for PH_DIGEST_KIND_VECTOR and PH_DIGEST_KIND_VECTOR16; ph_radial_similarity() is for PH_DIGEST_KIND_COEFFICIENTS; ph_histogram_intersection() is for PH_DIGEST_KIND_HISTOGRAM.
ph_hamming_distance_digest()¶
Number of differing bits between two PH_DIGEST_KIND_BITS digests (mHash, BMH, or a 64-bit hash taken as a digest).
Returns 0 to 8 times the digest size; -1 for anything the digest contract above rejects: NULL, mismatched or invalid sizes, or another kind.
ph_l2_distance()¶
Euclidean distance between two feature vectors: PH_DIGEST_KIND_VECTOR16 (ColorMoments, decoded from its 16-bit fixed point) or PH_DIGEST_KIND_VECTOR (one unsigned byte per feature).
Returns 0.0 or more, in the features' own units; -1.0 for anything the digest contract above rejects: NULL, mismatched or invalid sizes, or another kind.
ph_similarity_digest()¶
Normalized similarity between two digests, in [0.0, 1.0].
Returns -1.0 for anything the digest contract above rejects: NULL, mismatched or invalid sizes, or a kind other than PH_DIGEST_KIND_BITS.
ph_radial_similarity()¶
Compares two radial digests the way the algorithm's source specifies: by the peak of their cross-correlation over all cyclic shifts.
The Pearson correlation of the two digests' bytes, computed with b shifted cyclically by each of 0 to size - 1 places; the largest of them. It runs from -1.0 to 1.0, and 1.0 means the same profile up to a shift. Compare it against PH_RADIAL_PCC_THRESHOLD, or against your own measured cut. The sums are exact integers and the score is rounded once, at the end, so it is the same on every machine and symmetric in a and b to the last bit. See Radial — Radial Variance Hash.
A digest with all bytes equal – the all-zero digest ph_compute_radial_hash() gives an image with no angular structure – has no correlation with anything: any number would be invented, and 1.0 would call two unrelated flat images identical. Such a pair is answered with PH_ERR_NO_STRUCTURE; whether "no data" counts as a match is the caller's decision.
Note
This returns its result through out_pcc rather than as the return value, as the other comparison functions here do. They signal failure with -1.0, and -1.0 is a legitimate correlation — a perfect anti-correlation — so the sentinel would be ambiguous exactly where the caller needs it not to be.
Parameters
| Parameter | Description |
|---|---|
a |
Digests of equal size and kind PH_DIGEST_KIND_COEFFICIENTS (or unspecified), both valid per the contract above. |
b |
Digests of equal size and kind PH_DIGEST_KIND_COEFFICIENTS (or unspecified), both valid per the contract above. |
out_pcc |
Receives the score. Untouched on error. |
Returns PH_SUCCESS; PH_ERR_NO_STRUCTURE if either digest has all bytes equal; PH_ERR_INVALID_ARGUMENT for a NULL argument, an invalid or empty digest, two digests of different sizes, or a digest of another kind.
ph_histogram_intersection()¶
ph_error_t ph_histogram_intersection(
const ph_digest_t *a,
const ph_digest_t *b,
double *out_similarity);
Compares two color histograms by their intersection: sum(min(a_i, b_i)) over bins, each histogram normalized by its own total.
The measure Swain & Ballard define, and the reason a histogram is worth keeping: it counts only what the two images have in common, so a change of background or a partial overlap costs only the part that differs.
Runs from 0.0 (no color in common) to 1.0 (identical distributions). Two empty histograms score 1.0; an empty one against a populated one scores 0.0.
Note
Swain & Ballard normalize by the reference histogram, which makes their score asymmetric when the two images hold different pixel counts. This normalizes each side by its own total, which agrees with them whenever the counts match and is symmetric when they do not. See ColorHash — Color Histogram.
Parameters
| Parameter | Description |
|---|---|
a |
Digests of equal size, both from ph_compute_color_hash() (or untagged). |
b |
Digests of equal size, both from ph_compute_color_hash() (or untagged). |
out_similarity |
Receives the score. Untouched on error. |
Returns PH_SUCCESS, or PH_ERR_INVALID_ARGUMENT for a NULL argument, an invalid or empty digest, two digests of different sizes, or a digest tagged as something other than a histogram.