Skip to content

Commit

Permalink
Hooked up inexact matching
Browse files Browse the repository at this point in the history
  • Loading branch information
jezhiggins committed Aug 26, 2019
1 parent bfeba51 commit d6ec813
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 62 deletions.
Binary file added chrome-extension/images/maybe.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 18 additions & 9 deletions chrome-extension/scripts/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ const baseUrl = window.location.origin;
const baseLocation = baseUrl + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')+1);

const AuthenticatedClass = 'archangel-authenticated';
const AuthenticatedInexactClass = 'archangel-authenticated-inexact';
const NotAuthenticatedClass = 'archangel-not-authenticated';
const AuthenticatedWrapper = `<div class='${AuthenticatedClass}'></div>`;
const AuthenticatedInexactWrapper = `<div class='${AuthenticatedInexactClass}'></div>`;
const NotAuthenticatedWrapper = `<div class='${NotAuthenticatedClass}'></div>`

angelsWings();
Expand All @@ -26,12 +28,12 @@ function authenticateImage(image) {
image.src,
function (data) {
image.data = data;
markImage(image, data.authentic);
markImage(image, data.authentic, data.exact);
}
);
}

function markImage(image, isAuthentic) {
function markImage(image, isAuthentic, isExact) {
if (isAuthentic == 'error')
return;

Expand All @@ -41,24 +43,31 @@ function markImage(image, isAuthentic) {
if (parent.is("picture")) { // The Guardian!
const grandparent = parent.parent();
if (grandparent.children().length == 1)
style(grandparent, isAuthentic);
style(grandparent, isAuthentic, isExact);
return;
}

if ((parent.is("div") && parent.children().length == 1)) {
style(parent, isAuthentic);
style(parent, isAuthentic, isExact);
return;
}

wrap(image.element, isAuthentic);
wrap(image.element, isAuthentic, isExact);
}

function style(elem, isAuthentic) {
elem.addClass(isAuthentic ? AuthenticatedClass : NotAuthenticatedClass);
function style(elem, isAuthentic, isExact) {
let cls = NotAuthenticatedClass;
if (isAuthentic)
cls = isExact ? AuthenticatedClass : AuthenticatedInexactClass;

elem.addClass(cls);
}

function wrap(elem, isAuthentic) {
elem.wrap(isAuthentic ? AuthenticatedWrapper : NotAuthenticatedWrapper);
function wrap(elem, isAuthentic, isExact) {
let cls = NotAuthenticatedWrapper;
if (isAuthentic)
cls = isExact ? AuthenticatedWrapper : AuthenticatedInexactWrapper;
elem.wrap(cls);
}

function gatherImages() {
Expand Down
19 changes: 19 additions & 0 deletions chrome-extension/styles/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@
opacity: 0.7;
}

.archangel-authenticated-inexact {
position: relative;
}

.archangel-authenticated-inexact:after {
content: "";
display: block;
width: 100%;
height: 100%;
position: absolute;
top: 0px;
left: 0px;
background-image: url("chrome-extension://__MSG_@@extension_id__/images/maybe.png");
background-size: 64px 64px;
background-position: 15px 15px;
background-repeat: no-repeat;
opacity: 0.7;
}

.archangel-not-authenticated {
position: relative;
}
Expand Down
10 changes: 5 additions & 5 deletions image-hash/build-searchtree.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
from hasher.database import JsonFilesReader as DatabaseReader

if __name__ == '__main__':
image_path = sys.argv[1]
database_path = join(image_path, 'fingerprint.db')
fingerprints_path = sys.argv[1]
index_path = join(fingerprints_path, 'fingerprint.db')

db = DatabaseReader(image_path)
db = DatabaseReader(fingerprints_path)
feats = db.get_hashes()
nbrs = NN(1, algorithm='ball_tree').fit(feats)
with open(database_path, 'wb') as f:
with open(index_path, 'wb') as f:
pickle.dump(nbrs, f)
print('Search index saved at %s' % database_path)
print('Search index saved at %s' % index_path)
16 changes: 11 additions & 5 deletions image-hash/hasher/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,21 @@ def __init__(self, fingerprintPath):
self.fingerprintPath = fingerprintPath

def get_hashes(self):
hashes = []
return self.load_fingerprint_data('hash')

def get_thresholds(self):
return self.load_fingerprint_data('threshold')

def load_fingerprint_data(self, key):
data = []
for filePath in self.fingerprintFiles():
with open(filePath, 'r') as f:
fingerprint = json.load(f)['payload']['fingerprint']
hashes.append(fingerprint['hash'])
return hashes
fingerprint = json.load(f)['payload']['fingerprint']
data.append(fingerprint[key])
return data

def fingerprintFiles(self):
everything = [join(self.fingerprintPath, f) for f in listdir(self.fingerprintPath)]
everything = [join(self.fingerprintPath, f) for f in sorted(listdir(self.fingerprintPath))]
files = [f for f in everything if isfile(join(self.fingerprintPath, f))]
return [f for f in files if f.endswith('.json')]

49 changes: 49 additions & 0 deletions image-hash/image-checker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
from os.path import join
import pickle
from hasher.database import JsonFilesReader as DatabaseReader
from hasher.extractor import Extractor

def load_thresholds(fingerprints_path):
db = DatabaseReader(fingerprints_path)
return db.get_thresholds()

def load_search_index(index_path):
with open(index_path, 'rb') as f:
search = pickle.load(f)
return search

def hash_image(img_path):
hasher = Extractor()
feat, th = hasher.extract2(img_path)
feat = feat[None, ...]
return feat

if __name__ == '__main__':
img_path = sys.argv[1]
fingerprints_path = sys.argv[2]
index_path = join(fingerprints_path, 'fingerprint.db')

ths = load_thresholds(fingerprints_path)
search = load_search_index(index_path)
img_hash = hash_image(img_path)

dist, ids = search.kneighbors(img_hash)
ids = ids.squeeze()
dist = dist.squeeze()

if dist > ths[ids]:
print('{"found": false}')
else:
print('{')
print(' "found": true,')
print(' "image": %d,' % ids)
if (dist == 0.0):
print(' "exact": true')
else:
print(' "exact": false,')
print(' "distance": %f' % dist)
print('}')
17 changes: 5 additions & 12 deletions web-server/hashDB/AngelsWings.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,10 @@ function saveFingerprint(payload) {

async function listFingerprintFiles() {
const fileNames = await fsp.readdir(fingerprintPath);
return fileNames.map(
name => path.join(fingerprintPath, name)
);
}

async function* listFingerprints() {
const filePaths = await listFingerprintFiles();
for (const path of filePaths) {
const fingerprint = await fsp.readFile(path);
yield JSON.parse(fingerprint);
}
fileNames.sort();
return fileNames
.filter(name => name.endsWith('.json'))
.map(name => path.join(fingerprintPath, name));
}

async function StartAngelsWings() {
Expand All @@ -51,4 +44,4 @@ async function StartAngelsWings() {
);
}

export { StartAngelsWings, listFingerprints }
export { StartAngelsWings, listFingerprintFiles }
9 changes: 2 additions & 7 deletions web-server/hashDB/driver/ArchangelEthereumDriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,8 @@ class ArchangelEthereumDriver {
const p = unwrapPayload(r.args._payload);
if (!(p.data && (p.data.pack === 'photo')))
return;

if (Array.isArray(p.fingerprint)) {
p.fingerprint = {
hash: p.fingerprint,
threshold: 0
}
}
if (Array.isArray(p.fingerprint))
return;

const unwrapped = {
blockNumber: r.blockNumber,
Expand Down
34 changes: 18 additions & 16 deletions web-server/imagehash/authenticate-photo.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import { listFingerprints } from '../hashDB/AngelsWings'
import { fingerprintPhoto } from './fingerprint-photo'
import { listFingerprintFiles } from '../hashDB/AngelsWings'
import { checkPhoto } from './fingerprint-photo'
import { promises as fsp } from 'fs';

async function authenticatePhoto(imagePath) {
const fingerprint = await fingerprintPhoto(imagePath);
const result = await checkPhoto(imagePath, '/tmp/fingerprints');

for await (const fp of listFingerprints()) {
if (fingerprintMatch(fingerprint, fp.payload.fingerprint)) {
fp.authentic = true;
fp.payload.fingerprint = null;
return fp;
}
} // for ...
console.log(result)

return { authentic: false };
if (!result.found)
return { authentic: false };

const fingerprint = await loadFingerprint(result.image);
fingerprint.authentic = true;
fingerprint.exact = result.exact;
fingerprint.distance = result.distance;
fingerprint.payload.fingerprint = null;
return fingerprint;
} // authenticatePhoto

function fingerprintMatch(lhs, rhs) {
for (let i = 0; i !== lhs.hash.length; ++i)
if (lhs.hash[i] !== rhs.hash[i])
return false;
return true;
async function loadFingerprint(index) {
const imagePaths = await listFingerprintFiles();
const fingerprint = await fsp.readFile(imagePaths[index]);
return JSON.parse(fingerprint);
}

export { authenticatePhoto };
29 changes: 21 additions & 8 deletions web-server/imagehash/fingerprint-photo.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,30 @@ import path from 'path';
const scriptPath = path.join(__dirname, '../../image-hash/');
const imageHasher = path.join(scriptPath, 'image-hash.py');
const reindexer = path.join(scriptPath, 'build-searchtree.py');
const imageChecker = path.join(scriptPath, 'image-checker.py');

async function runScript(script, ...args) {
const cmd = `${script} ${args.join(' ')}`
const { stdout } = await execp(cmd);
return stdout;
}
async function fingerprintPhoto(filename) {
const fingerprintCmd = `${imageHasher} ${filename}`;
const { stdout } = await execp(fingerprintCmd);
return JSON.parse(stdout);
const fingerprint = await runScript(imageHasher, filename);
return JSON.parse(fingerprint);
}

async function reindexFingerprints(fingerprintPath) {
const reindexCmd = `${reindexer} ${fingerprintPath}`;
const {stdout} = await execp(reindexCmd);
console.log(stdout);
function reindexFingerprints(fingerprintPath) {
runScript(reindexer, fingerprintPath)
.then(console.log)
}

async function checkPhoto(photoPath, fingerprintPath) {
const stdout = await runScript(
imageChecker,
photoPath,
fingerprintPath
);
return JSON.parse(stdout);
}

export { fingerprintPhoto, reindexFingerprints };
export { fingerprintPhoto, reindexFingerprints, checkPhoto };

0 comments on commit d6ec813

Please sign in to comment.