Created
October 2, 2018 21:23
-
-
Save atwong/3da16d729b495f36ad5d09c68611172a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Jimp = require("Jimp"); | |
/* | |
* Compute Perceptual Hash of an Image | |
* Javascript equivalent of https://github.com/bjlittle/imagehash | |
* | |
* These hashes differ by ~1-3 Hamming distance from original python implementation | |
* | |
*/ | |
// Copied from https://gist.github.com/bellbind/6fee86bd8027b57991f9 | |
function dct2d(mat, m, n) { | |
// 0.0-1.0 2D matrix | |
var isqrt2 = 1 / Math.sqrt(2); | |
var px = Math.PI / m; | |
var py = Math.PI / n; | |
var r = []; | |
for (var ry = 0; ry < n; ry++) { | |
for (var rx = 0; rx < m; rx++) { | |
var c = Math.pow(isqrt2, (rx === 0) + (ry === 0)); | |
var t = 0; | |
for (var y = 0; y < n; y++) { | |
for (var x = 0; x < m; x++) { | |
var v = mat[y * m + x]; | |
t += v * Math.cos(px * (x + 0.5) * rx) * Math.cos(py * (y + 0.5) * ry); | |
} | |
} | |
r.push(c * t / 4); | |
} | |
} | |
return r; | |
}; | |
function phashQ(imgUrl, hashsize = 8, hfreq_fact = 4) { | |
const LUMASCALE = [0.2989, 0.5870, 0.1140]; //ITU-R 601-2 luma RGB -> greyscale transform | |
const OCTLEN = 8; | |
var imgsize = hashsize * hfreq_fact; | |
var midpoint = Math.floor((hashsize * hashsize) / 2); | |
var noctets = Math.floor((hashsize * hashsize) / OCTLEN); | |
return new Promise((resolve, reject) => { | |
Jimp.read(imgUrl).then(img => { | |
var pixels = []; | |
img.resize(imgsize, imgsize).scan(0, 0, imgsize, imgsize, function(x, y, idx) { | |
pixels.push( | |
this.bitmap.data[idx] * LUMASCALE[0] + | |
this.bitmap.data[idx + 1] * LUMASCALE[1] + | |
this.bitmap.data[idx + 2] * LUMASCALE[2]); | |
}); | |
var coef = dct2d(pixels, imgsize, imgsize); | |
var lofreqcoef = coef.filter((v, idx) => (Math.floor(idx / imgsize) < hashsize) && ((idx % imgsize) < hashsize)); | |
var median = lofreqcoef.slice().sort((a, b) => a - b)[midpoint]; | |
var bits = new Uint8Array(noctets); | |
for (var i=0; i<noctets; i++) { | |
bits[i] = lofreqcoef.slice(i * OCTLEN, (i + 1) * OCTLEN). | |
reduce((acc, val, idx) => acc |= ((val > median) ? 01 : 00) << (OCTLEN - idx - 1), 00); | |
} | |
resolve(bits.reduce((acc, val) => acc += val.toString(16).padStart(2, "0"), "")); | |
}); | |
}); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment