├── .gitignore ├── spec ├── images │ ├── matches │ │ ├── blur.jpg │ │ ├── crop.jpg │ │ ├── mix.jpg │ │ ├── scale.jpg │ │ ├── wrong.jpg │ │ ├── source.jpg │ │ ├── rotation.jpg │ │ ├── compression.jpg │ │ └── desaturation.jpg │ └── colorful-picture.png ├── component.json ├── simi.js └── index.html ├── .travis.yml ├── package.json ├── Gruntfile.js ├── README.md └── simi.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | components/ 3 | .idea 4 | .DS_Store 5 | .idea/ 6 | -------------------------------------------------------------------------------- /spec/images/matches/blur.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitlyfied/js-image-similarity/HEAD/spec/images/matches/blur.jpg -------------------------------------------------------------------------------- /spec/images/matches/crop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitlyfied/js-image-similarity/HEAD/spec/images/matches/crop.jpg -------------------------------------------------------------------------------- /spec/images/matches/mix.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitlyfied/js-image-similarity/HEAD/spec/images/matches/mix.jpg -------------------------------------------------------------------------------- /spec/images/matches/scale.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitlyfied/js-image-similarity/HEAD/spec/images/matches/scale.jpg -------------------------------------------------------------------------------- /spec/images/matches/wrong.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitlyfied/js-image-similarity/HEAD/spec/images/matches/wrong.jpg -------------------------------------------------------------------------------- /spec/images/matches/source.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitlyfied/js-image-similarity/HEAD/spec/images/matches/source.jpg -------------------------------------------------------------------------------- /spec/images/colorful-picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitlyfied/js-image-similarity/HEAD/spec/images/colorful-picture.png -------------------------------------------------------------------------------- /spec/images/matches/rotation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitlyfied/js-image-similarity/HEAD/spec/images/matches/rotation.jpg -------------------------------------------------------------------------------- /spec/images/matches/compression.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitlyfied/js-image-similarity/HEAD/spec/images/matches/compression.jpg -------------------------------------------------------------------------------- /spec/images/matches/desaturation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitlyfied/js-image-similarity/HEAD/spec/images/matches/desaturation.jpg -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.8 4 | before_script: 5 | - npm cache clear 6 | - npm install grunt-cli -g 7 | script: grunt --verbose 8 | -------------------------------------------------------------------------------- /spec/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-image-similarity", 3 | "version": "0.0.1", 4 | "dependencies": { 5 | "jquery": ">= 1.7", 6 | "underscore": "*", 7 | "mocha": ">= 1.6", 8 | "chai": ">= 1.0" 9 | } 10 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-image-similarity", 3 | "version": "0.0.1", 4 | "description": "Tiny image comparison lib", 5 | "main": "simi.js", 6 | "dependencies": { 7 | "grunt": "~0.4.1", 8 | "grunt-mocha": "~0.3.0", 9 | "grunt-contrib-jshint": "~0.3.0", 10 | "phantomjs": "~1.8.2-2", 11 | "grunt-lib-phantomjs": "~0.2.0" 12 | }, 13 | "devDependencies": {}, 14 | "scripts": { 15 | "test": "grunt" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git://github.com/bitlyfied/js-image-similarity.git" 20 | }, 21 | "author": "", 22 | "license": "BSD", 23 | "readmeFilename": "README.md", 24 | "engines" : { "node" : ">=0.9.0" } 25 | } -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global module:false*/ 2 | module.exports = function (grunt) { 3 | 4 | // Project configuration. 5 | grunt.initConfig({ 6 | // Task configuration. 7 | mocha: { 8 | all: [ 'spec/index.html' ] 9 | }, 10 | jshint: { 11 | options: { 12 | curly: true, 13 | eqeqeq: true, 14 | immed: true, 15 | latedef: true, 16 | newcap: true, 17 | noarg: true, 18 | sub: true, 19 | undef: true, 20 | unused: true, 21 | boss: true, 22 | eqnull: true, 23 | browser: true, 24 | globals: { 25 | jQuery: true 26 | } 27 | }, 28 | gruntfile: { 29 | src: 'Gruntfile.js' 30 | }, 31 | lib_test: { 32 | src: ['simi.js'] 33 | } 34 | } 35 | }); 36 | 37 | grunt.loadNpmTasks('grunt-contrib-jshint'); 38 | grunt.loadNpmTasks('grunt-mocha'); 39 | 40 | // Default task. 41 | grunt.registerTask('default', ['jshint', 'mocha']); 42 | 43 | }; 44 | -------------------------------------------------------------------------------- /spec/simi.js: -------------------------------------------------------------------------------- 1 | describe("simi", function () { 2 | 3 | describe("utils", function () { 4 | 5 | describe("mapToBits", function () { 6 | it("generates a bit mask out of a callback run on each element of an array", function () { 7 | var bitMask = simi.utils.mapToBits([1, 2, 3, 4], function (item) { 8 | return item % 2 == 0; 9 | }); 10 | 11 | assert.equal('1010', bitMask.toString(2)); 12 | }); 13 | }); 14 | 15 | describe("thresholdMap", function () { 16 | it("returns the correct bits", function () { 17 | var input = new Array(64); 18 | input[0] = 10; 19 | input[1] = 20; 20 | input[2] = 30; 21 | 22 | var threshold = 20; 23 | 24 | var expectedOutput = '110'; 25 | 26 | var bitMask = simi.utils.thresholdMap(input, threshold); 27 | 28 | assert.equal(expectedOutput, bitMask.toString(2)); 29 | }); 30 | }); 31 | 32 | describe("hammingDistance", function () { 33 | it("returns the correct distance", function () { 34 | var from = parseInt('11111', 2), 35 | to = parseInt('10110', 2); 36 | 37 | var distance = simi.utils.hammingDistance(from, to); 38 | 39 | assert.equal(2, distance); 40 | }); 41 | }); 42 | 43 | 44 | }); 45 | 46 | }); 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JavaScript Image Similarity Comparison 2 | ======================= 3 | 4 | [](https://travis-ci.org/bitlyfied/js-image-similarity) 5 | 6 | This is a first draft of a basic image comparison algorithm using average hashes. 7 | The algorithm used is the one described here: 8 | 9 | http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html 10 | 11 | The library is only supposed to work in latest WebKit. 12 | Supports for Canvas and Array.forEach is required. 13 | 14 | Usage 15 | ----- 16 | 17 | var img1 = $('#image1'), 18 | img2 = $('#imge2'); 19 | 20 | // returns a difference rate (from 0 to 1) 21 | simi.compare(img1, img2); 22 | 23 | // returns true or false (same as compare with a default threshold) 24 | simi.same(img1, img2); 25 | 26 | // returns a hash of the image 27 | // simi.hash could be invoked to cache the hash 28 | var hash = simi.hash(img1); 29 | simi.compare(hash, img2); // only img2 will be hashed 30 | 31 | 32 | Dependencies 33 | ----- 34 | 35 | The library doesn't have any external dependencies, but you need bower, jquery, underscore, mocha and chai to run tests 36 | 37 | 38 | How to run tests 39 | ---- 40 | 41 | Tests are now run automatically using Travis CI. 42 | If you need to run tests manually you just need to use Grunt and run the default task. 43 | 44 | If you want to run tests manually from a browser you can follow this process: 45 | 46 | # run tests inside the browser 47 | cd .. 48 | python -m SimpleHTTPServer 49 | open http://localhost:8000/spec/index.html 50 | 51 | Always remember to download spec depdencies using bower before doing anything: 52 | 53 | # install tests dependencies using bower 54 | cd spec 55 | bower install 56 | -------------------------------------------------------------------------------- /spec/index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |