| examples | seed | |
| src | seed | |
| test | seed | |
| LICENSE | seed | |
| phash.janet | seed | |
| project.janet | seed | |
| README.org | seed | |
pHash
Janet FFI bindings for the pHash perceptual hash library. Provides perceptual hashing functions for images, text, audio, and video. Further details can be found in the pHash documentation.
Installation
The wrapper requires the phash library to be installed somewhere on the libpath.
apt install libphash-dev # Debian/Ubuntu
brew install phash # macOS Homebrew
The module can be installed via jpm
jpm install https://codeberg.org/zzkt/phash
Or build from source...
git clone https://codeberg.org/zzkt/phash
cd phash
jpm build
jpm test
jpm install
Quick start
There are some examples in the examples/ folder that can provide various starting points. Short descriptions of each algorithm has been taken from the pHash Design & Validation document.
(importphash)
DCT image hash (64-bit)
"The discrete cosine transform (DCT) is an efficient means to compute a hash from frequency spectrum data, and the distance calculation is relatively simple. While it is insufficient to consider image similarity in any semantically meaningful way, it does provide a hash as an ID for an image, and is robust against minor distortions, like small rotations, blurring and compression."
# Compute a 64-bit hash for an image(defdct-img-1(phash/dct-image-hash"image-1.jpg"))(defdct-img-2(phash/dct-image-hash"image-2.png"))# Compare two images via Hamming distance (0 = identical, 64 = completely different)(print(phash/hamming-distancedct-img-1dct-img-2))
Marr-Hildreth wavelet hash
"We have developed a new image hash based on the Marr wavelet that computes a perceptual hash based on edge information with particular emphasis on corners. It has been shown that the human visual system makes special use of certain retinal cells to distinguish corner-like stimuli."
(defmh-img-1(phash/mh-image-hash"image.jpg"))(defmh-img-2(phash/dct-image-hash"image-2.png"))(printf"MH hash bytes:\n[1] %s\n[2] %s\n"mh-img-1mh-img-2)(print"Normalized distance: "(phash/hamming-distance2mh-img-1mh-img-2))
Radial image digest (Radish)
"This method tries to take into account geometric features of the image in extracting a hash value. The idea is to generate a feature vector from the variances of 180 lines drawn through the center of the image, and then compact the feature vector with the discrete cosine tranform (DCT). Images can be compared by looking for correlations between the images' hash values. "
(defd(phash/image-digest"image.jpg"))(print"Digest id: "(d:id))# Compare via cross-correlation (1.0 = identical)(defpcc(phash/compare-images"a.jpg""b.jpg"))(print"Cross-correlation: "pcc)
Text hash
(deftexth(phash/text-hash"document.txt"))(print"Found "(lengthtexth)" text hash points")
Bark Audio Hash
"This hashing method for audio signals extracts a feature vector for every frame of audio from the bark scale frequency spectrum - that is, it only considers those frequencies to which the human auditory system is most sensitive."
(definfo(phash/audio-hash-from-file"recording.wav"))(print"Frames: "(info:count))
DCT Variable Length Video Hash
"A variable length DCT video hash is included, It consists of the dct image hash applied to a select number of key frames chosen from the original image sequence. The key frames are selected using an adaptive thresholding technique and are based upon a standard framerate, so as not to be fooled by alterations in the frame rate."
(defdct-video-1(phash/dct-video-hash"video.mp4"))(print(lengthdct-video-1)" DCT keyframes extracted")# Compare two videos via minimum Hamming distance across all keyframe pairs(defd(phash/video-distancedct-video-1dct-video-2))(printf"Distance: %d/64"d)
API reference
image
(dct-image-hash file)→uint64|nilDCT perceptual hash of an image file.(mh-image-hash file &opt alpha lvl)→ buffer |nilMarr-Hildreth wavelet hash (72 bytes).(mh-image-hash-from-pixels pixels width height channels &opt alpha lvl)→ buffer |nilMH hash from raw pixel data.(image-digest file &opt sigma gamma n)→{:id string :coeffs buffer :size int}|nilRadial image hash (Radish).(compare-images file1 file2 &opt sigma gamma n threshold)→double|nilCross-correlation between two image digests.(cross-correlation digest-x digest-y &opt threshold)→double|nilCross-correlation between two image digests.
text
(text-hash file)→ array of{:hash uint64 :index int64}|nilPerceptual text hash points from a file.(compare-text-hashes hash1 hash2)→ array of{:first int64 :second int64 :length uint32}|nilFind matching text hash sequences between two documents.
audio
(read-audio file &opt sr channels)→{:samples ptr :length int}|nilRead raw audio samples.(read-audio-samples file &opt sr channels)→ array offloat|nilRead audio samples as a Janet array.(audio-hash samples sample-rate)→{:frames buffer :count int}|nilCompute audio hash from raw float samples.(audio-hash-from-file file &opt sr channels)→{:frames buffer :count int}|nilCompute audio hash directly from a file.(audio-distance-ber hash-a count-a hash-b count-b &opt threshold block-size)→double|nilBit error rate distance between two audio hashes.
video
(dct-video-hash file)→ array ofuint64|nilDCT frame hashes from a video file.(video-distance hash-a hash-b &opt threshold)→intMinimum Hamming distance (0–64) across all keyframe pairs. Returns 0 when the minimum is ≤ threshold (indicating similar videos). Seeexamples/compare_videos.janet.
distance & utility functions
(hamming-distance a b)→intHamming distance between two 64-bit hashes (0–64).(hamming-distance2 hash-a hash-b)→double(0.0–1.0) Normalized Hamming distance between two byte-array hashes.(bitcount8 val)→intNumber of set bits in a byte (0–8).(about)→stringpHash version and copyright string.
License
GPL-3.0-or-later (pHash itself is GPL-2.0-or-later. this binding inherits that license)