├── Gruntfile.js ├── LICENSE ├── README.md ├── browser.js ├── classifiers ├── mixed-svm-1000.json ├── network.js ├── nn-options.js └── svm-options.js ├── kittydar.js ├── nms.js ├── package.json ├── testing ├── README.md ├── TEST │ ├── .DS_Store │ ├── 00092f6ec7a911e1be6a12313820455d_7.jpg │ ├── 00092f6ec7a911e1be6a12313820455d_7.jpg.cat │ ├── 0475ea02c7da11e18cf91231380fd29b_7.jpg │ ├── 0475ea02c7da11e18cf91231380fd29b_7.jpg.cat │ ├── 0502a3b2a1e111e18cf91231380fd29b_7.jpg │ ├── 0502a3b2a1e111e18cf91231380fd29b_7.jpg.cat │ ├── 066bdac8c71811e1a38422000a1c8933_7.jpg │ ├── 066bdac8c71811e1a38422000a1c8933_7.jpg.cat │ ├── 0c375608c71811e1b10e123138105d6b_7.jpg │ ├── 0c375608c71811e1b10e123138105d6b_7.jpg.cat │ ├── 10b80642c7da11e19894123138140d8c_7.jpg │ ├── 10b80642c7da11e19894123138140d8c_7.jpg.cat │ ├── 1140967248_e982ddc8d7.jpg │ ├── 1140967248_e982ddc8d7.jpg.cat │ ├── 1288302525156.jpg │ ├── 1288302525156.jpg.cat │ ├── 12a8d742be7f11e188131231381b5c25_7.jpg │ ├── 12a8d742be7f11e188131231381b5c25_7.jpg.cat │ ├── 144692464_f0053e1093.jpg │ ├── 144692464_f0053e1093.jpg.cat │ ├── 16cb636ed3c711e1b62722000a1e8b36_7.jpg │ ├── 16cb636ed3c711e1b62722000a1e8b36_7.jpg.cat │ ├── 171790888_d80e34a4f7.jpg │ ├── 171790888_d80e34a4f7.jpg.cat │ ├── 219966284_4aa0a3c465.jpg │ ├── 219966284_4aa0a3c465.jpg.cat │ ├── 22981-1363980352-3.jpg │ ├── 22981-1363980352-3.jpg.cat │ ├── 2320b0ae089e11e29e6f22000a1e8b8a_7.jpg │ ├── 2320b0ae089e11e29e6f22000a1e8b8a_7.jpg.cat │ ├── 23385-1363980332-4.jpg │ ├── 23385-1363980332-4.jpg.cat │ ├── 23981-1363980427-8.jpg │ ├── 23981-1363980427-8.jpg.cat │ ├── 2431886567_66ce6145ea.jpg │ ├── 2431886567_66ce6145ea.jpg.cat │ ├── 25508c1e88ba11e1a87612313804ec91_7.jpg │ ├── 25508c1e88ba11e1a87612313804ec91_7.jpg.cat │ ├── 265923028_ac8732cc7d.jpg │ ├── 265923028_ac8732cc7d.jpg.cat │ ├── 2703668839_cfe0d6b154.jpg │ ├── 2703668839_cfe0d6b154.jpg.cat │ ├── 27299-1363981152-9.jpg │ ├── 27299-1363981152-9.jpg.cat │ ├── 28273-1363981235-15.jpg │ ├── 28273-1363981235-15.jpg.cat │ ├── 286465_953271199759_1283353304_o.jpg │ ├── 286465_953271199759_1283353304_o.jpg.cat │ ├── 28654-1363981115-11.jpg │ ├── 28654-1363981115-11.jpg.cat │ ├── 29482-1363980679-3.jpg │ ├── 29482-1363980679-3.jpg.cat │ ├── 2994-1363980988-4.jpg │ ├── 2994-1363980988-4.jpg.cat │ ├── 2f49bd8cbf0911e180d51231380fcd7e_7.jpg │ ├── 2f49bd8cbf0911e180d51231380fcd7e_7.jpg.cat │ ├── 30599-1363980752-0.jpg │ ├── 30599-1363980752-0.jpg.cat │ ├── 33eb19201ed811e1abb01231381b65e3_7.jpg │ ├── 33eb19201ed811e1abb01231381b65e3_7.jpg.cat │ ├── 3437df14c7aa11e1aee522000a1e8a5f_7.jpg │ ├── 3437df14c7aa11e1aee522000a1e8a5f_7.jpg.cat │ ├── 3661671516_aab2c59cde.jpg │ ├── 3661671516_aab2c59cde.jpg.cat │ ├── 3ba670686e7111e181bd12313817987b_7.jpg │ ├── 3ba670686e7111e181bd12313817987b_7.jpg.cat │ ├── 4316096411_cfb2737168.jpg │ ├── 4316096411_cfb2737168.jpg.cat │ ├── 433e375c2cc211e1a87612313804ec91_7.jpg │ ├── 433e375c2cc211e1a87612313804ec91_7.jpg.cat │ ├── 4375600759_f6382fd5ff.jpg │ ├── 4375600759_f6382fd5ff.jpg.cat │ ├── 474156503_d64e972df3.jpg │ ├── 474156503_d64e972df3.jpg.cat │ ├── 4817433684_ff2dfedc58.jpg │ ├── 4817433684_ff2dfedc58.jpg.cat │ ├── 4878878197_31de9837ba.jpg │ ├── 4878878197_31de9837ba.jpg.cat │ ├── 491889103_603d896630.jpg │ ├── 491889103_603d896630.jpg.cat │ ├── 4ebcfed0a75911e1b2fe1231380205bf_7.jpg │ ├── 4ebcfed0a75911e1b2fe1231380205bf_7.jpg.cat │ ├── 506407837_5c15ab57db.jpg │ ├── 506407837_5c15ab57db.jpg.cat │ ├── 5352794771_5e03ca6451.jpg │ ├── 5352794771_5e03ca6451.jpg.cat │ ├── 54652550_2fe234cec7.jpg │ ├── 54652550_2fe234cec7.jpg.cat │ ├── 548c8aa491a811e1be6a12313820455d_7.jpg │ ├── 548c8aa491a811e1be6a12313820455d_7.jpg.cat │ ├── 55d268706e7111e1989612313815112c_7.jpg │ ├── 55d268706e7111e1989612313815112c_7.jpg.cat │ ├── 5640834510_35be88d31d.jpg │ ├── 5640834510_35be88d31d.jpg.cat │ ├── 5672121084_0a666a9f76.jpg │ ├── 5672121084_0a666a9f76.jpg.cat │ ├── 5804b25e64d211e18bb812313804a181_7.jpg │ ├── 5804b25e64d211e18bb812313804a181_7.jpg.cat │ ├── 5929820421_b710bd97a4.jpg │ ├── 5929820421_b710bd97a4.jpg.cat │ ├── 5c7ac9ec6fa211e1a87612313804ec91_7.jpg │ ├── 5c7ac9ec6fa211e1a87612313804ec91_7.jpg.cat │ ├── 653_555388061514093.jpg │ ├── 653_555388061514093.jpg.cat │ ├── 66250dd8be6011e1aebc1231381b647a_7.jpg │ ├── 66250dd8be6011e1aebc1231381b647a_7.jpg.cat │ ├── 663354768.jpg │ ├── 663354768.jpg.cat │ ├── 667_19375928237.jpg │ ├── 667_19375928237.jpg.cat │ ├── 67dcb80ab41b11e1aebc1231381b647a_7.jpg │ ├── 67dcb80ab41b11e1aebc1231381b647a_7.jpg.cat │ ├── 69375046_d06dc77299.jpg │ ├── 69375046_d06dc77299.jpg.cat │ ├── 6c8b25eea03911e192e91231381b3d7a_7.jpg │ ├── 6c8b25eea03911e192e91231381b3d7a_7.jpg.cat │ ├── 6cd3d502c03011e180c9123138016265_7.jpg │ ├── 6cd3d502c03011e180c9123138016265_7.jpg.cat │ ├── 7023222_87b23bb0cd.jpg │ ├── 7023222_87b23bb0cd.jpg.cat │ ├── 711.jpg │ ├── 711.jpg.cat │ ├── 78fd1f1aca3911e1a39b1231381b7ba1_7.jpg │ ├── 78fd1f1aca3911e1a39b1231381b7ba1_7.jpg.cat │ ├── 7d7f0184a43711e1b10e123138105d6b_7.jpg │ ├── 7d7f0184a43711e1b10e123138105d6b_7.jpg.cat │ ├── 8093406111_6fa933bf78.jpg │ ├── 8093406111_6fa933bf78.jpg.cat │ ├── 812794549d2511e1a9f71231382044a1_7.jpg │ ├── 812794549d2511e1a9f71231382044a1_7.jpg.cat │ ├── 84592b6ebedc11e1989612313815112c_7.jpg │ ├── 84592b6ebedc11e1989612313815112c_7.jpg.cat │ ├── 84bec45e2b7211e19e4a12313813ffc0_7.jpg │ ├── 84bec45e2b7211e19e4a12313813ffc0_7.jpg.cat │ ├── 8591817645_14993744d2.jpg │ ├── 8591817645_14993744d2.jpg.cat │ ├── 8592298699_265576d71d.jpg │ ├── 8592298699_265576d71d.jpg.cat │ ├── 8592651325_51b44f50ff.jpg │ ├── 8592651325_51b44f50ff.jpg.cat │ ├── 8593156480_03c3e57d50.jpg │ ├── 8593156480_03c3e57d50.jpg.cat │ ├── 8593717742_9162f0ef34.jpg │ ├── 8593717742_9162f0ef34.jpg.cat │ ├── 8f496896661b11e180d51231380fcd7e_7.jpg │ ├── 8f496896661b11e180d51231380fcd7e_7.jpg.cat │ ├── 90d35578a43711e180d51231380fcd7e_7.jpg │ ├── 90d35578a43711e180d51231380fcd7e_7.jpg.cat │ ├── 92df98b46efd11e18bb812313804a181_7.jpg │ ├── 92df98b46efd11e18bb812313804a181_7.jpg.cat │ ├── 9319d9f6ca3911e1b2fe1231380205bf_7.jpg │ ├── 9319d9f6ca3911e1b2fe1231380205bf_7.jpg.cat │ ├── 93c475d0ff4c11e1839c123138192853_7.jpg │ ├── 93c475d0ff4c11e1839c123138192853_7.jpg.cat │ ├── 9796956091a811e181bd12313817987b_7.jpg │ ├── 9796956091a811e181bd12313817987b_7.jpg.cat │ ├── 99890867_90c1e90437.jpg │ ├── 99890867_90c1e90437.jpg.cat │ ├── a227324aa43711e19e4a12313813ffc0_7.jpg │ ├── a227324aa43711e19e4a12313813ffc0_7.jpg.cat │ ├── ac62bcbcac5111e1b9f1123138140926_7.jpg │ ├── ac62bcbcac5111e1b9f1123138140926_7.jpg.cat │ ├── b1d94ca0ca3911e18cf91231380fd29b_7.jpg │ ├── b1d94ca0ca3911e18cf91231380fd29b_7.jpg.cat │ ├── b3f6a1ae359711e19e4a12313813ffc0_7.jpg │ ├── b3f6a1ae359711e19e4a12313813ffc0_7.jpg.cat │ ├── b672f508bedc11e1af7612313813f8e8_7.jpg │ ├── b672f508bedc11e1af7612313813f8e8_7.jpg.cat │ ├── bd9c8d0ea75711e1989612313815112c_7.jpg │ ├── bd9c8d0ea75711e1989612313815112c_7.jpg.cat │ ├── be87b8a0721f11e1b9f1123138140926_7.jpg │ ├── be87b8a0721f11e1b9f1123138140926_7.jpg.cat │ ├── business%2520cat.jpg │ ├── business%2520cat.jpg.cat │ ├── c47c1ca0ff4c11e1a76e22000a1e8903_7.jpg │ ├── c47c1ca0ff4c11e1a76e22000a1e8903_7.jpg.cat │ ├── c9eead403a8c11e19e4a12313813ffc0_7.jpg │ ├── c9eead403a8c11e19e4a12313813ffc0_7.jpg.cat │ ├── chemistry%2520cat.jpg │ ├── chemistry%2520cat.jpg.cat │ ├── d27f934ed5f411e19b0622000a1e8a4f_7.jpg │ ├── d27f934ed5f411e19b0622000a1e8a4f_7.jpg.cat │ ├── de5ad150c19111e1b9f1123138140926_7.jpg │ ├── de5ad150c19111e1b9f1123138140926_7.jpg.cat │ ├── e1bca2f66ff711e1a87612313804ec91_7.jpg │ ├── e1bca2f66ff711e1a87612313804ec91_7.jpg.cat │ ├── e66928da64d311e19e4a12313813ffc0_7.jpg │ ├── e66928da64d311e19e4a12313813ffc0_7.jpg.cat │ ├── e8f4da56d3c611e18ca012313806b840_7.jpg │ ├── e8f4da56d3c611e18ca012313806b840_7.jpg.cat │ ├── ebd69cfc2bae11e1abb01231381b65e3_7.jpg │ ├── ebd69cfc2bae11e1abb01231381b65e3_7.jpg.cat │ ├── ed45f0cc2e7111e19896123138142014_7.jpg │ ├── ed45f0cc2e7111e19896123138142014_7.jpg.cat │ ├── f2033f0a6bb311e19e4a12313813ffc0_7.jpg │ ├── f2033f0a6bb311e19e4a12313813ffc0_7.jpg.cat │ ├── f8558fc44b0c11e180c9123138016265_7.jpg │ ├── f8558fc44b0c11e180c9123138016265_7.jpg.cat │ ├── fbe98620432f11e19e4a12313813ffc0_7.jpg │ └── fbe98620432f11e19e4a12313813ffc0_7.jpg.cat ├── test.js └── todos.js ├── training ├── README.md ├── collect.js ├── collection │ ├── README.md │ ├── fetch-negatives.rb │ ├── make-negatives.js │ └── make-positives.js ├── features.js ├── neuralnet │ ├── cross-validate.js │ ├── mine-negatives.js │ ├── params.js │ ├── test-network.js │ └── train-network.js └── svm │ ├── cross-validate.js │ ├── mine-negatives.js │ ├── params.js │ ├── test-svm.js │ └── train-svm.js └── utils.js /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /* 2 | * To run this file: 3 | * `npm install --dev` 4 | * `npm install -g grunt` 5 | * 6 | * `grunt --help` 7 | */ 8 | 9 | var fs = require("fs"), 10 | browserify = require("browserify"), 11 | pkg = require("./package.json"); 12 | 13 | module.exports = function(grunt) { 14 | grunt.initConfig({ 15 | pkg: grunt.file.readJSON('package.json'), 16 | uglify: { 17 | options: { 18 | banner: "/*\n" + grunt.file.read('LICENSE') + "\n*/" 19 | }, 20 | dist: { 21 | files: { 22 | '<%=pkg.name%>-<%=pkg.version%>.min.js': ['<%=pkg.name%>-<%=pkg.version%>.js'] 23 | } 24 | } 25 | } 26 | }); 27 | 28 | grunt.registerTask('build', 'build a browser file', function() { 29 | var done = this.async(); 30 | 31 | var outfile = './kittydar-' + pkg.version + '.js'; 32 | 33 | var bundle = browserify('./browser.js').bundle(function(err, src) { 34 | console.log("> " + outfile); 35 | // write sync instead of piping to get around event bug 36 | fs.writeFileSync(outfile, src); 37 | done(); 38 | }); 39 | }); 40 | 41 | grunt.loadNpmTasks('grunt-contrib-uglify'); 42 | }; 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Heather Arthur 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kittydar 2 | 3 | Kittydar is short for kitty radar. Kittydar takes an image (canvas) and tells you the locations of all the cats in the image: 4 | 5 | ```javascript 6 | var cats = kittydar.detectCats(canvas); 7 | 8 | console.log("there are", cats.length, "cats in this photo"); 9 | 10 | console.log(cats[0]); 11 | 12 | // { x: 30, y: 200, width: 140, height: 140 } 13 | ``` 14 | 15 | [Kittydar demo](http://harthur.github.com/kittydar) 16 | 17 | ## Install 18 | 19 | For node: 20 | 21 | ```bash 22 | npm install kittydar 23 | ``` 24 | 25 | Or grab the [browser file](http://github.com/harthur/kittydar/downloads) 26 | 27 | ## Specifics 28 | 29 | Kittydar takes a `canvas` element. In node you can get a `Canvas` object with [node-canvas](https://github.com/LearnBoost/node-canvas). 30 | 31 | Kittydar will give an approximate rectangle around the cat's head. Each rectangle has an `x` and `y` for the top left corner, and a `width` and `height` of the rectangle. 32 | 33 | ## How it works 34 | 35 | Kittydar first chops the image up into many "windows" to test for the presence of a cat head. For each window, kittydar first extracts more tractable data from the image's data. Namely, it computes the [Histogram of Orient Gradients](http://en.wikipedia.org/wiki/Histogram_of_oriented_gradients) descriptor of the image, using the [hog-descriptor](http://github.com/harthur/hog-descriptor) library. This data describes the directions of the edges in the image (where the image changes from light to dark and vice versa) and what strength they are. This data is a vector of numbers that is then fed into a [neural network](https://github.com/harthur/brain) which gives a number from `0` to `1` on how likely the histogram data represents a cat. 36 | 37 | The neural network (the JSON of which is located in this repo) has been pre-trained with thousands of photos of cat heads and their histograms, as well as thousands of non-cats. See the repo for the node training scripts. 38 | 39 | ## Limitations 40 | 41 | Kittydar will miss cats sometimes, and sometimes classify non-cats as cats. It's best at detecting upright cats that are facing forward, but it can handle a small tilt or turn in the head. 42 | 43 | Kittydar isn't fast. It'll take a few seconds to find the cats in one image. 44 | 45 | There's lots of room for improvement, so fork and send requests. 46 | 47 | ## Propers 48 | 49 | * This informative reasearch paper: [Cat Head Detection - How to Effectively Exploit Shape and Texture Features](http://research.microsoft.com/pubs/80582/ECCV_CAT_PROC.pdf) by Weiwei Zhang, Jian Sun, and Xiaoou Tang. 50 | 51 | * This off the hook [dataset of cat images](http://137.189.35.203/WebUI/CatDatabase/catData.html) annotated with the locations of the cat's ears, eyes, and mouth. 52 | 53 | * [@gdeglin](http://github.com/gdeglin) for the name. 54 | -------------------------------------------------------------------------------- /browser.js: -------------------------------------------------------------------------------- 1 | // this file is the entrypoint for building a browser file with browserify 2 | 3 | kittydar = require("./kittydar"); -------------------------------------------------------------------------------- /classifiers/mixed-svm-1000.json: -------------------------------------------------------------------------------- 1 | {"N":3000,"D":2904,"b":-2.972102772598755,"kernelType":"linear","w":[0.00045846138474754704,-0.02548534349221223,0.0036521522503538736,0.02897765044669849,-0.023931910648796396,-0.020036073347839,-0.03368543823763425,-0.009727374522943479,-0.011232614770506744,0.07780246546180751,-0.029451433417049117,-0.03700524249331545,0.00805069597435279,-0.005402826947696353,-0.002089835599985356,-0.003300699712345044,-0.01979298737478994,-0.020978635802266526,0.035775929569741356,0.041273172338987876,0.02702182135023776,0.005971713604841152,-0.003376521841924158,0.003189169627644287,-0.03161232944982632,-0.007387471178150249,-0.009983591384831611,0.06236940336587255,-0.031199905033445635,-0.035332268459987055,-0.014272983265119468,-0.016955922624548696,-0.027126354895823473,0.0009980507498318007,-0.02955362520143756,-0.035162818079477964,0.029691315322247315,0.0412640818550605,0.028886621930224367,0.005089657968137765,-0.0071469698137260115,0.0006270210579294625,-0.023512658381681033,-0.018841742046249357,-0.016970413176316975,-0.0029137387064379016,0.10229439049507158,0.052184448228765765,-0.012871326076764602,-0.01642064604970254,-0.02514662381330283,0.015782313788150343,-0.02917521747066922,-0.033314068931369595,-0.0023344783885759107,-0.0027907857747898144,-0.011059847823631234,-0.024755636652547753,-0.02190138369960881,-0.018893489885527328,-0.021487793654930275,-0.01754592502679432,-0.014917384168154775,-0.0009423550561365801,0.11454506632783483,0.065683170388399,-0.008902373318196544,-0.007916640376527548,-0.0031937964984858833,0.0026972777418736455,0.01254803940688964,-0.010943872616051164,0.004704107070543296,0.0004972514700623596,-0.005123700319611528,0.009248559442680878,-0.019878854750651473,-0.015583770628607599,0.003654775263344899,-0.0023196024255872616,-0.010282568561073352,-0.0029747423770386796,-0.012572555603927777,-0.008807576841812518,-0.003252640616297602,-0.004470383434961367,0.00012263392203701293,0.006833717885763753,0.023654715956000064,0.000022250336835890545,-0.005123308387936756,-0.003552034420223046,0.0044800569506299685,0.007716570202622755,-0.016273741025403937,-0.015196773232981133,0.007396805840212757,-0.001592520290559919,-0.009499263584707663,0.006612188305340306,-0.010488837205691676,-0.008377243995743466,0.005769136380414519,-0.004760596523624729,-0.0015286450207012178,-0.00204083626797679,-0.00773439844128217,-0.0009789987705141477,-0.0026249606320617614,-0.0011897746507470342,0.006835452599613347,0.010088456180943655,-0.016480385327719158,-0.013404011243830475,-0.0019714551606993696,-0.005900528963218796,-0.0008914435324196447,0.007651919734843199,-0.010466494875647207,-0.008894993562070791,0.005627628121364716,-0.0040273476473740525,-0.001037517501261604,-0.0034451948476361665,-0.006631218152277443,-0.0006337706750518244,0.002581098572736593,-0.006423768335240285,-0.010250494911828554,-0.0002112791494050738,-0.008588257694528399,-0.002392228949618646,-0.0008750103291457354,-0.0051718777887208535,-0.0004068994132690137,0.007018125918470553,-0.010422407890955119,-0.00927459151983728,-0.0008625055131411561,-0.003900509510000487,-0.0078318645445383,0.009083952513730701,0.0013206670474116174,-0.003245145998668058,0.0033782839259373153,-0.0056374856374424,-0.012521729585465848,-0.00028012565814761924,-0.0074135683213368605,-0.0024791682883318453,0.004088817756379358,-0.008477033475454903,-0.013901258514096152,0.0022741302892055914,-0.0042424281141361705,-0.003763659597535271,0.001543516465343557,-0.0028680618430279043,-0.006769625467237688,0.010264813919797514,0.0015426776654007465,-0.0026808160277509607,-0.00033168066559921615,-0.009194771926617048,-0.010581966505603682,0.00842316062343843,0.005423417391042684,-0.006549861999438369,0.0029033200828688785,-0.009165580584822766,-0.014957665295792082,-0.00481582851417863,-0.007007656496318297,-0.005087539460763992,-0.0024701705865240453,-0.013732844790878902,-0.012055260610385496,0.010498589802885424,-0.008405268265769046,0.0016389607258746296,-0.0015206886796472413,-0.00898690097409495,-0.011741622268080936,0.008216795409497827,0.00691948465869494,-0.008118226232439919,-0.004786508131984067,0.007346620970534675,0.01996155851291825,0.005598765888650628,0.004621062156616955,-0.004832022917770803,-0.006521633176348057,-0.01664096357506844,-0.018228723689163395,-0.023886918046475105,-0.012325129825138543,-0.0010947991969089959,-0.016098399946379325,-0.026388836140291683,-0.01897844904064697,0.012250814507238328,-0.01776200882590119,-0.015127431019993927,-0.00743863342134811,-0.0031518760674021655,0.008764568415287347,0.0010320360021169224,0.00005448653860446594,-0.007690112693864488,-0.020658762695673537,0.07700787506540982,0.10711023829070157,0.0038603208638559377,-0.014518530308231655,-0.017264040613132577,-0.015790168143656854,-0.0299531538117475,-0.019103677711496778,-0.003813021812045242,-0.01922705078982764,-0.016308691307732975,-0.0338179907047534,-0.028213580530549186,-0.02383695578233209,0.06621776993846853,-0.004429800804046942,-0.008700726149516955,-0.02047174594011744,0.06273222327894303,0.09179412353445165,-0.00039558853295242513,-0.017404831271427397,-0.018468969528683536,0.02260526101312886,0.0009464693604224433,-0.0028935247201733816,0.014497295768743272,0.02799742384685194,0.03832503367949538,-0.036483929740561714,-0.028830740759757348,-0.021728396477006025,0.08029486388734922,-0.005330747566742836,-0.0113768279346434,0.00020540717777944119,-0.01704887744501591,-0.024109115922802432,0.017706603566187983,-0.019268672317079176,0.0034696213485764385,0.024749858288421647,0.006497410288634243,0.0005321728272454706,0.015018237445583798,0.025581759010338115,0.036371850468268026,-0.0021651281643430102,-0.020081771363722058,-0.019403161538217834,-0.007003506666081639,-0.0006826708198475357,0.008490316497193683,0.009579720391864199,-0.0036593398345351157,-0.0009489631581304199,0.001707785094608022,-0.022169196413195716,-0.021453699098472397,0.04685822683625734,0.05021892233042973,0.03264685738869588,0.008479281638493359,-0.008452967380995357,-0.0006461131388868244,0.0067397642613102,-0.0032275641292562798,-0.003298701214786289,0.0025519537330286842,-0.014651805939636678,-0.01722212587662875,0.05214934394464402,-0.0026561926455406725,-0.014333983291446282,-0.018188761814904274,-0.008799495592117602,0.032517177125614284,0.038516214582628626,0.053502761720163675,0.034516349953931526,0.004157458287070723,-0.01384370881731361,-0.007679258999392291,-0.031149995880471754,-0.023326833485282576,-0.0217946538963862,-0.003483380543359464,0.11577922234263568,0.05997130210187046,0.04417215892463669,-0.007267216050460084,-0.020800374951151668,-0.025625829319290465,-0.01836162330209303,0.025680205302285417,-0.02143706992035842,-0.02576154227558428,-0.026120289443307906,-0.030030944964567693,-0.0037397687560826384,0.02229030545026583,-0.03929590831718787,-0.028992360549922203,-0.02544819835803733,-0.006330715130707286,0.11356256145415622,0.06036987429267229,-0.019962519148187734,-0.01460640506440184,-0.012284962264153473,-0.004350792330465042,-0.0017801884880922713,-0.029335041827933506,-0.02685624157175751,-0.028067705698936934,-0.02792045250439771,-0.0323989005528352,-0.008316794885495467,0.01685298034442419,-0.018745820781777885,-0.01554664440244689,-0.02197384920983195,-0.020855517251729683,0.05418603272490023,0.0604635112521398,-0.01914788740903069,-0.014770778878389216,-0.011117714226294512,-0.0029688055640968974,0.003303211640867781,-0.026590809239519956,-0.020446276790527445,-0.014085224751828477,-0.008912645168947542,-0.008160555358501268,-0.03481927558945268,-0.032382690257333244,-0.0161736414741584,-0.013727078014326207,-0.018347918695942923,-0.018683532744906993,0.06950427267645505,0.07856304041543043,-0.01697492656885821,-0.01687137593195164,-0.0033754114539735,0.025795371835957887,0.0007591243490898557,-0.017997020084352593,-0.008012501864224763,-0.004642347405207297,-0.000059935757559469556,0.003875158304258057,-0.030349096613005923,-0.024522778316041088,-0.004742068320402287,-0.015876928193652513,-0.008729120861768355,-0.0029564822707603675,-0.02524776844595977,-0.01671947851239444,-0.003934769279533994,-0.008615018410388746,0.011216443724938295,0.03996999839843513,0.014323876622120145,-0.006728071606480421,-0.010175134318368424,-0.016089568898609824,-0.003417163710525033,0.05024288980164942,-0.012259080805019655,-0.017987889103252396,-0.004249570894381818,-0.012418852775216399,-0.006854901683988267,-0.0010444334402567252,-0.023151939103035434,-0.015403909309358843,-0.0033268723844313767,-0.011913160013092523,-0.016424822851203537,-0.002323513861049359,-0.006397577894230555,-0.010588908557132092,-0.011774709593853683,-0.014830959320171751,0.0028118114627673717,0.05495333708582514,-0.01629211658328268,-0.019697744186355365,-0.0033087676040092946,-0.010522016798075257,-0.01450609558940975,0.03612764659017,-0.00014364032616769,-0.010680353309660811,-0.0055143505518435295,-0.014016810685712346,-0.019172728283593843,-0.00335438745038906,-0.00938455152617445,-0.011879003448080523,-0.009047453381146068,-0.020458054317970834,-0.021470582080493284,0.004809381380897054,0.0022783898041551457,-0.017832995874973362,-0.009680371421720745,-0.00880110895300509,-0.009281247346865522,0.04045744982033569,-0.0029988829931052313,-0.017174112218463038,-0.006062264616655701,-0.007703747809261508,0.006137921173522127,0.03192691693393136,0.0038339004781191796,-0.007575383880702565,-0.01728275711566544,-0.026526296538578152,-0.029722374431614376,-0.010966360628270026,-0.005742608182896408,-0.02329871835417451,-0.02112053691998752,-0.014965294097200835,0.000226321785826814,-0.011815199493389718,-0.008206159879752026,-0.018855742676633966,-0.018350432595017917,-0.01550986336828972,-0.004947039343658801,0.016814281322577108,-0.0064275650963876215,-0.015695057841404934,-0.014627178946276995,0.08624544758920416,0.06643119783879267,-0.02826094454812732,-0.01546255695878366,-0.01372690851306034,-0.02152733614274256,-0.01972598111398207,-0.006303438260039011,-0.015041701959162561,-0.00973033780605587,-0.01942278427880911,-0.03574099455023762,0.06961949705144,0.1098643457101019,-0.006722281419932648,-0.02711369234876746,-0.029439334377324048,-0.018129754337801195,0.06368318824376981,0.04870080516670005,-0.03170635123763349,-0.021014490385143476,-0.017624381198698386,-0.025366409734805282,0.027631894206504495,-0.006089868083231982,-0.036975495022026586,-0.02400551171657037,-0.025372521372254556,-0.029063904052315726,0.07001711066853282,0.11073823711396139,0.00048473039008244443,-0.022060675803823693,-0.02352987520602187,0.027743808245851483,-0.0074647847373615645,-0.010614813382254692,0.015987307316969696,0.03665514594742787,0.04829422815674743,-0.016509631437673488,0.03437117364442167,-0.0004937658775761111,-0.032385432305790954,-0.022494745840836796,-0.023050720521727762,0.03855366074202222,0.015695565574653438,-0.019603510967415524,-0.023730640429646163,-0.011004332172108432,-0.001022805777604501,0.0350599424718805,0.003927121881315417,-0.004683584121142156,0.0184130838394935,0.03232865016213023,0.04477111960380153,-0.0024996650612040074,-0.021135059213851982,-0.01951918950048153,0.00015516683950645498,0.0032236107434273796,0.010939705735028192,0.05055650457926694,0.03196418215307703,-0.006960953094709694,-0.01434464090476871,-0.00611987230966911,0.0027249232059541376,0.005612548986016224,-0.011239927396829942,-0.011857093283825884,-0.005036950050833066,-0.0022035115697440146,0.0052292870491971065,0.007326724586243948,-0.0027566637460852013,-0.00259985661051572,0.004631142787554527,-0.013985842329841843,-0.016946261997141655,0.06362365194424471,0.0014009236675782556,-0.012738855025680744,-0.016369075214404536,-0.006811196221598882,0.0358006924380477,-0.012931448702118495,-0.0029512545674670494,-0.00042700405575661155,-0.0023240693022150488,-0.0024161725847510716,-0.010208655319812389,0.02419386811462296,-0.002361266589202649,-0.003388650935828569,-0.0038454489667242436,0.00040130331107156737,0.024287356259853655,0.0810887339327427,0.000972348835488839,-0.019989508361183805,-0.021655924847836773,-0.013667763947613707,0.042274899085890355,-0.012245192411427467,-0.0209834887467198,-0.021624066978132277,-0.027478517758430354,0.0015430317540295652,0.03796916014245531,0.039935652837932455,0.0012762496615707536,-0.0019912441256805095,-0.004460193863379711,-0.0010756187202007853,0.027627860929409623,0.00884224610161394,0.007195592663764014,-0.0002726388666262974,0.002190231486257248,0.0007648386015907582,0.01341404915203041,-0.01732276706092834,-0.021645217988167275,-0.02311462972348577,-0.02620249203160737,0.0014367635403621578,0.031197299467834127,-0.011219022902527229,-0.007993613366335629,-0.013200065175650345,-0.009484196211964483,0.07979970037133795,0.08482970222761671,0.0013120681141974451,0.007023261037859076,0.001823131820968869,-0.0018463185630266399,-0.0030377600330070654,0.007538201184337424,0.015915312745643485,0.014647274169006845,-0.0005221232048462102,-0.028374616299596502,-0.015349708504271945,0.015755533370044605,-0.013309354571669759,-0.009788993604027999,-0.015041766699340089,-0.01271696482526414,0.06821481471912692,0.07041778947672171,-0.012000558992832921,-0.013391469289542858,0.0012679403089874317,0.031230875795013976,0.0023778849561102125,-0.011216278974300971,0.010229906980470096,0.011796075047304956,-0.00006325186606149912,-0.027897368311801472,-0.01956251199458885,0.007703506649768665,-0.007865014553634558,-0.00479200786116037,-0.013772269035549053,-0.006407329265445295,0.01809825749509324,0.008195518395144263,-0.00819680415401967,-0.013409367450125102,0.005148002904336324,0.03273125548064323,0.010739281304701562,-0.006725676437619561,-0.01573197699983293,-0.017625186509035638,-0.003441825302886232,0.0400693782522701,-0.016243988714377613,-0.01962240166904412,-0.0031996522485008808,0.002647129752992954,-0.0033899846256024518,0.003074910426247,0.025082921700986572,0.013554059627350182,0.0016701450306953935,0.0011079392625103373,-0.0019269796006162235,0.032287950066801005,-0.008423974533602855,-0.009069042313299181,-0.01530453803678275,-0.01837931314231901,-0.0020255431151199542,0.04145762862644329,-0.015207150667245255,-0.01916701469304855,-0.00992616764591643,-0.012254753783492731,-0.0160113171781315,0.029451344428322652,-0.002914637053726152,-0.01773886104452895,0.0025074351479048677,0.0028589703072306625,0.005490003233205085,0.03984616741613255,-0.011822194391100124,-0.013057636382952775,0.007944414430560336,-0.005458994195621437,-0.0019302298533520885,0.034590716567375515,0.004406175453576821,0.006610335041370321,-0.015366918791956617,-0.014479584575801379,-0.018937923970972822,0.027356707886121392,-0.0035352777546983783,-0.020149940593563977,-0.009184038954859438,-0.007058119158267175,-0.0013578768264574524,0.017337700995783346,-0.00474035667465098,-0.011802772118143212,0.004001074427880993,-0.0025462047251436056,-0.002452544686883975,0.02763359217412771,-0.004665532730659658,0.00038406170650218027,-0.000261208251394092,0.020615545514735947,0.022732775599570643,0.008383141012045493,-0.0003611771734921968,0.0024250204128512276,-0.010803251595905018,-0.008988957214558837,-0.00654894957634869,0.01803044222787511,-0.004662950381878856,-0.01217350641637716,-0.01105508035496636,0.07771187489517695,0.06352931229770424,-0.026832644403736977,-0.015218628777956187,-0.01037710534706241,-0.0033091643966575925,0.014370400329093348,0.012678972365475653,-0.0017736741296629787,-0.005559704014672312,-0.0021300902344037363,0.008699500202829386,0.01624696467462546,-0.0046414165478647655,-0.02455048880824487,-0.006957692659571156,0.006471609762545061,-0.009594119197561058,0.08825031274111965,0.07146893746371552,-0.025806779522179663,-0.014035613919465605,-0.01104862555277748,-0.017674881748634307,0.043450136938114226,0.004415249746073896,-0.03193705462462703,-0.021773568610826213,-0.022731362342353345,0.01107705521369377,0.02085706622603502,0.0016084948973181642,-0.02440404482789509,-0.010675230146563299,0.007516760889501878,0.0005415024235353845,0.007464628895750142,-0.004366318178009686,0.00393977241141381,0.006213551878336078,0.0054533541676053815,-0.011191280054736349,0.0459053593281905,-0.004926404197333695,-0.03591151229046546,-0.019610148262173416,-0.01938051482006913,0.0692553536118837,0.03341889742732971,-0.016335762360198833,-0.024206672473737874,-0.010377870258146545,0.007392796764011129,0.007128534402092859,0.012318446995421672,0.001091646608860627,0.004915303703271213,0.009180284671221893,0.0075350866716696755,0.051851811922899116,0.03615295219561229,0.005957341582747337,-0.008637021800950544,-0.0056048146219989155,-0.0026268757215627174,0.054741574897340835,0.03382358366135532,-0.009973201596530337,-0.01644741551750075,-0.004950676994163362,0.00490631261371976,0.004855158043852877,-0.011748420758765544,-0.010731304855519609,-0.0039670981921698534,-0.0017614319417454125,0.00751931603266497,0.03885632784264106,0.03499809503482246,0.005446782334977297,-0.006229328675801018,-0.004293070664272745,0.00040007713719887486,-0.015519836324009752,-0.014458703066625996,-0.009490694136602073,-0.0028078556167079835,-0.0024884149974698532,0.00035075972818799923,0.0008106998646509273,-0.0001675615315465216,0.0014159120409448344,0.002210113087951116,0.0010856133490049233,-0.008034687027041038,0.034787657673881534,0.0023804408508717244,0.0008118650484686008,-0.00036234938992413084,0.004099608238735974,0.030767085343583755,-0.013576071183789763,-0.002904765575428493,0.007092282105401308,-0.0006344625638599147,-0.005088187988705017,-0.007960969587914616,0.028371670094019863,0.012273368995405464,-0.008751093740643291,-0.0023550008562623534,-0.00008124901086856907,0.018919494546019103,0.034536232929251065,-0.004019797844133847,-0.004493078495951884,-0.007061867992680225,-0.0035768844993779715,0.02430346803444172,0.01130242227877768,0.00836316038287465,0.002196867735189756,0.0009314134455849163,-0.005781153221578411,0.00744631960381951,0.03569797316863865,0.015638128675157823,-0.012718340377322626,-0.009459855951374573,-0.007106402856206765,0.016449792408055545,0.018206785725210405,0.019005203229942376,0.007260960182766128,-0.0015333807030096715,-0.0032709526419339155,0.0009693097748016622,0.01625201324349758,0.016512169877388495,0.011545400872877785,0.010431757228741161,0.005331844047943152,0.017738808556053563,0.02582678121841445,0.026942374543610943,0.013039598056425381,-0.026180652263204818,-0.011779896452650896,0.03152039015193709,0.024443801588554054,0.030719943346674692,0.018393062613843714,0.005616314103251527,0.0028716231719653866,0.004433852732379262,-0.00042887644148219246,0.021544163454522865,0.023244454216529806,-0.0024381517127607124,-0.014952713909681307,-0.020040696743015396,0.02704697012496961,0.026507706773862105,0.012963020485391124,-0.01989630276231129,-0.008975449929622742,0.030944495189531924,0.005654773045538818,0.007101652340763007,0.0006197324609313052,0.014706317309107745,0.03367213424776703,0.025093666434318547,0.0003947833072299958,0.022660131800134663,0.025134565808704257,-0.00033838813354626575,-0.014587236904108097,-0.0222054317867536,0.008293133759302853,0.01714680167576522,0.0014040672748331338,0.007906948738461789,0.004657855984023527,0.003702966127923447,0.0037627626825341137,0.005004869260007879,-0.0018544968711435455,0.007535282652333986,0.031012619798421757,0.025001332095302732,0.005605913310860315,0.00672278200944984,0.005215458565040375,0.03612320832590744,-0.0032162024665684194,-0.0076744421055437466,0.0043925110975215,0.014704361407353365,-0.001191804890690938,0.004667375789997302,-0.0003887462309089872,-0.0024679993839802445,0.023975208566101455,0.016338094020971323,0.0027504859849644273,0.007903539277294678,0.007673687174652603,0.016608227957147413,0.003565221795272283,0.0019904299919218885,0.0015449374814272374,0.036926044587909664,-0.004260300710593132,-0.011044329499635384,0.007322736507414191,0.001287196039296782,-0.0013610950698622983,0.033732564529168924,0.005942175043749611,0.005795504320157657,0.020268101241108262,0.01812104427335416,0.0033103158006097754,0.006999320398594834,-0.0003889006508531564,0.009242167517087363,0.02374000058435956,0.0025507202953535995,0.00290515871294279,0.004173754597566674,0.007861405643772633,0.020889179849892157,0.004536978505960501,-0.003671513728232189,-0.006177831414541402,0.0285526179550995,0.0024308490827174927,0.003209224743547602,0.004761380332184346,0.02579561459289356,0.023866117794387756,0.011529570014501826,-0.002578493349845382,0.0050022201886983034,0.020353606091888254,0.006310555473498185,0.005169165689333629,-0.0002458452427622535,-0.0017417285201792908,0.012748639175606705,0.021118503183315682,-0.003480941011039293,0.0023018885232945754,0.00003637765400522213,0.0029960787966118014,0.014693161645722517,0.006828705443185707,0.02178330263298114,0.0237114091821304,0.020919929691809256,0.004781697901444046,0.010298183361584338,0.02399365381574021,0.03292108013265361,0.006818857399349842,-0.01936517398193416,0.00257322646644594,0.017920164892620688,0.026297863787635257,0.0023717256711078714,0.005811023122518995,0.00557897273907101,0.004760112772519435,0.01740258502253852,-0.011608298781611303,-0.016639686841582214,-0.01420636746983902,-0.0006845741570620087,0.01070822522033422,0.02103091768336897,0.02248247526483325,0.03416847790638556,0.007892023157910417,-0.018473679251026186,0.00136255496746095,0.020863899065166842,0.00851568422653531,0.015701603095139443,0.002112527961107337,0.011053204798421647,0.01441337648629873,0.012372131591042055,-0.011902057480646551,-0.014290841139491499,-0.01004757850251659,0.002595025284477923,0.011140103307608142,0.02091431507322529,0.026535014306531015,-0.00003055139536278453,-0.0077403610927871,-0.00432912004036535,0.02546719968960198,0.03514186864911575,0.002165969371883276,0.004747429297683846,-0.00804932731097357,0.002387876163869591,0.006408531355904745,0.004852930754678374,0.045428365381735905,0.03700334243750377,0.0030757107661269875,-0.011688038956835439,-0.011265172466911432,-0.01186072601818834,0.016003317482447148,-0.00404359269380825,-0.009773792132351251,-0.011679829319850198,0.012227892331951802,0.022489403043378087,0.03593147053215883,0.022717504617659395,-0.008146433220344983,-0.003298385768223442,0.001038867686255609,0.018942456796792146,0.044072704795877916,0.04070019925718173,0.007113813083696186,-0.00433699323693911,-0.002849517716244056,0.002070766757809743,-0.004301366962853776,-0.012033478061048625,-0.007445905587172678,-0.0003357548964048203,-0.0008229139630310029,0.0009240972441867395,0.03207262628376944,0.02746668108232737,-0.0003538458164996497,-0.0005015898462825777,0.0018705727892995632,0.02094992353956525,-0.02465805620396494,-0.005493137887584304,-0.006111609416467369,0.004004921265404374,0.003534649489302278,0.004494508403933823,-0.0063961156740729355,-0.00024637618717076226,0.010722968339040751,0.0019529133829662882,-0.0034479551815445454,-0.0038222154879752872,0.033235144222174016,0.01611081019506464,-0.005245488781977272,0.0005780672598028829,0.001626642368909713,0.021200345466845037,-0.01624655271652749,0.015509075411681705,0.0032192761862979177,0.00007346193245999154,-0.0019283769562736764,-0.00996244032874061,0.012604871082260206,0.028874981792327423,0.0036473889406527793,0.0002852990958450918,0.0014070061254295655,0.008212310796221896,0.03298104160937476,0.013727506857412293,-0.011750309532819598,-0.009564110209626353,-0.0066758323179503185,0.015937321388010715,0.018867806502176572,0.022259834685381473,0.010511603384660083,-0.0011790198221114363,-0.003931490759333865,-0.0005018080642439538,0.008640673182502365,0.0323391212312046,-0.0030744045327758865,-0.006367721439757606,-0.010851958431250768,0.001962763668954652,-0.006367641536941982,0.021349279167888577,0.01338849197092667,-0.003261463060716849,-0.01075786494759651,-0.01888000674498946,0.023018831086514136,0.03129775913024157,0.02291408948012115,0.009762767257699366,0.0057745366690659964,0.006694132331807389,0.0036889691499906846,0.02556079164611675,0.024867267926110867,-0.0027257300658514506,-0.016993914824393195,-0.024264395928664202,-0.0028381218613798454,0.034470925593748564,0.02959158165025982,0.003910943592752399,-0.007261586615928463,-0.015037068459896935,-0.0011029645349341568,0.01440097597763972,0.0272667080817876,0.029011830459325882,-0.0034004567351210357,-0.0026051828480038045,0.005294527742631285,0.02162607216512538,0.0205518680356397,-0.004147964517262595,-0.013332758199539881,-0.02038472089908233,0.0034827676307096923,0.015143334674604091,-0.00017065368820251542,0.006347578146558043,0.0026790380174675074,-0.006134730226026293,-0.004908226776923696,0.012852636184119895,0.02709295965470657,0.026283724593206364,-0.006369989249860557,-0.005553500173143517,0.024176847670751497,0.024712841954170905,0.026692194299595982,0.030847162216864437,0.028710594371932595,0.021038141894360953,-0.0007300590131242993,0.00718461914830165,-0.010957058192466042,-0.0014832191866565303,-0.002683479791834258,-0.0058529351301552035,0.01559408890452446,0.010379700427855998,-0.0003685694715178576,0.00938765704565838,-0.0016687105780239329,0.0005227791910220061,0.016306002177703928,0.018363966828293124,0.020969230704439453,0.01999865010622388,0.01890807001356116,0.012164147035557012,0.02828704927010623,0.021373684271278927,-0.0003208994093735915,0.0001778825539879056,0.017831447766880355,0.026077731429295203,0.014554852418748489,0.00866938431756923,-0.005021758789847897,0.005665586523103284,-0.002775196867058022,0.0018502925031409594,0.01716467683829296,-0.0026239995665625236,0.00040911229349451005,-0.00007696246018005118,-0.00019288390831273154,0.01350351950045458,0.02450262347553835,0.021276280129072966,0.002201912525821472,0.0005693044675923911,0.015329413477562689,0.022888931370657367,0.023958612275384608,0.01708659788205796,0.008274345365818838,0.0040560874346428095,0.002073098842518652,0.024918382817727854,0.014205523800240843,-0.008400837965553003,-0.005392667740765241,-0.0010231115050407572,-0.0011812887328700224,0.011053481748465085,0.014796927263359913,-0.006126018112749178,0.0003647692777635442,-0.00482463315996829,-0.0029803389243895674,0.009644453158954146,0.020573331621956497,0.01687104591718542,0.00656621707299044,0.0013278998563530855,-0.0018160506424099877,0.020840808806474834,0.02031108153162132,0.017793095381152355,0.019154398021905585,0.02096374162793531,0.025497163823165282,0.01572864789872769,0.022129321114109757,-0.005150233965009276,0.0017234398833065928,0.00531121706303564,0.0062416348733172105,0.016734760300167472,-0.011951181459580365,-0.014818277003116193,-0.009538170776736361,0.0006961842874244552,0.010063010968973616,0.01980851902946519,0.030448925909850058,0.028437261104862832,0.027443475410646144,0.032554588830606274,0.03207272091692204,0.02195148232913594,-0.014899499361323112,-0.012578663463432341,-0.005797154968369345,0.015792221858595062,0.01970211027445312,0.010564572813488982,-0.007500791325399836,-0.012321837018194101,-0.006123684646791436,0.01003096112332583,0.01826233185175193,0.021956930103074576,0.027432922255204304,0.005201483787528138,-0.0014154940826795967,0.0027935663190967607,0.031127201479343607,0.032170926194994245,-0.007429965727509254,-0.0026039435880893533,0.0031387170386075625,0.023414090861732753,0.025505649660439268,0.01280026223850034,0.00676752775497057,-0.012244635872216914,-0.009562334167484388,0.0001296686457547784,0.024436993242937476,0.025878308881793478,0.01885499504163336,-0.002214166756912093,-0.007827176329365483,-0.0071775629601198414,0.01876088923333434,0.02509377715221739,0.03823781951185374,0.0284059893225125,-0.005305839098373277,-0.002415105220167098,0.0008777486590314432,0.019032155667653896,-0.0011191844007993818,-0.010880884917074927,-0.009870159096659344,-0.009735071144456963,0.009311687576048066,0.011916366854514382,0.016735870478523585,-0.007935735283962514,-0.019652430373154287,-0.007967431478190129,0.0013600924254975717,0.03262242954329211,0.03709034365498571,0.03060513238569952,0.00001999775791924955,0.0015526915422313106,0.004741572492282249,0.023991150324745535,-0.015968793455127195,-0.0010350626165573354,-0.005541606375814346,0.004329696711332751,0.006647611075062168,0.009054631598854538,0.022232265393332184,0.0055305394558578126,-0.004067298675092423,-0.0010402557595847978,0.004941860260573058,0.030583608546631287,-0.013720417645055698,-0.01571659455724852,-0.012116085481046819,-0.0021471616875635897,0.002279512175105885,0.01965570820769575,-0.012045269678623759,0.014473552393050327,0.004215373606197098,0.003023720287208092,-0.0012104666147740603,-0.008368004799576678,0.013696227374972432,0.03203748847032976,0.005234285050718491,0.0007547767845576286,0.003547086174967513,0.009141872540602856,0.0019486025113617,0.017238924116895944,0.004656905453392173,-0.00020659232111010033,-0.004909510466532797,-0.014005185566716665,0.011799940739078592,0.023876349460997374,0.003384670304720247,0.0018111568245690124,-0.0067059034353813335,-0.0009954517878143709,0.011629808677406204,0.03387140381745823,-0.002996949165175766,-0.004614210682680085,-0.0062396222735484706,0.005479841254264928,-0.0038306549832273487,0.02736787627121154,0.022217689862516907,0.00035808233297856374,-0.007705079532742317,-0.019315927401449034,0.0044044872730544015,0.02220914599469666,0.00017785753517448601,-0.0053412314013058714,-0.02239711722290709,-0.010365969265777937,0.00392842259555797,0.008294635172478573,0.02119635493082478,0.0061243530846738226,-0.00009584559179810998,-0.002042422484187324,-0.009375203923696812,0.02101148070519097,0.01740741180407384,-0.0046276106727869025,-0.010340123915155304,-0.021686677592680143,-0.007764839718967819,0.008539785024073553,0.019680044023063507,0.015663314583777368,-0.0110933195184168,-0.013025957875241974,-0.005445842509559483,0.008360771296298036,0.023033994056377204,0.003183195175127191,-0.005702971380628571,-0.010854513902888501,-0.004093624968073857,0.012307759350171633,0.034737586567573565,0.03373615875869404,0.03212146022733946,0.03223353566402211,-0.018365743378481562,-0.005923838539240013,0.006279602535389125,0.002631144710187599,-0.017430467476720262,-0.01741819834716444,0.0005038680152337542,0.007038528908178419,0.010962196703324744,0.008121893027707747,0.007685118349331405,-0.004418741472028107,-0.013609589960129814,0.004395066465388145,0.022191022994501337,0.019051169026204372,0.01622102080091093,0.014100815969074589,0.02421834747034979,0.011053276504041218,0.02392907198333941,0.04032225923614623,0.04032910900265579,0.03318905497954597,-0.001428528186974051,0.0015334675271012064,0.002264260678171609,0.0013954391478073758,0.0038584726612732067,-0.004867109400217822,0.005221032262184491,0.004282554927727712,-0.011484047968176158,-0.014794488052651595,-0.003898398992989339,0.0017774984841740715,0.020363970199388032,0.011852610606819783,0.01657331678631814,0.03128883297790291,0.03248677686894617,0.02411375486428312,0.026605065454190998,0.006663320277334721,-0.00639058852560176,-0.020044953772120715,0.00597618877709074,0.021975837323971882,0.010259269096136758,0.004708678327451493,-0.009538151136225538,-0.011047180362570824,0.005239089259751575,0.010633627313680543,0.01168956980727985,0.006033991521043114,-0.003331599971130808,-0.004850823880511159,-0.01195561893286511,0.008622895672335807,0.03543759802291238,0.009366611225332977,-0.004380579538640338,-0.016858327181118616,0.009553105602892792,0.030067900681769316,0.03354684440593171,0.02736542527279615,0.00832435332482438,-0.01006808603625278,-0.006977808041209287,0.0064817922876879595,0.005479544008261561,-0.00461248375511758,-0.012295134384006375,-0.00829883700078903,-0.009707889241563343,0.009368739469140472,0.007742396879110957,0.00792502443204284,0.008741504590022355,0.00766830926870693,0.010563940597383054,0.000747449785463045,0.022871953666170976,0.020886643984127866,0.004730898335001998,-0.014606932881903397,-0.011206369360012198,0.0032622326542451766,0.010690562570899618,0.031327677264730354,0.03153249294739734,0.0326889639579375,0.0105054417026416,0.006944661102105899,0.012288264643750097,0.009546599882605911,0.011849363267971029,0.01613271732209298,0.0193195524263203,0.007618822466495341,-0.02665584037727013,-0.018355535715029618,-0.01235422272472869,0.0012260866137889814,0.0014151807096670686,-0.006238868854565,0.015380731496524701,0.04064084723119937,0.03815107811613357,0.03994081641445089,0.013652159187798177,0.008718086416422237,-0.005533826039022317,0.0063169297638642815,0.011811085082103722,0.020845501566230225,0.027311718428987147,0.0017964075743613507,-0.014619062025611017,-0.00934816845375356,-0.0049877408796340185,0.013050797319577973,0.017040832380043655,0.008130192688949257,-0.000390304977667246,-0.013004679251837186,-0.008881917462127884,-0.0017732978555996639,0.01268200912610518,0.019505915768620374,0.008002743376574858,0.03057775632259489,0.034343840960353464,0.0353763955401161,0.03671897965517278,0.011809743965974081,-0.009358282630279414,-0.016588623793635862,-0.0052419144271820504,0.0059925567977589115,0.01930429072607453,0.018216610829784693,0.002606690328102552,-0.008434779580106055,-0.006806549986189396,-0.001508585692290825,0.016214728961271675,0.02123935608479096,0.023757457446492068,-0.00017173947738433477,-0.013217394644087496,-0.001971722746881911,0.00476972007177938,0.03871734320347938,0.00012094087580001548,-0.004436132819292182,0.0008701488177711523,0.004664728969088276,0.01710303200757801,0.019420918105605128,0.008334970668946671,-0.006475329637660889,-0.022541612692489294,-0.015751852849819458,0.005734121488870046,0.03120985707742062,0.023124871961235905,0.006178017813839738,-0.0033666674158086152,0.0001973130207742721,0.007515869882090038,0.03243454180905504,-0.005901353513769989,-0.013215036136589916,-0.009089742896806375,0.000373855184266,0.0033892878380802852,0.020322266765551822,0.013885969706576153,0.006788321140659538,-0.010281522026154597,-0.006227816720804952,0.008928549551779769,0.03131659896735396,-0.0015795295277627262,-0.007272506806682679,-0.011854597701150597,-0.005603005326552062,0.002042895824238998,0.018425519934518634,0.00118191015991322,0.018675349071145906,0.0020649561685065314,0.0006313123555405482,-0.0029160299799871068,-0.012084795028952244,0.012302750128002506,0.023800732727153818,0.006012759886607705,0.0016102035505589757,-0.005658603717502894,-0.0010830117133246578,0.012202054700286145,0.010716396238270472,-0.0008567154552814641,-0.003929558759610396,-0.008240461605956295,-0.011483073876881671,-0.0007038963987515261,0.014612574510494504,0.0013375170322130448,0.0011179504383906909,-0.0038461420600376553,0.0018805085975368912,0.009525589337320107,0.021653927797821833,0.0009892865527894332,-0.0032824804058201877,-0.017962578476692314,-0.006815366043115011,0.006751244780043358,0.013078200029450704,0.023632832637830326,0.007627008570601191,-0.0022820798198231796,-0.00007415114876255745,-0.010242787382005892,0.011480416346287775,-0.003673677702464558,-0.010027793545710883,-0.013891469709230225,-0.004610845222034465,0.006905897943611548,0.012932711334292716,0.0154372505404029,0.004359658611850755,0.008780394977241148,0.01213316667770058,-0.009806888304338663,-0.0008587141559522493,0.012198635871958805,-0.004561455009140003,-0.013586747981120806,-0.013636724312273587,-0.011713568773449942,0.005952584066371841,0.022529018336125316,0.01861074225332116,0.022022444198050505,0.02334154485843408,-0.010509242961938663,0.0010635900154083767,0.005223293648089046,-0.007596100587134042,-0.005769840062563046,-0.007200540039351027,0.005970332026242045,0.010394246778022191,0.021343400234902016,0.021539613799914488,0.02876320519507066,0.02860282201389219,-0.02406764023832059,-0.011094540162373018,0.0029218422839285096,0.0021675388388417115,0.009765752489995656,0.0073308388615521075,0.007650624085626994,0.0008807901689955825,0.011006831952768728,0.026376264239637574,0.02555124260836328,0.014748011011197455,-0.004451901438627712,0.0006497502724619681,0.004216419695169025,0.0041331419019433775,0.006203278466264686,0.0077586256766496945,0.0060277111742816575,0.004157120158595805,0.008464216191726338,0.016377026796811203,0.020178589684581277,0.0187247063134138,0.011449193681654595,0.001055621759105184,0.007054043672114889,0.022463854309355498,0.026048933453747,0.016552205470169685,0.014302077411395631,0.00020548635016458857,-0.012260169435984757,-0.02513981969274771,-0.0028569041992697257,0.008185127687549424,0.010240069050749772,0.008655074510338295,0.004640703894358287,0.016256765550024515,0.015808279221064384,0.015949863884445376,0.016524518091854422,0.004249261000702036,-0.0179854042609339,-0.016626691440913374,-0.0018871937031442018,0.0056801527327115155,0.02682488708433832,0.0017257745752303117,-0.010670298566787027,-0.02003138969392486,0.005705841343221397,0.02164039354361699,0.024227437542695414,0.01975768041124411,0.004708097156442412,-0.015943713170011347,-0.015375039223207147,-0.0028486113840832054,0.02911109154808196,0.009842950885465256,-0.011720336528028917,-0.011837804524803368,0.0024355377616444855,0.015753262383692394,0.02120768307721753,0.01987441457223997,-0.005989472342978644,-0.012139941013735979,-0.006980235644027459,-0.0006090571705454002,0.014383964424353713,0.007903548911072264,-0.002285199382470125,-0.01786206530465372,-0.015258357841278295,-0.000797804496561059,0.005165017902375186,0.026277290338070053,0.025508301339998832,0.024957213924140076,0.001870436349407513,0.0004418824226399279,0.00969322848592392,0.013255617031708074,-0.008822498567440329,-0.013759965938753073,-0.00970694793399346,-0.006229555797156288,-0.003605453238452784,0.013369674761439384,0.026711553335384806,0.02056354364842084,0.008029844410400933,-0.0009659149509299394,0.003988789066885842,0.024603460803976275,0.023442314824339085,0.02532518970882578,0.004095777502791114,0.0025596015280649363,-0.014424750988039293,0.003507488126320096,0.00925580909038943,0.006171415936540978,0.010868600902211936,-0.009717245547717815,-0.005767599772581132,0.0171224893128095,0.03025473578785248,0.022284288101022114,0.011280837789199962,0.0013584067512972286,-0.00944026636217228,0.0006363032971904759,0.011421522219173313,-0.0008257579532973088,0.008250655257339357,0.0013013201571555673,-0.0002507131421730247,0.01792006282824829,0.02389502694163342,0.01926339241863781,0.026909415341822836,0.004425573647784557,-0.015165314828105373,-0.017566577820878948,-0.006726295933293198,-0.004199521738078098,0.007072441884838541,0.008560446501237315,0.0019125821828231341,0.02295594277473201,0.03457778221075508,0.014926369019415518,0.021155173937002572,0.01080783201779766,-0.006045078954906561,-0.01073877793168913,-0.006186615179190258,-0.008943755472126665,0.012841344061764234,0.0069153308581229095,0.001038047736235697,-0.004171765004676949,0.0005277379994721768,0.007817639685555237,0.021672145004668686,0.024308359863208062,0.011920811809547485,-0.0017978870267014496,-0.018658330317929517,-0.013621054083733488,0.006778504612133274,0.03521918161823674,0.010721840521903678,0.010863582798892798,0.012757629092880878,0.005591319462546298,0.02247324805477169,0.01629970696800914,-0.0032538316028189844,-0.0041818422224914505,-0.01870037390172439,-0.007499468745045261,-0.005395207502908537,0.009629158068220355,0.012894691666097562,0.00591753782669842,-0.00997444133462092,-0.005364047406600277,0.010644205746634385,0.03217913146977686,0.004213866190622575,-0.0030780388829520656,-0.008039265477256176,-0.003615566932024805,0.00319290820024497,0.02218772490812959,0.0037900488180663133,0.00591203525740669,-0.003986992732996217,0.00009900500746522628,0.00006607961101400545,0.013903772259461846,0.007154247746998492,-0.0011548562667961849,-0.009090568867403767,-0.009014084357147815,-0.00014491221336044498,0.017068454059624177,0.009199994384463693,0.011451669994840973,-0.0030465933681448243,-0.0049828071430927925,-0.009754078137580986,-0.009257011560962545,-0.0023402692360176025,0.012530832629031713,0.0016787173740179498,-0.0007488491872088254,-0.0044181663117638425,0.0018340142402275654,0.007149713292771719,0.014655165374695411,-0.005793856654506045,-0.0015930395930061566,-0.004449492393143042,0.0015833874988937886,0.0019049037596983222,0.013391337845323096,0.0003370208827934879,0.004540407506105792,0.0004217090670518693,0.016850173496631135,-0.007073922286085517,0.010287289510511922,-0.004576116776400263,-0.01186640176357527,-0.011948714174485247,-0.0014049976714287826,0.00878914630153379,0.01336535891570239,0.014571566883459883,0.00153088127009927,0.009277350051488702,0.013611467655698985,-0.0026595774848767293,0.0040333020947732785,-0.009152092458850703,-0.003994507764650937,-0.006997835713499309,0.012533751858381645,0.0001246402626088785,0.0065847603661835195,0.006415566500991835,0.006199827577698509,0.014788756633114805,0.021539557819661694,-0.00648372822982235,0.00025817178241443225,0.0005800877162005333,-0.007262927407361126,0.0012562758683975744,-0.002267825752433137,0.00438957113199726,0.01184377058792716,0.01919857310208252,0.01946441465085275,0.03360922977616123,0.027448081680490035,-0.014037893891275218,-0.004106555715842759,-0.0035059326008524297,-0.00512755759844297,0.0005320313855950639,0.004390202919434793,-0.0014436283518949248,0.003450580554095383,0.006911457649200015,0.00894101868437511,0.015151213766748767,0.01665394575219845,-0.002438901384481195,0.0033167865583184565,0.005128663931825509,0.008716731615421887,0.018837444786373128,0.015625114964219075,0.010744468179302398,0.014590473891132539,0.014111802737928059,0.02642826301585772,0.024598226634895193,0.020756716265361335,-0.005735890725845323,-0.0021127568938754246,-0.002673361422942431,-0.000688686883835047,0.0011414425238143885,0.0019582293385376403,-0.0023690290553155537,-0.00315450033313754,0.0020770829800322186,0.004971858945508637,0.019737394084827463,0.0008630585434460648,0.01145470728332889,0.010853978335402305,0.006688383922613036,0.020996251088648946,0.023712211422569043,0.021100681097270445,0.01919284577134721,0.010070942934829737,-0.010576865219300555,-0.01032216446680717,0.0011969628277273099,0.006977533148235641,-0.0008291411338569717,-0.0002397799443139032,0.0007563959061975382,0.0003396381294036199,0.009392900849451675,-0.006112246206671945,0.008852939238128594,0.00011117914512568979,-0.004916986042643106,-0.006886669923722586,0.0012951831815881487,0.010971247730221179,0.025800413293352798,0.010269926545671337,-0.010288858703585656,-0.011160873729321558,0.003007718191983949,0.014585627176166835,0.019743121558917047,0.021519931859539553,-0.0026703044018712378,-0.010733221122727383,-0.007745471021727465,-0.0030320658530340874,0.020353120587291475,0.00405154621102601,-0.0035907206964135756,-0.002267181486066915,-0.00022338316707368124,0.011602379524367917,0.007305099151925647,0.009546985270025515,0.00427715186186727,-0.002196964552596617,-0.006270925357808931,0.005503279333274651,0.012469774881836789,0.01311142489006853,-0.006723556911900997,-0.009675886686347756,-0.0046511765544463785,-0.002157920294163193,-0.0011952505527191293,0.016279124630739897,0.033467665185122425,0.02390006131183765,0.009663968891031598,-0.0020074951294127004,0.0028555511182112837,0.00969949776298203,0.0045042218682399444,-0.004100783696710372,-0.009890918971759153,0.0014380455164689574,-0.005484275601407416,-0.0020220086919760837,0.008677249699593298,0.0032983654443499294,0.0018877119006611804,0.005151602361774252,-0.003535364397593189,0.01581612056354474,0.037003311907412004,0.02902527806077384,0.015628897569273884,0.004730535539321723,-0.009570737364336314,0.008535768832959516,0.02243815583304978,0.003061689561823289,0.007534298487728108,0.001700751306137129,-0.007434043414941658,0.004256323842269407,0.016546708179783702,0.005299914409718352,0.005073569996632321,0.005863529967390956,-0.013887690101117617,-0.010848790638468461,-0.004019263171403795,0.010510302761430796,-0.0033992668086934613,-0.0038500225028484103,-0.0018814770041016761,0.02417514145332968,0.03636943143937326,0.016097971419568688,0.019428744799179852,0.011314409037051575,-0.007054207153545246,-0.0038187025205191115,0.002697046913160734,-0.0069343070803882054,0.012362617741377735,0.004347347997136501,-0.007180650492471532,0.0038682725712541927,0.01457419946995933,0.02001393817105149,0.004999863264642967,0.004111955419428479,-0.012628230944003982,-0.00012067224549262858,0.00009052254905578312,-0.0010339251624036428,-0.0006565140588466908,-0.011193748178008476,0.010541285896031509,0.009225041851181285,0.010173831495071018,0.002011565237747908,0.02432816588301642,0.017372054595951637,-0.001772194987426438,0.000783176618659364,-0.015570983733503038,-0.011560228679039275,-0.006892770941718674,0.009378968919198417,0.003087744972661866,0.02259056506017643,0.0174581062294871,0.009318065510786197,0.011706712676107725,-0.0014112681121060745,-0.008384995820105,0.014123984600432833,-0.01504301251541814,-0.004674929196967466,-0.0014587876059451884,0.003954994150974941,0.0010457228195613717,0.004637655740528018,-0.005854514279238809,-0.0019141158865148347,0.0007222744477991692,0.015348319467012931,0.00821962904844508,0.0004066908613233035,-0.008718995932820656,-0.010349365005503468,-0.0004652892825110414,0.0195445222178455,0.0012487645213813139,0.01735132093919092,-0.002225342461568829,0.006114534782426966,0.005663154193572332,0.012319959133455625,0.016922140323357142,0.0034058461280989244,-0.004952395394153564,-0.0033129573279699082,-0.0017118801590780635,0.0074972367678805794,-0.0035861632688003685,0.011491299302182597,-0.008174274181781946,-0.006149842101588629,-0.00687097022055598,-0.0027639506077166754,-0.004943739172239744,0.00837664531938365,-0.005199364129903396,-0.0015829140040271037,-0.0061173525487969995,0.012624859602838821,0.014060324589670372,0.011530834866761387,0.003990395226475553,0.0005250043588034506,0.0012719634421077645,-0.0062074946058197225,0.0023663956112482784,0.006468091312100125,0.0024402008413137483,0.008653888032162728,0.008761324250964599,0.015054018747964868,-0.005193795380530892,0.003603335601081636,-0.014180566781257183,-0.007332973676266228,-0.009525469023789254,0.011649727791168869,-0.0031911256571423774,0.00613689447533992,0.0028301427979371863,0.001569922280598196,0.011497686683000656,0.016889146510346058,-0.003749147681430256,0.003640789281267845,-0.0034383136543586546,0.0016050072374348052,0.0042588957845754415,0.005022313685642785,-0.0008378927553953826,0.004197317144060402,0.01036589168477246,0.006379575112282987,0.00705959738358264,0.009069706241284786,-0.007646405207399363,-0.00038949917036946346,-0.001830310908254068,-0.0011936521297084815,0.008489587643372288,0.01227818329276831,0.0019814203136906197,0.008431109371701153,0.012580782123976082,0.015753856171861088,0.025074613089930795,0.022717107756526543,-0.00507171153312819,-0.0007900802150428765,0.0035591546271694463,-0.0006992006249041798,0.000168294506031657,0.0031189968423230127,-0.00248400659257509,-0.003215600729731312,0.005109560756729392,0.0018253893636451144,0.014265175009189595,0.003958033619502124,0.0025289321768377677,0.005664054864339726,0.008413446278998815,0.007950585839798036,0.016494536878646347,0.014735280300911065,0.011209285337422057,0.013511166483885102,0.014602526629583893,0.01859932952123625,0.028925784183062235,0.007200359141469698,-0.0037491759261915284,-0.0005411108468862742,0.0025420438379270124,-0.0037415182176892803,0.005025250231847953,-0.0030022058634890363,-0.012674192544237989,-0.007556476955342744,0.0039060179488421306,-0.0031044061205014774,0.013699872855526693,0.003191870360283257,0.00947121547813348,0.01042301669772669,0.009848904435202106,0.012042148697592516,0.024789451075445352,0.004897679121222919,0.0228921107233271,0.01154985956444446,0.004454512497297358,0.0031884010339560745,0.011138003245333579,0.02326220361221861,-0.0090439965151957,-0.007727937096327575,0.0009311061511785138,-0.01085712832405129,0.00243746013091003,0.0024180334121919884,-0.010485521020267799,-0.0129219015128491,-0.0011549594937722645,0.003779717838700894,0.010080407709862972,0.011678364983314322,0.02440257565175357,0.005274541366522477,-0.0017256944564681645,0.0018602415208610393,0.004595146292248524,0.01897003593655349,0.011097866536282681,0.018075433400302536,0.01002619789808831,0.004431855001992841,-0.001603580062473146,0.010657169182392423,-0.009474041027121329,-0.01036398290204435,-0.0022063657566087397,0.0018930756767344269,0.0047507083431315355,0.006432520199955158,-0.00517406502420692,0.011574106838765258,0.005981160084723125,0.004454565278178832,0.0000334432232656689,-0.0001348374348735808,0.01008062352901227,0.01708815499193071,0.0108800886228534,0.007339906301035962,-0.0012738198020340473,0.011803871114031077,0.0006121078839250423,0.007551531939622625,0.016872348587400183,0.014491696699158427,0.006261389523058,0.012790494481351578,-0.007168624551134283,0.012911498947459774,0.009391851587664644,0.008008183053481043,-0.0006693386506680298,-0.0025175195174293066,-0.006911251912842224,-0.005697758531669676,-0.0017364721127271546,-0.0038251855467974927,-0.005674113692256506,-0.0015585340300500088,0.0018119234264120181,0.010613032845827944,0.0259579222839354,0.020223648913138867,0.01232057648805747,0.01652620364371136,-0.008038087571056845,0.005095524232298587,0.016113453358644038,0.01928031060496586,0.00045924647652390195,0.0009236230398152124,-0.005508234452373497,0.002842328286354279,0.008834980869574082,0.005509100924766543,0.0002941731833422674,-0.0003965033446252178,-0.0004600239942833675,-0.011423076337860688,-0.006208584547216269,-0.002544427752856102,-0.006259004808256197,0.0040831905920165,-0.008692673240965272,0.010056432955039695,0.0224591805992189,0.022563560096105714,0.00570106440582356,0.007514557221867601,-0.007387121116026165,0.010352435485917385,0.01034291671324321,-0.001790915986207779,0.0011151042333714743,-0.009042970462100001,-0.0009434285675818735,-0.0029245101511050416,0.004856662172672801,0.003389553942788064,-0.002704143846242572,0.00693880844992526,-0.005600094924148433,0.004441866343848492,0.00378935244684325,0.0037446067549944772,-0.004773507434627054,-0.007082659177100635,0.005977922546033796,0.020683327154441544,0.016723643627072748,0.0025712581304564693,0.007701647726496612,-0.0024488708430552017,-0.007877402203894103,0.013595465224892642,-0.01713241978249803,-0.007684528235495038,-0.006833956511357153,0.00264975663674593,0.007954370258603126,0.013247189146011735,0.013966656077615483,0.009601397828939682,0.0010864541649415692,0.0005221857640123019,-0.015336029663733767,0.012633955223667791,-0.0021586147844752227,-0.006718322605831637,-0.003734879823878887,-0.00022034979337406057,-0.004149329245803754,0.012411009950838783,-0.007021386296381554,0.0029566516169323245,0.002113669695516442,0.010009581429156953,0.011929938035556711,0.0021002157777938544,-0.0066873207936624475,-0.004859813257638886,-0.0022101262913070616,0.0033727473031762135,-0.003787829249541238,0.017769049229532163,0.007898584543417776,0.005020618671442438,0.0024674325271244663,0.008794081512762127,0.014398830814596347,-0.0028839071541122666,-0.005227630597256378,-0.0006965866751569239,0.0032094268927684287,0.012180665809484768,0.0062514681258864805,0.007285383855261037,0.0037099483869243864,-0.00047644064448829917,-0.0006470256290675838,-0.010301574644630855,-0.004267962766682944,0.0042980262910862835,-0.0017684075334474607,0.004303979080364275,0.002386470303810309,0.009060481281962221,0.007468318610870085,0.015205472251949879,0.0019427563165989603,0.0015232961576439857,-0.0035289730682634495,-0.0017801809785676418,0.0016095626885901456,0.008914150834427275,-0.00045885965305003646,-0.0016722984945785925,-0.004595633177387551,0.0042275622573621965,-0.0010311140467513158,0.005347810754814775,-0.006435130359318286,0.0009222782398374784,0.004926086614755482,0.009456446265213083,-0.0038714120213111983,0.00299532993890092,0.012483590141587501,0.005863101979442901,0.006240710052811653,0.011917454567697591,0.00029571714911574186,0.007586783491749991,-0.005967886299823807,-0.010837672761214195,-0.016117837180229556,-0.002544983655415894,0.007321549003802709,0.011741275419017207,0.0008068531606828936,-0.005859122714433524,-0.0009289654080408844,0.0009506535533302615,-0.0025548287119033794,0.0021084603258994397,0.007782291417054135,0.00330156896291984,0.007517882359939796,0.011049936815398287,0.003265983176195582,0.005249851124905189,0.012148042126937745,0.007115168543133896,0.021768882243321467,0.008292916613930505,0.005331940106734491,0.009717771085621286,-0.0026785370959787275,-0.009390568059826939,-0.002153675497552583,0.00011934849663223945,-0.0013446276199407115,-0.014519097052511889,-0.006556177764735028,0.007833270546539147,0.014772197648784471,-0.00016380788121217845,0.00023151528716784556,0.005080283366874688,0.012039446928239822,0.005147199732263999,0.01608549791130919,0.005425082412130024,-0.004039318900666423,0.0008358346420483143,0.015581766732339334,0.005951175499177251,0.019396601739092256,0.011205354272387962,0.00029079690316142847,-0.012885042998384775,-0.006426669275090328,0.002666281355092908,0.009027312625208752,-0.004783000309064039,-0.012139333933555584,-0.020155077113371615,-0.009060331656133187,0.0013344969852337914,0.02779872758682522,0.012974681353975054,-0.005663356020402393,-0.002397636353164996,0.009904308997639208,-0.002170026209788503,0.0137870682725635,0.00854275726858943,-0.004779839404157895,-0.0020667961624278672,0.0081653768496887,0.018346148644895203,0.020009292313808602,0.018121751666313305,-0.011433025231410229,-0.018681479890225346,-0.011108580705025016,-0.00416972538895561,0.02147472297281434,0.004250881995056217,-0.02427273670606371,-0.01782721555388306,0.0008811776409269633,0.026815180968982433,0.015046067630459846,0.008920653172544039,-0.006001905522475149,-0.005859395710973588,-0.001012266765662917,0.01226742302246135,0.016391364000994415,0.016989925141987664,0.0007088433815973514,0.021087263634554897,0.018222022356208782,0.014893714832983278,0.004613571049695243,0.005341190766629699,-0.0250590638044622,-0.017550653858430503,0.0005366522672880664,0.022622288069660268,0.009181823498113346,0.004635465022866946,-0.025221572365687554,-0.00048721006889655726,0.0189333435213457,0.0159597587885014,-0.0010602610074243047,-0.016191679932578,-0.0012091830667382347,0.0219146546173042,0.016079330886177363,0.017509992350382222,0.010482480283321577,0.009438760697244683,-0.0011740548730356738,0.007833789362255181,0.014177140373323942,0.00626631256869765,0.0006158074029869783,0.0026065365711816415,-0.024670675799038977,0.0005107933020368085,0.023317809223082915,0.01968980037256814,0.0006269561931199021,-0.017587938678880925,-0.015492003324108553,-0.004058330995203049,0.006481089261720749,-0.00267005237989496,-0.008843677320514118,-0.014595462870210121,0.0031940920212634957,0.01288711860486307,0.019601485728748612,0.011275616741376808,0.009183721750967438,0.00772893507537482,0.005765449773283122,0.0003579237554514052,0.007658058611128972,0.005492429076568972,-0.004014044895223098,0.006708441584812001,-0.01392215099068089,0.0051846334443848225,0.015690324746409107,0.002348563161652849,-0.00746586919278563,-0.012793782197156984,0.0031221134604928233,0.004803400735567941,0.0017581488550968874,-0.005310236817508696,-0.007039278866658427,-0.006005551847504703,0.005343409722900928,0.003267579359797647,0.010449286766160654,0.011469632023731148,0.0014719466713541212,0.010559299485608947,0.001148108098909771,0.014671436020564647,0.012455253535892725,0.008969808846328845,-0.005038526304826892,-0.004004880915417642,0.0020909208206111476,0.01078214000281892,0.006606675140210314,-0.0021026011540739844,-0.008264047478730366,-0.0024542468281810144,-0.004036318971975205,0.00900545098620011,-0.01103560959751724,-0.0026642078924797377,-0.01152717246738435,0.004666006487236571,0.010147247241202195,0.015001125648825121,0.012958608756831792,0.012360739067722575,-0.0009887460913306988,0.0011765331241106807,-0.014845985612083144,0.012875727724705124,0.001068394551128867,-0.005068878583244713,-0.003416013540236241,0.0007890992294206329,0.002545863088018597,0.014446728567106092,-0.0032010810617204397,0.003515465465791744,-0.008632047110830668,0.00757449876364194,-0.007565068461905165,0.004867190234696698,-0.00988179883582076,-0.0021071188684007825,-0.004762601516670237,0.0007952385541129103,-0.011312997148687004,0.013298437520613418,0.0037204331240180783,0.0015520660573473568,0.0001550435235370488,0.006769732314367571,0.010379482115526766,-0.006166690941304334,-0.0053548281369337316,-0.0045129207272453925,0.0023603455445232752,0.008535262555281314,-0.000472475975045451,0.009311183813299723,-0.0016477674522652303,0.003970941303630934,0.0060320711564447104,0.008126277593321227,0.011887959345978647,-0.0003962421732531627,-0.0081229821001205,0.0009849057623104046,0.007537077012616662,0.00499994795175544,0.008148653199600047,0.014464923645996573,0.003410729344848527,0.0007610537802270464,-0.004371537516125917,-0.0025967647812116623,-0.0016632322316352292,0.00724594388813182,0.00016429846289577543,-0.003737884253633708,-0.006503846149117047,0.0008330211771130294,0.007122558586826425,0.008504940438303616,-0.0038214524228947127,0.009229162114932899,0.005872385876743178,0.00762468572837992,-0.006079212360859948,0.004896907044789272,0.005474558854489055,-0.0003916438861083046,0.002002454234296786,0.0031530969415787644,0.00011643435014882736,0.008846196284272254,0.0004335410786507553,-0.00320070091830683,-0.005602919952593841,0.005006326567041979,0.010409922885423594,0.012079978406413406,0.0014324712973170907,-0.001275984706406032,0.0004009531458108372,0.003640786924100827,-0.0047917418544694956,0.006143203110169122,0.007569199773543592,0.0020074066971893607,0.004144199933701636,0.0037653089991289287,0.003956353322884874,0.0009432121716946155,0.009481942778174369,0.004181115167944207,0.001078782287581857,0.006075961475992267,0.010508256993802798,0.012368485284733471,-0.0013992090667067417,-0.0029429555516593863,0.003426715131678202,0.006451070541955417,0.004090193871726568,-0.004749301005477269,0.00153494598520242,0.005476256060603112,0.0075414796954462225,0.00014211285523282397,0.004294218383355705,0.002210750552387017,0.011084398547706476,0.004163674122288736,0.0008081985204974514,0.007483908364434193,-0.003612673295273058,-0.003040390951670304,-0.0013177965227726325,0.010799230605260664,0.012952808371269189,0.010003146275172426,0.007410080604539829,-0.0036799623208586263,0.0009812075855465023,0.00602884104976329,0.01074729946954682,0.004256059850559727,-0.002308015856017369,-0.0059402506839789085,0.00025860932654257865,0.0009928448025906685,0.021385521979332377,0.011369054547322259,0.0004704515094564004,-0.0023105584956819537,0.0010520746831201438,0.014578880238415984,0.010660865907175835,0.01053695105144543,-0.010513977075990045,-0.006208811273258325,-0.0016400826010779586,0.006282398557678052,0.015581627125247606,0.008073979838149312,-0.0012874219228697487,-0.008314064042923616,-0.0013225816328929138,0.0030828705378264784,0.023654098341486136,0.011143488256654382,-0.013606507508773808,-0.005098690546538647,0.006596853532514518,0.026608185346054948,0.017278435706290236,0.01233268873470221,-0.009283028097585144,-0.004186749184775783,-0.0020703928466647764,0.004441299980607823,0.013307021358362835,0.008018776022462402,-0.008417151671949955,-0.0048133859245715295,-0.0006039134477725187,0.011514881510113734,0.013837813407341991,0.005832005942563593,-0.013708767622847333,-0.004738057724875432,0.006062038691332979,0.024738473413043537,0.016484691469357063,0.009755950463945562,-0.01208432033022056,0.005389014281477542,0.024370436704021614,0.02021773292320669,0.006494920370784568,-0.005906241614388337,-0.007965336483764344,-0.004677619285093743,-0.0022909177450985627,0.008621389196737106,0.012317779552538165,0.005200166804028229,-0.016162055929954202,-0.0018603183831759598,0.012183617806427856,0.010263741194751163,-0.0004228374745820191,-0.007977798348490174,-0.01251382582021226,0.005736263988327464,0.02523339858286297,0.02111851361726168,0.007392742637874874,-0.004987737291825345,-0.006006059487211995,0.006272794216982489,0.013685594692736768,0.006773117476974601,0.0007695038087558477,-0.003546375723001351,-0.01606552305693364,-0.0008890531802092194,0.014084424235557755,0.011437705991504917,-0.0005747255259733431,-0.007818784811223419,-0.010272791823355477,0.004567280091825023,0.014607139047670827,0.0016498312343022467,0.003476277229298759,-0.010792052335106052,-0.005327281774635982,0.00792014465673965,0.015225614801508313,0.00627822235886169,0.0013952023908430247,-0.0024105891001967666,0.008279905173053301,0.008377326976794441,0.008992130195116618,0.003745341641990154,0.00134831621009287,0.003681843200696136,-0.010233893590293494,0.005455301876855012,0.016537636875496253,0.006026595264855723,0.00220558639415122,-0.00945267484636891,-0.0006722322131419659,0.010190842250679434,0.009023294275638048,0.0013722824548428347,0.00021056623202267435,-0.005521537169341145,0.007213038744952471,0.005286471191377856,0.0072684489979721175,0.004339058313243019,0.0020731947385923544,0.004465189101445881,0.005437297619354026,0.010107626644833414,-0.0016460268304670101,0.004586966173978323,-0.0006274055083399751,0.010174264686059404,-0.0011528628954579946,0.01010304890763954,0.009532629707820952,-0.002221096610950428,0.0017041549395208498,-0.004930551829053238,0.005501826549910307,0.005821268150627809,0.015373274272467397,0.0019205400918096325,0.0015458072001775021,0.000696142910181052,0.0029291638687260575,0.0078614573348628,-0.002592230251497233,0.0044911354447433145,-0.00046438843769203603,0.008871315480516551,-0.009521602806141382,0.006405731590101805,-0.004210128924002405,0.0017656208732437738,0.0026697737253431547,0.005627552991593991,0.004388127554554584,0.005866810974464865,0.018654874003901523,0.0014254672903517744,0.002254991544391642,0.00005159684490415296,0.0005999809000041737,0.00632810806905327,0.003058093167474708,0.011080573140110883,-0.0031498241554027175,-0.003388806364185941,-0.00912387796185759,0.00294127431740463,-0.009361749789680227,0.00017352711984354037,0.0037401618047468842,0.004113988317920324,0.0022711235538522443,-0.005314525870372638,-0.00992486417531961,-0.001416316024886916,0.006800616104097579,0.0010619631258551884,-0.00158859429329811,0.006752110127128466,0.002098862519239573,0.007152068647682953,-0.004249401161456246,-0.004230273141575119,0.008647580493380066,-0.003922182843417208,0.012947808357825606,0.0032337866867034382,0.0034830368951608284,0.004015395821842091]} -------------------------------------------------------------------------------- /classifiers/nn-options.js: -------------------------------------------------------------------------------- 1 | /* 2 | Running kittydar with these options will use the neural network backend: 3 | 4 | var options = require("./nn-options"); 5 | kittydar.detectCats(canvas, options); 6 | */ 7 | var brain = require("brain"); 8 | 9 | var network = require("./network.js"); 10 | var net = new brain.NeuralNetwork().fromJSON(network); 11 | 12 | module.exports = { 13 | shiftBy: 6, // px to slide window by 14 | minOverlaps: 2, // minumum overlapping rects to classify as a head 15 | HOGparams: { // parameters for HOG descriptor 16 | cellSize: 6, // must divide evenly into shiftBy 17 | blockSize: 2, 18 | blockStride: 1, 19 | bins: 6, 20 | norm: "L2" 21 | }, 22 | classify: function(features) { 23 | var output = net.runInput(features)[0]; 24 | return { 25 | isCat: output > 0.9998, 26 | value: output 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /classifiers/svm-options.js: -------------------------------------------------------------------------------- 1 | /* 2 | Running kittydar with these options will use the neural network backend: 3 | 4 | var options = require("./svm-options"); 5 | kittydar.detectCats(canvas, options); 6 | */ 7 | var svm = require("svm"); 8 | 9 | var state = require("./mixed-svm-1000.json"); 10 | var SVM = new svm.SVM(); 11 | SVM.fromJSON(state); 12 | 13 | module.exports = { 14 | shiftBy: 4, // px to slide window by 15 | minOverlaps: 2, // minumum overlapping rects to classify as a head 16 | HOGparams: { // parameters for HOG descriptor 17 | cellSize: 4, // must divide evenly into shiftBy 18 | blockSize: 2, 19 | blockStride: 1, 20 | bins: 6, 21 | norm: "L2" 22 | }, 23 | classify: function(features) { 24 | var label = SVM.predict([features])[0]; 25 | return { 26 | isCat: label == 1, 27 | value: 1 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /kittydar.js: -------------------------------------------------------------------------------- 1 | var hog = require("hog-descriptor"), 2 | nms = require("./nms"), 3 | nnOptions = require("./classifiers/nn-options"), 4 | svmOptions = require("./classifiers/svm-options"); 5 | 6 | if (process.arch) { // in node 7 | // make sure browserify doesn't pick this require up 8 | var require_ = require; 9 | var Canvas = require_('canvas'); 10 | } 11 | 12 | exports.Kittydar = Kittydar; 13 | 14 | exports.detectCats = function(canvas, options) { 15 | var kittydar = new Kittydar(options); 16 | return kittydar.detectCats(canvas); 17 | } 18 | 19 | var defaultParams = { 20 | patchSize: 48, // size of training images in px 21 | minSize: 48, // starting window size 22 | resize: 360, // initial image resize size in px 23 | scaleStep: 6, // scaling step size in px 24 | shiftBy: 6, // px to slide window by 25 | overlapThresh: 0.5, // min overlap ratio to classify as an overlap 26 | minOverlaps: 2, // minumum overlapping rects to classify as a head 27 | HOGparams: { // parameters for HOG descriptor 28 | cellSize: 6, // must divide evenly into shiftBy 29 | blockSize: 2, 30 | blockStride: 1, 31 | bins: 6, 32 | norm: "L2" 33 | }, 34 | extractFeatures: function(imagedata, histograms) { 35 | // override if using another set of features 36 | var descriptor = hog.extractHOGFromHistograms(histograms, this.HOGparams); 37 | return descriptor; 38 | }, 39 | classify: function(features) { 40 | // override if using another classifier 41 | var output = net.runInput(features)[0]; 42 | return { 43 | isCat: output > 0.999, 44 | value: output 45 | }; 46 | } 47 | } 48 | 49 | function Kittydar(options) { 50 | this.params = {}; 51 | extend(this.params, defaultParams); 52 | extend(this.params, options); 53 | 54 | if (this.params.classifier == "svm") { 55 | // use the support vector machine as the classifier 56 | extend(this.params, svmOptions); 57 | } 58 | else { 59 | // use the neural network as the classifier 60 | extend(this.params, nnOptions); 61 | } 62 | } 63 | 64 | Kittydar.prototype = { 65 | detectCats: function(canvas) { 66 | // get canvases of the image at different scales 67 | var resizes = this.getAllSizes(canvas, this.params.minSize); 68 | 69 | var cats = []; 70 | resizes.forEach(function(resize) { 71 | var kitties = this.detectAtScale(resize.imagedata, resize.scale); 72 | cats = cats.concat(kitties); 73 | }.bind(this)); 74 | cats = this.combineOverlaps(cats, this.params.overlapThresh, this.params.minOverlaps); 75 | 76 | return cats; 77 | }, 78 | 79 | getAllSizes: function(canvas, minSize) { 80 | // For use with Worker threads, return canvas ImageDatas 81 | // resized to accomodate various window sizes 82 | 83 | minSize = minSize || this.params.minSize; 84 | 85 | // resize canvas to cut down on number of windows to check 86 | var max = Math.max(canvas.width, canvas.height) 87 | var scale = Math.min(max, this.params.resize) / max; 88 | 89 | var resizes = []; 90 | for (var size = minSize; size < max; size += this.params.scaleStep) { 91 | var winScale = (minSize / size) * scale; 92 | var imagedata = this.scaleCanvas(canvas, winScale); 93 | 94 | resizes.push({ 95 | imagedata: imagedata, 96 | scale: winScale, 97 | size: size 98 | }) 99 | } 100 | return resizes; 101 | }, 102 | 103 | scaleCanvas: function(canvas, scale) { 104 | var width = Math.floor(canvas.width * scale); 105 | var height = Math.floor(canvas.height * scale); 106 | 107 | canvas = resizeCanvas(canvas, width, height); 108 | var ctx = canvas.getContext("2d"); 109 | var imagedata = ctx.getImageData(0, 0, width, height); 110 | 111 | return imagedata; 112 | }, 113 | 114 | detectAtScale: function(imagedata, scale) { 115 | // Detect using a sliding window of a fixed size. 116 | var histograms = hog.extractHistograms(imagedata, this.params.HOGparams); 117 | var cats = []; 118 | 119 | var width = imagedata.width, 120 | height = imagedata.height; 121 | 122 | var size = this.params.patchSize; 123 | var shift = this.params.shiftBy; 124 | 125 | for (var y = 0; y + size < height; y += shift) { 126 | for (var x = 0; x + size < width; x += shift) { 127 | var histRect = getRect(histograms, x / shift, y / shift, size / shift, size / shift); 128 | var features = this.params.extractFeatures(imagedata, histRect); 129 | var result = this.params.classify(features); 130 | 131 | if (result.isCat) { 132 | cats.push({ 133 | x: Math.floor(x / scale), 134 | y: Math.floor(y / scale), 135 | width: Math.floor(size / scale), 136 | height: Math.floor(size / scale), 137 | value: result.value 138 | }); 139 | } 140 | } 141 | } 142 | return cats; 143 | }, 144 | 145 | combineOverlaps: function(rects, overlapThresh, minOverlaps) { 146 | cats = nms.combineOverlaps(rects, overlapThresh, minOverlaps); 147 | return cats; 148 | } 149 | } 150 | 151 | function getRect(matrix, x, y, width, height) { 152 | var square = new Array(height); 153 | for (var i = 0; i < height; i++) { 154 | square[i] = new Array(width); 155 | for (var j = 0; j < width; j++) { 156 | square[i][j] = matrix[y + i][x + j]; 157 | } 158 | } 159 | return square; 160 | } 161 | 162 | function resizeCanvas(canvas, width, height) { 163 | var resizeCanvas = createCanvas(width, height); 164 | var ctx = resizeCanvas.getContext('2d'); 165 | ctx.patternQuality = "best"; 166 | 167 | ctx.drawImage(canvas, 0, 0, canvas.width, canvas.height, 168 | 0, 0, width, height); 169 | return resizeCanvas; 170 | } 171 | 172 | function createCanvas(width, height) { 173 | if (typeof Canvas !== 'undefined') { 174 | // have node-canvas 175 | return new Canvas(width, height); 176 | } 177 | else { 178 | // in browser 179 | var canvas = document.createElement('canvas'); 180 | canvas.setAttribute('width', width); 181 | canvas.setAttribute('height', height); 182 | return canvas; 183 | } 184 | } 185 | 186 | function extend(object, extensions) { 187 | for (ext in extensions) { 188 | object[ext] = extensions[ext]; 189 | } 190 | } -------------------------------------------------------------------------------- /nms.js: -------------------------------------------------------------------------------- 1 | /* non-maximum suppression - combine overlapping rects into the strongest one */ 2 | 3 | exports.combineOverlaps = combineOverlaps; 4 | exports.doesOverlap = doesOverlap; 5 | 6 | /* rects is an array of objects that look like: 7 | * { 8 | * x: // top left x coordinate, 9 | * y: // lop left y coordinate, 10 | * width: // width of rect, 11 | * height: // height of rect, 12 | * value: // rect with a higher value will suppress a rect with a lower value 13 | * } 14 | * 15 | * minRatio is the min ratio of intersection area to union area of two rects 16 | * to qualify them as overlapping. 17 | * 18 | * minOverlaps is the number of suppressions required for a rect 19 | * to be included in the final returned set. 20 | */ 21 | function combineOverlaps(rects, minRatio, minOverlaps) { 22 | minRatio = minRatio || 0.5; 23 | minOverlaps = minOverlaps || 1; 24 | 25 | for (var i = 0; i < rects.length; i++) { 26 | var r1 = rects[i]; 27 | r1.tally = 0; // number of rects it's suppressed 28 | 29 | for (var j = 0; j < i; j++) { 30 | var r2 = rects[j]; 31 | 32 | if (doesOverlap(r1, r2, minRatio)) { 33 | if (r1.value > r2.value) { 34 | r2.suppressed = true; 35 | r1.tally += 1 + r2.tally; 36 | } 37 | else { 38 | r1.suppressed = true; 39 | r2.tally += 1 + r1.tally; 40 | } 41 | } 42 | } 43 | } 44 | // only take a rect if it wasn't suppressed by any other rect 45 | return rects.filter(function(rect) { 46 | return !rect.suppressed && rect.tally >= minOverlaps; 47 | }) 48 | } 49 | 50 | function doesOverlap(r1, r2, minRatio) { 51 | minRatio = minRatio || 0.5; 52 | 53 | var overlapW, overlapH; 54 | if (r1.x > r2.x) { 55 | overlapW = Math.min((r2.x + r2.width) - r1.x, r1.width); 56 | } 57 | else { 58 | overlapW = Math.min((r1.x + r1.width) - r2.x, r2.width); 59 | } 60 | 61 | if (r1.y > r2.y) { 62 | overlapH = Math.min((r2.y + r2.height) - r1.y, r1.height); 63 | } 64 | else { 65 | overlapH = Math.min((r1.y + r1.height) - r2.y, r2.height); 66 | } 67 | 68 | if (overlapW <= 0 || overlapH <= 0) { 69 | return false; 70 | } 71 | var intersect = overlapW * overlapH; 72 | var union = (r1.width * r1.height) + (r2.width * r2.height) - (intersect * 2); 73 | 74 | return intersect / union > minRatio; 75 | } 76 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kittydar", 3 | "description": "Cat detection", 4 | "version": "0.1.7", 5 | "author": "Heather Arthur ", 6 | "repository": { 7 | "type": "git", 8 | "url": "http://github.com/harthur/kittydar.git" 9 | }, 10 | "dependencies": { 11 | "canvas": "1.0.1", 12 | "brain": "~0.6.0", 13 | "hog-descriptor": "~0.5.0", 14 | "svm": "~0.1.1", 15 | "browserify": "~2.10.1", 16 | "uglify-js": "~2.2.5" 17 | }, 18 | "devDependencies": { 19 | "nomnom": "~1.5.2", 20 | "async": "~0.1.22", 21 | "colors": "~0.6.0-1", 22 | "charm": "~0.1.1", 23 | "grunt": "~0.4.1", 24 | "grunt-contrib-uglify": "~0.2.0" 25 | }, 26 | "main": "./kittydar" 27 | } 28 | -------------------------------------------------------------------------------- /testing/README.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | To test kittydar, run: 4 | 5 | ``` 6 | node test.js 7 | ``` 8 | 9 | This will run `kittydar.detectCats()` on several images. The number of cats missed is reported, as well as the number of false positives. 10 | 11 | ## Test Images 12 | 13 | The test images are located in the `TEST` directory. Many of them are from @maxogden's [maxogden/cats](http://github.com/maxogden/cats) under BSD license. -------------------------------------------------------------------------------- /testing/TEST/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/.DS_Store -------------------------------------------------------------------------------- /testing/TEST/00092f6ec7a911e1be6a12313820455d_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/00092f6ec7a911e1be6a12313820455d_7.jpg -------------------------------------------------------------------------------- /testing/TEST/00092f6ec7a911e1be6a12313820455d_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 278 256 66 61 -------------------------------------------------------------------------------- /testing/TEST/0475ea02c7da11e18cf91231380fd29b_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/0475ea02c7da11e18cf91231380fd29b_7.jpg -------------------------------------------------------------------------------- /testing/TEST/0475ea02c7da11e18cf91231380fd29b_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 296 437 89 89 -------------------------------------------------------------------------------- /testing/TEST/0502a3b2a1e111e18cf91231380fd29b_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/0502a3b2a1e111e18cf91231380fd29b_7.jpg -------------------------------------------------------------------------------- /testing/TEST/0502a3b2a1e111e18cf91231380fd29b_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 295 246 52 56 -------------------------------------------------------------------------------- /testing/TEST/066bdac8c71811e1a38422000a1c8933_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/066bdac8c71811e1a38422000a1c8933_7.jpg -------------------------------------------------------------------------------- /testing/TEST/066bdac8c71811e1a38422000a1c8933_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 344 368 43 46 -------------------------------------------------------------------------------- /testing/TEST/0c375608c71811e1b10e123138105d6b_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/0c375608c71811e1b10e123138105d6b_7.jpg -------------------------------------------------------------------------------- /testing/TEST/0c375608c71811e1b10e123138105d6b_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 90 86 358 384 -------------------------------------------------------------------------------- /testing/TEST/10b80642c7da11e19894123138140d8c_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/10b80642c7da11e19894123138140d8c_7.jpg -------------------------------------------------------------------------------- /testing/TEST/10b80642c7da11e19894123138140d8c_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 192 252 117 120 -------------------------------------------------------------------------------- /testing/TEST/1140967248_e982ddc8d7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/1140967248_e982ddc8d7.jpg -------------------------------------------------------------------------------- /testing/TEST/1140967248_e982ddc8d7.jpg.cat: -------------------------------------------------------------------------------- 1 | 119 123 83 81 -------------------------------------------------------------------------------- /testing/TEST/1288302525156.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/1288302525156.jpg -------------------------------------------------------------------------------- /testing/TEST/1288302525156.jpg.cat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/1288302525156.jpg.cat -------------------------------------------------------------------------------- /testing/TEST/12a8d742be7f11e188131231381b5c25_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/12a8d742be7f11e188131231381b5c25_7.jpg -------------------------------------------------------------------------------- /testing/TEST/12a8d742be7f11e188131231381b5c25_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 305 346 53 53 -------------------------------------------------------------------------------- /testing/TEST/144692464_f0053e1093.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/144692464_f0053e1093.jpg -------------------------------------------------------------------------------- /testing/TEST/144692464_f0053e1093.jpg.cat: -------------------------------------------------------------------------------- 1 | 198 65 184 187 -------------------------------------------------------------------------------- /testing/TEST/16cb636ed3c711e1b62722000a1e8b36_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/16cb636ed3c711e1b62722000a1e8b36_7.jpg -------------------------------------------------------------------------------- /testing/TEST/16cb636ed3c711e1b62722000a1e8b36_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 202 32 263 254 -------------------------------------------------------------------------------- /testing/TEST/171790888_d80e34a4f7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/171790888_d80e34a4f7.jpg -------------------------------------------------------------------------------- /testing/TEST/171790888_d80e34a4f7.jpg.cat: -------------------------------------------------------------------------------- 1 | 135 23 138 159 -------------------------------------------------------------------------------- /testing/TEST/219966284_4aa0a3c465.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/219966284_4aa0a3c465.jpg -------------------------------------------------------------------------------- /testing/TEST/219966284_4aa0a3c465.jpg.cat: -------------------------------------------------------------------------------- 1 | 196 70 147 133 -------------------------------------------------------------------------------- /testing/TEST/22981-1363980352-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/22981-1363980352-3.jpg -------------------------------------------------------------------------------- /testing/TEST/22981-1363980352-3.jpg.cat: -------------------------------------------------------------------------------- 1 | 241 55 160 144 -------------------------------------------------------------------------------- /testing/TEST/2320b0ae089e11e29e6f22000a1e8b8a_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/2320b0ae089e11e29e6f22000a1e8b8a_7.jpg -------------------------------------------------------------------------------- /testing/TEST/2320b0ae089e11e29e6f22000a1e8b8a_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 242 257 72 69 -------------------------------------------------------------------------------- /testing/TEST/23385-1363980332-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/23385-1363980332-4.jpg -------------------------------------------------------------------------------- /testing/TEST/23385-1363980332-4.jpg.cat: -------------------------------------------------------------------------------- 1 | 139 187 160 174 -------------------------------------------------------------------------------- /testing/TEST/23981-1363980427-8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/23981-1363980427-8.jpg -------------------------------------------------------------------------------- /testing/TEST/23981-1363980427-8.jpg.cat: -------------------------------------------------------------------------------- 1 | 22 27 188 157 -------------------------------------------------------------------------------- /testing/TEST/2431886567_66ce6145ea.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/2431886567_66ce6145ea.jpg -------------------------------------------------------------------------------- /testing/TEST/2431886567_66ce6145ea.jpg.cat: -------------------------------------------------------------------------------- 1 | 241 37 69 70 -------------------------------------------------------------------------------- /testing/TEST/25508c1e88ba11e1a87612313804ec91_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/25508c1e88ba11e1a87612313804ec91_7.jpg -------------------------------------------------------------------------------- /testing/TEST/25508c1e88ba11e1a87612313804ec91_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 357 274 62 63 -------------------------------------------------------------------------------- /testing/TEST/265923028_ac8732cc7d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/265923028_ac8732cc7d.jpg -------------------------------------------------------------------------------- /testing/TEST/265923028_ac8732cc7d.jpg.cat: -------------------------------------------------------------------------------- 1 | 235 211 95 103 -------------------------------------------------------------------------------- /testing/TEST/2703668839_cfe0d6b154.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/2703668839_cfe0d6b154.jpg -------------------------------------------------------------------------------- /testing/TEST/2703668839_cfe0d6b154.jpg.cat: -------------------------------------------------------------------------------- 1 | 257 43 230 208 -------------------------------------------------------------------------------- /testing/TEST/27299-1363981152-9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/27299-1363981152-9.jpg -------------------------------------------------------------------------------- /testing/TEST/27299-1363981152-9.jpg.cat: -------------------------------------------------------------------------------- 1 | 173 34 147 149 -------------------------------------------------------------------------------- /testing/TEST/28273-1363981235-15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/28273-1363981235-15.jpg -------------------------------------------------------------------------------- /testing/TEST/28273-1363981235-15.jpg.cat: -------------------------------------------------------------------------------- 1 | 90 81 450 400 -------------------------------------------------------------------------------- /testing/TEST/286465_953271199759_1283353304_o.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/286465_953271199759_1283353304_o.jpg -------------------------------------------------------------------------------- /testing/TEST/286465_953271199759_1283353304_o.jpg.cat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/286465_953271199759_1283353304_o.jpg.cat -------------------------------------------------------------------------------- /testing/TEST/28654-1363981115-11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/28654-1363981115-11.jpg -------------------------------------------------------------------------------- /testing/TEST/28654-1363981115-11.jpg.cat: -------------------------------------------------------------------------------- 1 | 188 104 159 143 -------------------------------------------------------------------------------- /testing/TEST/29482-1363980679-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/29482-1363980679-3.jpg -------------------------------------------------------------------------------- /testing/TEST/29482-1363980679-3.jpg.cat: -------------------------------------------------------------------------------- 1 | 93 55 150 150 -------------------------------------------------------------------------------- /testing/TEST/2994-1363980988-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/2994-1363980988-4.jpg -------------------------------------------------------------------------------- /testing/TEST/2994-1363980988-4.jpg.cat: -------------------------------------------------------------------------------- 1 | 0 60 174 160 -------------------------------------------------------------------------------- /testing/TEST/2f49bd8cbf0911e180d51231380fcd7e_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/2f49bd8cbf0911e180d51231380fcd7e_7.jpg -------------------------------------------------------------------------------- /testing/TEST/2f49bd8cbf0911e180d51231380fcd7e_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 167 188 148 132 -------------------------------------------------------------------------------- /testing/TEST/30599-1363980752-0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/30599-1363980752-0.jpg -------------------------------------------------------------------------------- /testing/TEST/30599-1363980752-0.jpg.cat: -------------------------------------------------------------------------------- 1 | 187 0 167 180 -------------------------------------------------------------------------------- /testing/TEST/33eb19201ed811e1abb01231381b65e3_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/33eb19201ed811e1abb01231381b65e3_7.jpg -------------------------------------------------------------------------------- /testing/TEST/33eb19201ed811e1abb01231381b65e3_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 266 307 67 65 -------------------------------------------------------------------------------- /testing/TEST/3437df14c7aa11e1aee522000a1e8a5f_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/3437df14c7aa11e1aee522000a1e8a5f_7.jpg -------------------------------------------------------------------------------- /testing/TEST/3437df14c7aa11e1aee522000a1e8a5f_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 255 315 74 63 -------------------------------------------------------------------------------- /testing/TEST/3661671516_aab2c59cde.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/3661671516_aab2c59cde.jpg -------------------------------------------------------------------------------- /testing/TEST/3661671516_aab2c59cde.jpg.cat: -------------------------------------------------------------------------------- 1 | 88 0 402 377 -------------------------------------------------------------------------------- /testing/TEST/3ba670686e7111e181bd12313817987b_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/3ba670686e7111e181bd12313817987b_7.jpg -------------------------------------------------------------------------------- /testing/TEST/3ba670686e7111e181bd12313817987b_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 165 129 248 257 -------------------------------------------------------------------------------- /testing/TEST/4316096411_cfb2737168.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/4316096411_cfb2737168.jpg -------------------------------------------------------------------------------- /testing/TEST/4316096411_cfb2737168.jpg.cat: -------------------------------------------------------------------------------- 1 | 213 24 146 150 -------------------------------------------------------------------------------- /testing/TEST/433e375c2cc211e1a87612313804ec91_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/433e375c2cc211e1a87612313804ec91_7.jpg -------------------------------------------------------------------------------- /testing/TEST/433e375c2cc211e1a87612313804ec91_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 73 92 269 260 -------------------------------------------------------------------------------- /testing/TEST/4375600759_f6382fd5ff.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/4375600759_f6382fd5ff.jpg -------------------------------------------------------------------------------- /testing/TEST/4375600759_f6382fd5ff.jpg.cat: -------------------------------------------------------------------------------- 1 | 183 44 189 192 -------------------------------------------------------------------------------- /testing/TEST/474156503_d64e972df3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/474156503_d64e972df3.jpg -------------------------------------------------------------------------------- /testing/TEST/474156503_d64e972df3.jpg.cat: -------------------------------------------------------------------------------- 1 | 239 180 63 68 -------------------------------------------------------------------------------- /testing/TEST/4817433684_ff2dfedc58.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/4817433684_ff2dfedc58.jpg -------------------------------------------------------------------------------- /testing/TEST/4817433684_ff2dfedc58.jpg.cat: -------------------------------------------------------------------------------- 1 | 150 41 271 210 -------------------------------------------------------------------------------- /testing/TEST/4878878197_31de9837ba.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/4878878197_31de9837ba.jpg -------------------------------------------------------------------------------- /testing/TEST/4878878197_31de9837ba.jpg.cat: -------------------------------------------------------------------------------- 1 | 240 21 166 167 -------------------------------------------------------------------------------- /testing/TEST/491889103_603d896630.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/491889103_603d896630.jpg -------------------------------------------------------------------------------- /testing/TEST/491889103_603d896630.jpg.cat: -------------------------------------------------------------------------------- 1 | 187 80 107 101 -------------------------------------------------------------------------------- /testing/TEST/4ebcfed0a75911e1b2fe1231380205bf_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/4ebcfed0a75911e1b2fe1231380205bf_7.jpg -------------------------------------------------------------------------------- /testing/TEST/4ebcfed0a75911e1b2fe1231380205bf_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 148 71 244 243 -------------------------------------------------------------------------------- /testing/TEST/506407837_5c15ab57db.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/506407837_5c15ab57db.jpg -------------------------------------------------------------------------------- /testing/TEST/506407837_5c15ab57db.jpg.cat: -------------------------------------------------------------------------------- 1 | 114 101 104 111 -------------------------------------------------------------------------------- /testing/TEST/5352794771_5e03ca6451.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/5352794771_5e03ca6451.jpg -------------------------------------------------------------------------------- /testing/TEST/5352794771_5e03ca6451.jpg.cat: -------------------------------------------------------------------------------- 1 | 158 11 148 145 -------------------------------------------------------------------------------- /testing/TEST/54652550_2fe234cec7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/54652550_2fe234cec7.jpg -------------------------------------------------------------------------------- /testing/TEST/54652550_2fe234cec7.jpg.cat: -------------------------------------------------------------------------------- 1 | 178 93 141 135 -------------------------------------------------------------------------------- /testing/TEST/548c8aa491a811e1be6a12313820455d_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/548c8aa491a811e1be6a12313820455d_7.jpg -------------------------------------------------------------------------------- /testing/TEST/548c8aa491a811e1be6a12313820455d_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 171 20 361 348 -------------------------------------------------------------------------------- /testing/TEST/55d268706e7111e1989612313815112c_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/55d268706e7111e1989612313815112c_7.jpg -------------------------------------------------------------------------------- /testing/TEST/55d268706e7111e1989612313815112c_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 177 20 274 337 -------------------------------------------------------------------------------- /testing/TEST/5640834510_35be88d31d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/5640834510_35be88d31d.jpg -------------------------------------------------------------------------------- /testing/TEST/5640834510_35be88d31d.jpg.cat: -------------------------------------------------------------------------------- 1 | 195 55 108 119 -------------------------------------------------------------------------------- /testing/TEST/5672121084_0a666a9f76.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/5672121084_0a666a9f76.jpg -------------------------------------------------------------------------------- /testing/TEST/5672121084_0a666a9f76.jpg.cat: -------------------------------------------------------------------------------- 1 | 187 101 94 106 -------------------------------------------------------------------------------- /testing/TEST/5804b25e64d211e18bb812313804a181_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/5804b25e64d211e18bb812313804a181_7.jpg -------------------------------------------------------------------------------- /testing/TEST/5804b25e64d211e18bb812313804a181_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 51 0 560 560 -------------------------------------------------------------------------------- /testing/TEST/5929820421_b710bd97a4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/5929820421_b710bd97a4.jpg -------------------------------------------------------------------------------- /testing/TEST/5929820421_b710bd97a4.jpg.cat: -------------------------------------------------------------------------------- 1 | 152 29 156 162 -------------------------------------------------------------------------------- /testing/TEST/5c7ac9ec6fa211e1a87612313804ec91_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/5c7ac9ec6fa211e1a87612313804ec91_7.jpg -------------------------------------------------------------------------------- /testing/TEST/5c7ac9ec6fa211e1a87612313804ec91_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 168 0 288 250 -------------------------------------------------------------------------------- /testing/TEST/653_555388061514093.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/653_555388061514093.jpg -------------------------------------------------------------------------------- /testing/TEST/653_555388061514093.jpg.cat: -------------------------------------------------------------------------------- 1 | 41 10 183 184 -------------------------------------------------------------------------------- /testing/TEST/66250dd8be6011e1aebc1231381b647a_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/66250dd8be6011e1aebc1231381b647a_7.jpg -------------------------------------------------------------------------------- /testing/TEST/66250dd8be6011e1aebc1231381b647a_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 12 20 573 560 -------------------------------------------------------------------------------- /testing/TEST/663354768.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/663354768.jpg -------------------------------------------------------------------------------- /testing/TEST/663354768.jpg.cat: -------------------------------------------------------------------------------- 1 | 366 74 231 216 -------------------------------------------------------------------------------- /testing/TEST/667_19375928237.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/667_19375928237.jpg -------------------------------------------------------------------------------- /testing/TEST/667_19375928237.jpg.cat: -------------------------------------------------------------------------------- 1 | 36 58 255 224 -------------------------------------------------------------------------------- /testing/TEST/67dcb80ab41b11e1aebc1231381b647a_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/67dcb80ab41b11e1aebc1231381b647a_7.jpg -------------------------------------------------------------------------------- /testing/TEST/67dcb80ab41b11e1aebc1231381b647a_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 276 15 270 342 -------------------------------------------------------------------------------- /testing/TEST/69375046_d06dc77299.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/69375046_d06dc77299.jpg -------------------------------------------------------------------------------- /testing/TEST/69375046_d06dc77299.jpg.cat: -------------------------------------------------------------------------------- 1 | 170 75 120 119 -------------------------------------------------------------------------------- /testing/TEST/6c8b25eea03911e192e91231381b3d7a_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/6c8b25eea03911e192e91231381b3d7a_7.jpg -------------------------------------------------------------------------------- /testing/TEST/6c8b25eea03911e192e91231381b3d7a_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 115 165 112 105 -------------------------------------------------------------------------------- /testing/TEST/6cd3d502c03011e180c9123138016265_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/6cd3d502c03011e180c9123138016265_7.jpg -------------------------------------------------------------------------------- /testing/TEST/6cd3d502c03011e180c9123138016265_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 241 134 279 301 -------------------------------------------------------------------------------- /testing/TEST/7023222_87b23bb0cd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/7023222_87b23bb0cd.jpg -------------------------------------------------------------------------------- /testing/TEST/7023222_87b23bb0cd.jpg.cat: -------------------------------------------------------------------------------- 1 | 185 18 141 147 -------------------------------------------------------------------------------- /testing/TEST/711.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/711.jpg -------------------------------------------------------------------------------- /testing/TEST/711.jpg.cat: -------------------------------------------------------------------------------- 1 | 64 292 78 73 -------------------------------------------------------------------------------- /testing/TEST/78fd1f1aca3911e1a39b1231381b7ba1_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/78fd1f1aca3911e1a39b1231381b7ba1_7.jpg -------------------------------------------------------------------------------- /testing/TEST/78fd1f1aca3911e1a39b1231381b7ba1_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 153 337 90 101 -------------------------------------------------------------------------------- /testing/TEST/7d7f0184a43711e1b10e123138105d6b_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/7d7f0184a43711e1b10e123138105d6b_7.jpg -------------------------------------------------------------------------------- /testing/TEST/7d7f0184a43711e1b10e123138105d6b_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 276 288 66 58 -------------------------------------------------------------------------------- /testing/TEST/8093406111_6fa933bf78.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/8093406111_6fa933bf78.jpg -------------------------------------------------------------------------------- /testing/TEST/8093406111_6fa933bf78.jpg.cat: -------------------------------------------------------------------------------- 1 | 147 59 258 244 -------------------------------------------------------------------------------- /testing/TEST/812794549d2511e1a9f71231382044a1_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/812794549d2511e1a9f71231382044a1_7.jpg -------------------------------------------------------------------------------- /testing/TEST/812794549d2511e1a9f71231382044a1_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 442 287 172 176 -------------------------------------------------------------------------------- /testing/TEST/84592b6ebedc11e1989612313815112c_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/84592b6ebedc11e1989612313815112c_7.jpg -------------------------------------------------------------------------------- /testing/TEST/84592b6ebedc11e1989612313815112c_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 255 400 75 75 -------------------------------------------------------------------------------- /testing/TEST/84bec45e2b7211e19e4a12313813ffc0_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/84bec45e2b7211e19e4a12313813ffc0_7.jpg -------------------------------------------------------------------------------- /testing/TEST/84bec45e2b7211e19e4a12313813ffc0_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 475 299 77 71 -------------------------------------------------------------------------------- /testing/TEST/8591817645_14993744d2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/8591817645_14993744d2.jpg -------------------------------------------------------------------------------- /testing/TEST/8591817645_14993744d2.jpg.cat: -------------------------------------------------------------------------------- 1 | 254 11 129 129 -------------------------------------------------------------------------------- /testing/TEST/8592298699_265576d71d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/8592298699_265576d71d.jpg -------------------------------------------------------------------------------- /testing/TEST/8592298699_265576d71d.jpg.cat: -------------------------------------------------------------------------------- 1 | 61 9 318 307 -------------------------------------------------------------------------------- /testing/TEST/8592651325_51b44f50ff.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/8592651325_51b44f50ff.jpg -------------------------------------------------------------------------------- /testing/TEST/8592651325_51b44f50ff.jpg.cat: -------------------------------------------------------------------------------- 1 | 182 53 138 134 -------------------------------------------------------------------------------- /testing/TEST/8593156480_03c3e57d50.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/8593156480_03c3e57d50.jpg -------------------------------------------------------------------------------- /testing/TEST/8593156480_03c3e57d50.jpg.cat: -------------------------------------------------------------------------------- 1 | 60 156 190 166 -------------------------------------------------------------------------------- /testing/TEST/8593717742_9162f0ef34.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/8593717742_9162f0ef34.jpg -------------------------------------------------------------------------------- /testing/TEST/8593717742_9162f0ef34.jpg.cat: -------------------------------------------------------------------------------- 1 | 113 122 259 231 -------------------------------------------------------------------------------- /testing/TEST/8f496896661b11e180d51231380fcd7e_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/8f496896661b11e180d51231380fcd7e_7.jpg -------------------------------------------------------------------------------- /testing/TEST/8f496896661b11e180d51231380fcd7e_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 68 179 277 301 -------------------------------------------------------------------------------- /testing/TEST/90d35578a43711e180d51231380fcd7e_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/90d35578a43711e180d51231380fcd7e_7.jpg -------------------------------------------------------------------------------- /testing/TEST/90d35578a43711e180d51231380fcd7e_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 338 213 40 39 -------------------------------------------------------------------------------- /testing/TEST/92df98b46efd11e18bb812313804a181_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/92df98b46efd11e18bb812313804a181_7.jpg -------------------------------------------------------------------------------- /testing/TEST/92df98b46efd11e18bb812313804a181_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 278 264 81 68 -------------------------------------------------------------------------------- /testing/TEST/9319d9f6ca3911e1b2fe1231380205bf_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/9319d9f6ca3911e1b2fe1231380205bf_7.jpg -------------------------------------------------------------------------------- /testing/TEST/9319d9f6ca3911e1b2fe1231380205bf_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 281 256 102 105 -------------------------------------------------------------------------------- /testing/TEST/93c475d0ff4c11e1839c123138192853_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/93c475d0ff4c11e1839c123138192853_7.jpg -------------------------------------------------------------------------------- /testing/TEST/93c475d0ff4c11e1839c123138192853_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 251 257 90 89 -------------------------------------------------------------------------------- /testing/TEST/9796956091a811e181bd12313817987b_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/9796956091a811e181bd12313817987b_7.jpg -------------------------------------------------------------------------------- /testing/TEST/9796956091a811e181bd12313817987b_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 176 75 265 211 -------------------------------------------------------------------------------- /testing/TEST/99890867_90c1e90437.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/99890867_90c1e90437.jpg -------------------------------------------------------------------------------- /testing/TEST/99890867_90c1e90437.jpg.cat: -------------------------------------------------------------------------------- 1 | 9 23 170 174 -------------------------------------------------------------------------------- /testing/TEST/a227324aa43711e19e4a12313813ffc0_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/a227324aa43711e19e4a12313813ffc0_7.jpg -------------------------------------------------------------------------------- /testing/TEST/a227324aa43711e19e4a12313813ffc0_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 222 375 64 70 -------------------------------------------------------------------------------- /testing/TEST/ac62bcbcac5111e1b9f1123138140926_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/ac62bcbcac5111e1b9f1123138140926_7.jpg -------------------------------------------------------------------------------- /testing/TEST/ac62bcbcac5111e1b9f1123138140926_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 181 264 80 83 -------------------------------------------------------------------------------- /testing/TEST/b1d94ca0ca3911e18cf91231380fd29b_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/b1d94ca0ca3911e18cf91231380fd29b_7.jpg -------------------------------------------------------------------------------- /testing/TEST/b1d94ca0ca3911e18cf91231380fd29b_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 54 22 437 443 -------------------------------------------------------------------------------- /testing/TEST/b3f6a1ae359711e19e4a12313813ffc0_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/b3f6a1ae359711e19e4a12313813ffc0_7.jpg -------------------------------------------------------------------------------- /testing/TEST/b3f6a1ae359711e19e4a12313813ffc0_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 396 360 56 57 -------------------------------------------------------------------------------- /testing/TEST/b672f508bedc11e1af7612313813f8e8_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/b672f508bedc11e1af7612313813f8e8_7.jpg -------------------------------------------------------------------------------- /testing/TEST/b672f508bedc11e1af7612313813f8e8_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 208 129 191 183 -------------------------------------------------------------------------------- /testing/TEST/bd9c8d0ea75711e1989612313815112c_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/bd9c8d0ea75711e1989612313815112c_7.jpg -------------------------------------------------------------------------------- /testing/TEST/bd9c8d0ea75711e1989612313815112c_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 380 479 49 42 -------------------------------------------------------------------------------- /testing/TEST/be87b8a0721f11e1b9f1123138140926_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/be87b8a0721f11e1b9f1123138140926_7.jpg -------------------------------------------------------------------------------- /testing/TEST/be87b8a0721f11e1b9f1123138140926_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 176 50 158 178 -------------------------------------------------------------------------------- /testing/TEST/business%2520cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/business%2520cat.jpg -------------------------------------------------------------------------------- /testing/TEST/business%2520cat.jpg.cat: -------------------------------------------------------------------------------- 1 | 102 45 209 220 -------------------------------------------------------------------------------- /testing/TEST/c47c1ca0ff4c11e1a76e22000a1e8903_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/c47c1ca0ff4c11e1a76e22000a1e8903_7.jpg -------------------------------------------------------------------------------- /testing/TEST/c47c1ca0ff4c11e1a76e22000a1e8903_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 50 0 450 410 -------------------------------------------------------------------------------- /testing/TEST/c9eead403a8c11e19e4a12313813ffc0_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/c9eead403a8c11e19e4a12313813ffc0_7.jpg -------------------------------------------------------------------------------- /testing/TEST/c9eead403a8c11e19e4a12313813ffc0_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 193 208 120 98 -------------------------------------------------------------------------------- /testing/TEST/chemistry%2520cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/chemistry%2520cat.jpg -------------------------------------------------------------------------------- /testing/TEST/chemistry%2520cat.jpg.cat: -------------------------------------------------------------------------------- 1 | 109 71 112 107 -------------------------------------------------------------------------------- /testing/TEST/d27f934ed5f411e19b0622000a1e8a4f_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/d27f934ed5f411e19b0622000a1e8a4f_7.jpg -------------------------------------------------------------------------------- /testing/TEST/d27f934ed5f411e19b0622000a1e8a4f_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 173 59 288 280 -------------------------------------------------------------------------------- /testing/TEST/de5ad150c19111e1b9f1123138140926_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/de5ad150c19111e1b9f1123138140926_7.jpg -------------------------------------------------------------------------------- /testing/TEST/de5ad150c19111e1b9f1123138140926_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 165 22 280 337 -------------------------------------------------------------------------------- /testing/TEST/e1bca2f66ff711e1a87612313804ec91_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/e1bca2f66ff711e1a87612313804ec91_7.jpg -------------------------------------------------------------------------------- /testing/TEST/e1bca2f66ff711e1a87612313804ec91_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 264 236 205 174 -------------------------------------------------------------------------------- /testing/TEST/e66928da64d311e19e4a12313813ffc0_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/e66928da64d311e19e4a12313813ffc0_7.jpg -------------------------------------------------------------------------------- /testing/TEST/e66928da64d311e19e4a12313813ffc0_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 300 164 309 292 -------------------------------------------------------------------------------- /testing/TEST/e8f4da56d3c611e18ca012313806b840_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/e8f4da56d3c611e18ca012313806b840_7.jpg -------------------------------------------------------------------------------- /testing/TEST/e8f4da56d3c611e18ca012313806b840_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 336 205 132 135 -------------------------------------------------------------------------------- /testing/TEST/ebd69cfc2bae11e1abb01231381b65e3_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/ebd69cfc2bae11e1abb01231381b65e3_7.jpg -------------------------------------------------------------------------------- /testing/TEST/ebd69cfc2bae11e1abb01231381b65e3_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 375 64 112 96 -------------------------------------------------------------------------------- /testing/TEST/ed45f0cc2e7111e19896123138142014_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/ed45f0cc2e7111e19896123138142014_7.jpg -------------------------------------------------------------------------------- /testing/TEST/ed45f0cc2e7111e19896123138142014_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 290 370 107 103 -------------------------------------------------------------------------------- /testing/TEST/f2033f0a6bb311e19e4a12313813ffc0_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/f2033f0a6bb311e19e4a12313813ffc0_7.jpg -------------------------------------------------------------------------------- /testing/TEST/f2033f0a6bb311e19e4a12313813ffc0_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 250 125 210 210 -------------------------------------------------------------------------------- /testing/TEST/f8558fc44b0c11e180c9123138016265_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/f8558fc44b0c11e180c9123138016265_7.jpg -------------------------------------------------------------------------------- /testing/TEST/f8558fc44b0c11e180c9123138016265_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 211 195 96 88 -------------------------------------------------------------------------------- /testing/TEST/fbe98620432f11e19e4a12313813ffc0_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harthur/kittydar/b58628d09f18e9e77adc9ce24ee9958d286fc278/testing/TEST/fbe98620432f11e19e4a12313813ffc0_7.jpg -------------------------------------------------------------------------------- /testing/TEST/fbe98620432f11e19e4a12313813ffc0_7.jpg.cat: -------------------------------------------------------------------------------- 1 | 277 194 101 102 -------------------------------------------------------------------------------- /testing/test.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"), 2 | path = require("path"), 3 | util = require("util"), 4 | async = require("async"), 5 | nomnom = require("nomnom"), 6 | Canvas = require("canvas"), 7 | color = require("colors"), 8 | charm = require("charm")(), 9 | utils = require("../utils"), 10 | nms = require("../nms"), 11 | kittydar = require("../kittydar"), 12 | todos = require("./todos"); 13 | 14 | charm.pipe(process.stdout); 15 | 16 | var opts = nomnom.options({ 17 | dir: { 18 | default: __dirname + "/TEST/", 19 | help: "directory of images to test" 20 | } 21 | }).parse(); 22 | 23 | var truePos = 0; 24 | var falsePos = 0; 25 | var misses = []; 26 | var newpasses = []; 27 | var newfails = []; 28 | 29 | var results = []; 30 | var count; 31 | 32 | var time = 0; 33 | 34 | runTest(); 35 | 36 | function runTest() { 37 | fs.readdir(opts.dir, function(err, files) { 38 | if (err) throw err; 39 | 40 | var images = files.filter(function(file) { 41 | return path.extname(file) == ".jpg"; 42 | }); 43 | 44 | count = images.length; 45 | 46 | console.log("running kittydar on " + count + " images"); 47 | printDots(); 48 | 49 | async.forEach(images, testImage, printResults); 50 | }); 51 | } 52 | 53 | function printResults() { 54 | charm.cursor(true); 55 | 56 | console.log("\n\ntrue positives: ", truePos.toString().green); 57 | console.log("false negatives: ", misses.length.toString().red); 58 | console.log("false positives: ", falsePos.toString().red); 59 | 60 | if (newpasses.length) { 61 | console.log("\nnew passes!".green); 62 | for (var i = 0; i < newpasses.length; i++) { 63 | console.log(newpasses[i]); 64 | } 65 | console.log("\n"); 66 | } 67 | 68 | if (newfails.length) { 69 | console.log("\nnew failures )=".red); 70 | for (var i = 0; i < newfails.length; i++) { 71 | console.log(newfails[i]); 72 | } 73 | console.log("\n"); 74 | } 75 | 76 | var avg = (time / count / 1000).toFixed(2); // baseline 5.08s 77 | console.log("\naverage time per image: " + avg + "s\n"); 78 | } 79 | 80 | function testImage(image, callback) { 81 | var file = opts.dir + image; 82 | 83 | fs.readFile(file + ".cat", "utf-8", function(err, text) { 84 | if (err) throw err; 85 | 86 | var vals = text.split(" ").map(function(val) { 87 | return parseInt(val) 88 | }); 89 | 90 | var rect; 91 | if (vals.length >= 4) { 92 | rect = { 93 | x: vals[0], 94 | y: vals[1], 95 | width: vals[2], 96 | height: vals[3] 97 | }; 98 | } 99 | 100 | utils.drawImgToCanvas(file, function(err, canvas) { 101 | // todo: detect time 102 | var t1 = Date.now(); 103 | 104 | var cats = kittydar.detectCats(canvas); 105 | 106 | time += Date.now() - t1; 107 | 108 | var found = false; 109 | cats.forEach(function(cat) { 110 | var overlaps = false; 111 | if (rect) { 112 | overlaps = nms.doesOverlap(cat, rect); 113 | } 114 | if (overlaps) { 115 | found = true; 116 | truePos++; 117 | } 118 | else { 119 | falsePos++; 120 | } 121 | }); 122 | 123 | if (found) { 124 | results.push("pass"); 125 | 126 | if (todos.indexOf(image) >= 0) { 127 | newpasses.push(file); 128 | } 129 | } 130 | else if (rect) { 131 | misses.push(file); 132 | results.push("fail"); 133 | 134 | if (todos.indexOf(image) == -1) { 135 | newfails.push(file); 136 | } 137 | } 138 | printDots(); 139 | 140 | callback(); 141 | }); 142 | }) 143 | } 144 | 145 | function printDots() { 146 | charm.erase("start"); 147 | charm.move(-count, 0); 148 | 149 | var str = ""; 150 | for (var i = 0; i < results.length; i++) { 151 | if (results[i] == "pass") { 152 | str += "•".green.bold; 153 | } 154 | else { 155 | str += "•".red.bold; 156 | } 157 | } 158 | var rest = count - results.length; 159 | 160 | for (var i = 0; i < rest; i++) { 161 | str += "·".grey; 162 | } 163 | charm.write(str); 164 | } 165 | -------------------------------------------------------------------------------- /testing/todos.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '00092f6ec7a911e1be6a12313820455d_7.jpg', // too small 3 | '0502a3b2a1e111e18cf91231380fd29b_7.jpg', // too small 4 | '066bdac8c71811e1a38422000a1c8933_7.jpg', // too small 5 | '25508c1e88ba11e1a87612313804ec91_7.jpg', // too small 6 | '10b80642c7da11e19894123138140d8c_7.jpg', // not facing forward 7 | '12a8d742be7f11e188131231381b5c25_7.jpg', // too small 8 | '2320b0ae089e11e29e6f22000a1e8b8a_7.jpg', // too small 9 | '33eb19201ed811e1abb01231381b65e3_7.jpg', // too small 10 | '2f49bd8cbf0911e180d51231380fcd7e_7.jpg', // head tilted 11 | '3437df14c7aa11e1aee522000a1e8a5f_7.jpg', // too small 12 | '55d268706e7111e1989612313815112c_7.jpg', // not facing forward 13 | '66250dd8be6011e1aebc1231381b647a_7.jpg', // --- should work 14 | '5804b25e64d211e18bb812313804a181_7.jpg', // ears cut off 15 | '5c7ac9ec6fa211e1a87612313804ec91_7.jpg', // ears cut off 16 | '67dcb80ab41b11e1aebc1231381b647a_7.jpg', // not facing forward 17 | '84592b6ebedc11e1989612313815112c_7.jpg', // too small 18 | '90d35578a43711e180d51231380fcd7e_7.jpg', // too small 19 | '7d7f0184a43711e1b10e123138105d6b_7.jpg', // too small 20 | '8f496896661b11e180d51231380fcd7e_7.jpg', // not facing forward 21 | '92df98b46efd11e18bb812313804a181_7.jpg', // not facing forward 22 | 'a227324aa43711e19e4a12313813ffc0_7.jpg', // too small 23 | 'bd9c8d0ea75711e1989612313815112c_7.jpg', // too small 24 | 'b1d94ca0ca3911e18cf91231380fd29b_7.jpg', // ---- should work 25 | 'b3f6a1ae359711e19e4a12313813ffc0_7.jpg', // too small, facing away 26 | 'c47c1ca0ff4c11e1a76e22000a1e8903_7.jpg', // ears cut off 27 | 'c9eead403a8c11e19e4a12313813ffc0_7.jpg', // ---- should work 28 | 'e8f4da56d3c611e18ca012313806b840_7.jpg', // not facing forward 29 | 'be87b8a0721f11e1b9f1123138140926_7.jpg', // head tilted 30 | '812794549d2511e1a9f71231382044a1_7.jpg', // not facing forward 31 | '219966284_4aa0a3c465.jpg', // ---- should work 32 | '2703668839_cfe0d6b154.jpg', // kitten tilt 33 | '474156503_d64e972df3.jpg', // should work 34 | '5929820421_b710bd97a4.jpg', // tilt 35 | '69375046_d06dc77299.jpg', // not facing forward, tilt 36 | '7023222_87b23bb0cd.jpg', // ---- should work 37 | '8591817645_14993744d2.jpg', // ---- should work 38 | '8593156480_03c3e57d50.jpg', // ---- should work 39 | '8593717742_9162f0ef34.jpg' // ---- should work 40 | ]; -------------------------------------------------------------------------------- /training/README.md: -------------------------------------------------------------------------------- 1 | # Training 2 | 3 | The goal of training is to create a classifier (in this case a neural network) that can be used to classify cat head images. 4 | 5 | After a final round of training you should have the JSON state of a neural network in the file "network.json", which can be imported and used by kittydar. 6 | 7 | ## collection 8 | 9 | First you need to collect positive and negative images to train the network with. See the `collection` directory for more information. 10 | 11 | ## train the classifier 12 | 13 | You can train a network with: 14 | 15 | ``` 16 | node train-network.js POSITIVES NEGATIVES 17 | ``` 18 | 19 | where POSITIVES is the directory of positive images (cat head crops), and NEGATIVES is a directory of samples from non-cat images. 20 | 21 | This will write the network to "network.json". 22 | 23 | ## test the classifier 24 | 25 | After training the network you can test the network on a set of test positive and negative images (different from the ones that trained it): 26 | 27 | ``` 28 | node test-network.js POSITIVES_TEST NEGATIVES_TEST --network ./network.json 29 | ``` 30 | 31 | This will report the neural network error, as well as binary classification statistics like precision and recall. 32 | 33 | ## optional: finding optimal parameters 34 | 35 | Find the best parameters for the feature extraction and classifier with cross-validation. Edit the `combos` object to add a combination and run with: 36 | 37 | ``` 38 | node cross-validate.js POSITIVES NEGATIVES 39 | ``` 40 | 41 | This will cross-validate on each combination of parameteres and report statistics on each combination, including the precision, recall, accuracy, and error of the test set. 42 | 43 | ## optional: mining hard negatives 44 | 45 | After you've trained a classifier, you can test the classifier on a different set of negative images and save any false positives as "hard negatives". You can take the hard negatives and the positives and train a new (more precise) classifier. 46 | 47 | ``` 48 | node mine-negatives.js NEGATIVES_EXTRA HARD --samples 1 --network ./network.json 49 | ``` 50 | 51 | where `HARD` is a new directory to hold the mined negatives. The `threshold` param determines when a negative is classified as hard. It's a number from 0.5 to 1.0 (from "leaning positive" to very false positive). 52 | 53 | `samples` is the number of times to sample each negative image. It can take a lot of images to find a few hard negatives if you're classifier is good enough, so specifying a higher value will mine more hard negatives in the end. 54 | 55 | You can then train a new classifier with: 56 | 57 | ``` 58 | node train-network.js POSITIVES HARD 59 | ``` 60 | 61 | -------------------------------------------------------------------------------- /training/collect.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"), 2 | path = require("path"), 3 | Canvas = require("canvas"), 4 | utils = require("../utils") 5 | features = require("./features"); 6 | 7 | exports.collectData = collectData; 8 | exports.extractSamples = extractSamples; 9 | 10 | /* 11 | * Collect the canvas representations of the images in the positive and 12 | * negative directories and return 13 | * an array of objects that look like: 14 | * { 15 | * input: from image features 16 | * output: [0,1] (depending if it's a cat or not) 17 | * file: 'test.jpg' 18 | * } 19 | */ 20 | function collectData(pos, neg, samples, posLimit, negLimit, params) { 21 | // number of samples to extract from each negative, 0 for whole image 22 | samples = samples || 0; 23 | params = params || {}; 24 | 25 | var data = []; 26 | for (var i = 0; i < pos.length; i++) { 27 | data = data.concat(getDir(pos[i], true, 0, posLimit, params)); 28 | } 29 | for (var i = 0; i < neg.length; i++) { 30 | data = data.concat(getDir(neg[i], false, samples, negLimit, params)); 31 | } 32 | 33 | // randomize so neural network doesn't get biased toward one set 34 | data.sort(function() { 35 | return 1 - 2 * Math.round(Math.random()); 36 | }); 37 | return data; 38 | } 39 | 40 | function getDir(dir, isCat, samples, limit, params) { 41 | var files = fs.readdirSync(dir); 42 | 43 | var images = files.filter(function(file) { 44 | return (path.extname(file) == ".png" 45 | || path.extname(file) == ".jpg"); 46 | }); 47 | 48 | images = images.slice(0, limit); 49 | 50 | var data = []; 51 | for (var i = 0; i < images.length; i++) { 52 | var file = dir + "/" + images[i]; 53 | try { 54 | var canvas = utils.drawImgToCanvasSync(file); 55 | } 56 | catch(e) { 57 | console.log(e, file); 58 | continue; 59 | } 60 | 61 | var canvases = extractSamples(canvas, samples); 62 | 63 | for (var j = 0; j < canvases.length; j++) { 64 | var fts; 65 | try { 66 | fts = features.extractFeatures(canvases[j], params.HOG); 67 | } catch(e) { 68 | console.log("error extracting features", e, file); 69 | continue; 70 | } 71 | data.push({ 72 | input: new Float64Array(fts), 73 | output: [isCat ? 1 : 0], 74 | file: file, 75 | }); 76 | } 77 | } 78 | 79 | return data; 80 | } 81 | 82 | 83 | function extractSamples(canvas, num) { 84 | if (num == 0) { 85 | // 0 means "don't sample" 86 | return [canvas]; 87 | } 88 | 89 | var min = 48; 90 | var max = Math.min(canvas.width, canvas.height); 91 | 92 | var canvases = []; 93 | for (var i = 0; i < num; i++) { 94 | var length = Math.max(min, Math.ceil(Math.random() * max)); 95 | 96 | var x = Math.floor(Math.random() * (max - length)); 97 | var y = Math.floor(Math.random() * (max - length)); 98 | 99 | canvases.push(cropCanvas(canvas, x, y, length, length)); 100 | } 101 | return canvases; 102 | } 103 | 104 | function cropCanvas(canvas, x, y, width, height) { 105 | var cropCanvas = new Canvas(width, height); 106 | var context = cropCanvas.getContext("2d"); 107 | context.drawImage(canvas, x, y, width, height, 0, 0, width, height); 108 | return cropCanvas; 109 | } -------------------------------------------------------------------------------- /training/collection/README.md: -------------------------------------------------------------------------------- 1 | ## collection 2 | 3 | the goal of collection is to get a folder of positive (cat head) images and a folder of negative (non-cat) images to train the classifier with. 4 | 5 | ### creating the positives 6 | 7 | To get the positives, first download this [dataset of cat pictures](http://137.189.35.203/WebUI/CatDatabase/catData.html). There should be folders called CAT_00, CAT_01, etc. Take the images from all of these and combine into one directory. Also remove the file "00000003_019.jpg.cat" and add [00000003_015.jpg.cat](http://137.189.35.203/WebUI/CatDatabase/Data/00000003_015.jpg.cat). 8 | 9 | Run the script to rotate and the crop out the cat head from each image. If you put the cat dataset in a folder called "CATS" and you want to put the cropped images in a folder called "POSITIVES": 10 | 11 | `node make-positives.js CATS POSITIVES` 12 | 13 | ### creating the negatives 14 | 15 | If you don't already have a bunch of non-cat pictures you can fetch recent images from Flickr and save them in a folder called "FLICKR" by running: 16 | 17 | `ruby fetch-negatives.rb NEGATIVES` 18 | 19 | You'll need at least 10,000 images. 20 | 21 | To turn the full-sized images into negatives that can be used directly for training or testing, sample them with: 22 | 23 | `node make-negatives NEGATIVES NEGATIVES_SAMPLED` 24 | 25 | Where `NEGATIVES_SAMPLED` is the directory to contain the sampled images. 26 | 27 | If you're getting images from Flickr, some will contain cats for sure, so you'll need to weed those out by taking a close look at your hard negatives (see `training` directory above). 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /training/collection/fetch-negatives.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'open-uri' 3 | require 'flickraw' 4 | 5 | FlickRaw.api_key="0cc11cffc8a238efef4dfa6dca255a44" 6 | FlickRaw.shared_secret="5f76a97053f99673" 7 | 8 | $fetched = Hash.new 9 | 10 | $dir = ARGV[0] 11 | 12 | def getPage(page) 13 | list = flickr.photos.getRecent :per_page => 500, :page => page 14 | 15 | list.each do |photo| 16 | url = "http://farm#{photo.farm}.staticflickr.com/#{photo.server}/#{photo.id}_#{photo.secret}.jpg" 17 | 18 | if $fetched[url] != 1 19 | $fetched[url] = 1 20 | 21 | name = rand(1000000000000000) 22 | 23 | file = "#{$dir}/#{name}.jpg" 24 | 25 | open(file, 'wb') do |file| 26 | file << open(url).read 27 | end 28 | end 29 | end 30 | end 31 | 32 | # gets 120 x 500 = 60,000 images 33 | 120.times do |i| 34 | getPage(i) 35 | end -------------------------------------------------------------------------------- /training/collection/make-negatives.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"), 2 | path = require("path"), 3 | nomnom = require("nomnom"), 4 | Canvas = require("canvas"), 5 | utils = require("../../utils"); 6 | 7 | var opts = nomnom.options({ 8 | indir: { 9 | position: 0, 10 | default: __dirname + "/FLICKR/", 11 | help: "Directory of full-sizes negative images" 12 | }, 13 | outdir: { 14 | position: 1, 15 | default: __dirname + "/NEGATIVES/", 16 | help: "Directory to save cropped image sections" 17 | }, 18 | samples: { 19 | default: 1, 20 | help: "How many times to sub-sample each image" 21 | } 22 | }).colors().parse(); 23 | 24 | 25 | fs.readdir(opts.indir, function(err, files) { 26 | if (err) throw err; 27 | 28 | var images = files.filter(function(file) { 29 | return path.extname(file) == ".jpg"; 30 | }); 31 | 32 | console.log(images.length, "images to process"); 33 | 34 | images.forEach(function(image) { 35 | var file = opts.indir + "/" + image; 36 | try { 37 | var canvas = utils.drawImgToCanvasSync(file); 38 | } 39 | catch(e) { 40 | console.log(e, file); 41 | return; 42 | } 43 | var canvases = extractSamples(canvas, opts.samples); 44 | 45 | canvases.forEach(function(canvas) { 46 | var name = Math.floor(Math.random() * 10000000000); 47 | var file = opts.outdir + "/" + name + ".jpg"; 48 | 49 | utils.writeCanvasToFileSync(canvas, file); 50 | }); 51 | }); 52 | }) 53 | 54 | function extractSamples(canvas, num) { 55 | var min = 48; 56 | var max = Math.min(canvas.width, canvas.height); 57 | 58 | var canvases = []; 59 | for (var i = 0; i < num; i++) { 60 | var length = Math.max(48, Math.ceil(Math.random() * max)); 61 | 62 | var x = Math.floor(Math.random() * (max - length)); 63 | var y = Math.floor(Math.random() * (max - length)); 64 | 65 | canvases.push(cropCanvas(canvas, x, y, length, length)); 66 | } 67 | return canvases; 68 | } 69 | 70 | function cropCanvas(canvas, x, y, width, height) { 71 | var cropCanvas = new Canvas(width, height); 72 | var context = cropCanvas.getContext("2d"); 73 | context.drawImage(canvas, x, y, width, height, 0, 0, width, height); 74 | return cropCanvas; 75 | } 76 | -------------------------------------------------------------------------------- /training/collection/make-positives.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"), 2 | path = require("path"), 3 | nomnom = require("nomnom"), 4 | Canvas = require("canvas"), 5 | utils = require("../../utils"); 6 | 7 | var opts = nomnom.options({ 8 | indir: { 9 | position: 0, 10 | default: __dirname + "/CAT_DATASET/", 11 | help: "Directory of cat pics from http://137.189.35.203/WebUI/CatDatabase/catData.html" 12 | }, 13 | outdir: { 14 | position: 1, 15 | default: __dirname + "/POSITIVES/", 16 | help: "Directory to save rotated and cropped cat face images" 17 | } 18 | }).colors().parse() 19 | 20 | // Crop the cat head from each photo in cat dataset. 21 | // Everything is sync to avoid OS fd limit 22 | fs.readdir(opts.indir, function(err, files) { 23 | if (err) throw err; 24 | 25 | var images = files.filter(function(file) { 26 | return path.extname(file) == ".jpg"; 27 | }) 28 | 29 | console.log(images.length, "cat images"); 30 | 31 | console.time("cropping"); 32 | 33 | for (var i = 0; i < images.length; i++) { 34 | var file = images[i]; 35 | var infile = opts.indir + "/" + file; 36 | var outfile = opts.outdir + "/" + path.basename(file, ".jpg") + ".png"; 37 | 38 | cropFace(infile, outfile); 39 | 40 | if (i % 50 == 0) { 41 | console.log(i); 42 | } 43 | } 44 | 45 | console.timeEnd("cropping"); 46 | }); 47 | 48 | function cropFace(file, outfile) { 49 | var canvas = utils.drawImgToCanvasSync(file); 50 | 51 | var catfile = file + ".cat"; 52 | var annotations = getCatDataSync(catfile); 53 | 54 | var processed = transformCanvas(canvas, annotations, file); 55 | 56 | utils.writeCanvasToFileSync(processed, outfile); 57 | } 58 | 59 | function getCatDataSync(file, callback) { 60 | // read special annotation file from cat dataset 61 | var text = fs.readFileSync(file, "utf-8"); 62 | 63 | var vals = text.split(" ").map(parseFloat); 64 | var length = vals[0]; 65 | if (length != 9) { 66 | console.log("different number of points:", length); 67 | } 68 | 69 | // locations of ears, eyes, and mouth 70 | var features = ["leye", "reye", "mouth", "lear1", "lear2", 71 | "lear3", "rear1", "rear2", "rear3"]; 72 | var points = {}; 73 | for (var i = 0; i < length; i ++) { 74 | points[features[i]] = { 75 | x: vals[i * 2 + 1], 76 | y: vals[i * 2 + 2] 77 | } 78 | } 79 | 80 | return points; 81 | } 82 | 83 | function transformCanvas(canvas, points, file) { 84 | // Rotate and crop according to the shape detector training specifications in 85 | // "Cat Head Detection - How to Effectively Exploit Shape and Texture Features" 86 | // http://research.microsoft.com/pubs/80582/ECCV_CAT_PROC.pdf 87 | 88 | // if cat's head is turned more than 90deg 89 | var flipped = points.lear2.x > points.rear2.x; 90 | 91 | // find angle the face is tilted at 92 | var opp = points.rear2.y - points.lear2.y; 93 | var adj = points.rear2.x - points.lear2.x; 94 | if (flipped) { 95 | adj = -adj; 96 | } 97 | var hyp = Math.sqrt(Math.pow(opp, 2) + Math.pow(adj, 2)); 98 | 99 | var angle = -Math.atan(opp / adj); 100 | 101 | var rotation = angle; 102 | if (flipped) { 103 | if (angle < 0) { 104 | rotation = Math.PI - angle; 105 | } 106 | else { 107 | rotation = Math.PI - angle; 108 | } 109 | } 110 | 111 | var length = 4/3 * hyp; // length of final square canvas 112 | var drop = (5/12 * length); // len from ears to center of face 113 | 114 | // make a new canvas that can fit rotated image 115 | var dim = canvas.width + canvas.height; 116 | var transCanvas = new Canvas(dim, dim); 117 | var ctx = transCanvas.getContext("2d"); 118 | 119 | // will rotate on draw so tips of cat's ears are horizontal 120 | var half = dim / 2; 121 | ctx.translate(half, half); 122 | ctx.rotate(rotation); 123 | ctx.translate(-half, -half) 124 | 125 | var longOpp = Math.cos(angle) * drop; 126 | var longAdj = Math.sin(angle) * drop; 127 | 128 | var addX, addY; 129 | 130 | if (flipped) { 131 | addX = longAdj -(adj / 2); 132 | addY = -longOpp -(opp / 2); 133 | } 134 | else { 135 | addX = longAdj + (adj / 2); 136 | addY = longOpp - (opp / 2); 137 | } 138 | 139 | var centerX = points.lear2.x + addX; 140 | var centerY = points.rear2.y + addY; 141 | 142 | // draw image so center of cat's face is in the center of canvas 143 | ctx.drawImage(canvas, half - centerX, half - centerY); 144 | 145 | var cropCanvas = new Canvas(length, length); 146 | ctx = cropCanvas.getContext("2d"); 147 | 148 | // crop and resize cat face 149 | var dim = hyp / 0.75; 150 | ctx.drawImage(transCanvas, half - (dim / 2), half - (dim / 2), 151 | dim, dim, 0, 0, length, length); 152 | 153 | return cropCanvas; 154 | } 155 | -------------------------------------------------------------------------------- /training/features.js: -------------------------------------------------------------------------------- 1 | var hog = require("hog-descriptor"), 2 | utils = require("../utils"); 3 | 4 | var size = 48; 5 | 6 | exports.extractFeatures = function(canvas, params) { 7 | canvas = utils.resizeCanvas(canvas, size, size); 8 | 9 | var descriptor = hog.extractHOG(canvas, params); 10 | return descriptor; 11 | } -------------------------------------------------------------------------------- /training/neuralnet/cross-validate.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"), 2 | path = require("path"), 3 | nomnom = require("nomnom"), 4 | brain = require("brain"), 5 | utils = require("../../utils"), 6 | collect = require("../collect"); 7 | 8 | var opts = nomnom.options({ 9 | pos: { 10 | abbr: 'p', 11 | list: true, 12 | required: true, 13 | help: "Directory of cat head images" 14 | }, 15 | neg: { 16 | abbr: 'n', 17 | list: true, 18 | required: true, 19 | help: "Directory of negative images" 20 | }, 21 | sample: { 22 | flag: true, 23 | help: "Sub-sample negative images" 24 | }, 25 | limit: { 26 | default: 10000, 27 | help: "Max images to collect from each directory" 28 | } 29 | }).colors().parse(); 30 | 31 | 32 | var combos = [ 33 | { 34 | HOG: { 35 | cellSize: 4, 36 | blockSize: 3, 37 | blockStride: 3, 38 | bins: 6, 39 | norm: "L2" 40 | }, 41 | nn: { 42 | hiddenLayers: [10, 10], 43 | binaryThresh: 0.99 44 | }, 45 | train: { 46 | errorThresh: 0.008 47 | } 48 | }, 49 | { 50 | HOG: { 51 | cellSize: 3, 52 | blockSize: 4, 53 | blockStride: 4, 54 | bins: 6, 55 | norm: "L2" 56 | }, 57 | nn: { 58 | hiddenLayers: [10, 10], 59 | binaryThresh: 0.99 60 | }, 61 | train: { 62 | errorThresh: 0.008 63 | } 64 | } 65 | ]; 66 | 67 | console.log("testing", combos.length, "combinations"); 68 | 69 | testAll(combos); 70 | 71 | function testAll(combos) { 72 | var tests = []; 73 | 74 | for (var i = 0; i < combos.length; i++) { 75 | var params = combos[i]; 76 | var samples = opts.sample ? 1 : 0; 77 | var data = collect.collectData(opts.pos, opts.neg, samples, 78 | opts.limit, opts.limit, params); 79 | 80 | console.log("testing", i + 1 + ": " + JSON.stringify(params), "on " + data.length) 81 | 82 | var stats = testParams(data, params); 83 | var test = { 84 | params: params, 85 | featureSize: stats.featureSize, 86 | avgs: stats.avgs, 87 | stats: stats.stats 88 | }; 89 | tests.push(test); 90 | 91 | console.log(test); 92 | 93 | if (i == combos.length - 1) { 94 | console.log("\n" + getPrintout(tests)); 95 | 96 | fs.writeFile('tests.json', JSON.stringify(tests, 4), function (err) { 97 | if (err) throw err; 98 | console.log('saved tests to tests.json'); 99 | }); 100 | } 101 | } 102 | } 103 | 104 | function testParams(data, params) { 105 | var trainOpts = params.train; 106 | trainOpts.log = true; 107 | 108 | var stats = brain.crossValidate(brain.NeuralNetwork, data, 109 | params.nn, trainOpts); 110 | stats.featureSize = data[0].input.length; 111 | return stats; 112 | } 113 | 114 | function getPrintout(tests) { 115 | tests.sort(function(test1, test2) { 116 | return test1.stats.falsePos > test2.stats.falsePos; 117 | }); 118 | var lines = tests.map(function(test) { 119 | return JSON.stringify(test.params) + " " 120 | + "size: " + test.featureSize + " " 121 | + "p: " + test.stats.precision.toFixed(3) + " " 122 | + "r: " + test.stats.recall.toFixed(3) + " " 123 | + "a: " + test.stats.accuracy.toFixed(3) + " " 124 | + "fp: " + test.stats.falsePos; 125 | }); 126 | return lines.join("\n"); 127 | } 128 | -------------------------------------------------------------------------------- /training/neuralnet/mine-negatives.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"), 2 | path = require("path"), 3 | brain = require("brain"), 4 | nomnom = require("nomnom"), 5 | params = require("./params"), 6 | features = require("../features"), 7 | utils = require("../../utils") 8 | collect = require("../collect"); 9 | 10 | var opts = nomnom.options({ 11 | negDir: { 12 | position: 0, 13 | default: __dirname + "/collection/NEGATIVES/", 14 | required: true, 15 | help: "Directory of negatives" 16 | }, 17 | minedDir: { 18 | position: 1, 19 | default: __dirname + "/collection/MINED_NEGATIVES/", 20 | required: true, 21 | help: "Directory to put mined hard negatives in" 22 | }, 23 | network: { 24 | default: __dirname + "/network.json", 25 | help: "Neural network JSON file" 26 | }, 27 | samples: { 28 | default: 1, 29 | help: "How many times to sub-sample full negative image" 30 | }, 31 | limit: { 32 | default: undefined, 33 | help: "Max number of negative images to process from directory" 34 | }, 35 | threshold: { 36 | default: 0.9, 37 | help: "How wrong the classification is, from 0.5+ to 1.0" 38 | } 39 | }).colors().parse(); 40 | 41 | var trained = require(opts.network); 42 | var network = new brain.NeuralNetwork().fromJSON(trained); 43 | 44 | mineNegatives(); 45 | 46 | function mineNegatives() { 47 | var files = fs.readdirSync(opts.negDir); 48 | 49 | var images = files.filter(function(file) { 50 | return (path.extname(file) == ".png" 51 | || path.extname(file) == ".jpg"); 52 | }); 53 | images = images.slice(0, opts.limit); 54 | 55 | console.time("mined in"); 56 | console.log("mining negatives from " + images.length); 57 | 58 | var falsePositives = 0; 59 | for (var i = 0; i < images.length; i++) { 60 | var image = images[i]; 61 | var file = opts.negDir + "/" + image; 62 | 63 | try { 64 | var canvas = utils.drawImgToCanvasSync(file); 65 | } 66 | catch (e) { 67 | console.log(e, file); 68 | fs.unlinkSync(file); 69 | console.log("deleted", file); 70 | } 71 | var samples = collect.extractSamples(canvas, opts.samples); 72 | 73 | for (var j = 0; j < samples.length; j++) { 74 | var fp = testSample(image, samples[j]); 75 | falsePositives += fp ? 1 : 0; 76 | } 77 | } 78 | console.log(falsePositives + " hard negatives mined"); 79 | console.timeEnd("mined in"); 80 | } 81 | 82 | function testSample(file, canvas) { 83 | var fts = features.extractFeatures(canvas, params.HOG); 84 | var result = network.run(fts); 85 | 86 | if (result >= opts.threshold) { 87 | console.log("false positive", file); 88 | var rand = Math.floor(Math.random() * 1000); 89 | var file = opts.minedDir + "/" + rand + "_" + path.basename(file); 90 | utils.writeCanvasToFileSync(canvas, file); 91 | return true; 92 | } 93 | return false; 94 | } 95 | -------------------------------------------------------------------------------- /training/neuralnet/params.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | HOG: { 3 | cellSize: 4, 4 | blockSize: 2, 5 | blockStride: 1, 6 | bins: 6, 7 | norm: "L2" 8 | }, 9 | nn: { 10 | hiddenLayers: [10, 10], 11 | binaryThresh: 0.99 12 | }, 13 | train: { 14 | errorThresh: 0.008 15 | } 16 | } -------------------------------------------------------------------------------- /training/neuralnet/test-network.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"), 2 | path = require("path"), 3 | brain = require("brain"), 4 | nomnom = require("nomnom"), 5 | params = require("./params"), 6 | utils = require("../../utils"), 7 | collect = require("../collect"); 8 | 9 | var opts = nomnom.options({ 10 | pos: { 11 | abbr: 'p', 12 | list: true, 13 | required: true, 14 | help: "Directory of test positive images" 15 | }, 16 | neg: { 17 | abbr: 'n', 18 | list: true, 19 | required: true, 20 | help: "Directory of test negative images" 21 | }, 22 | json: { 23 | default: __dirname + "/network.json", 24 | help: "Neural network JSON file" 25 | }, 26 | sample: { 27 | flag: true, 28 | help: "sub-sample the negative images" 29 | }, 30 | threshold: { 31 | default: 0.99, 32 | help: "threshold for classifying as a positive" 33 | } 34 | }).colors().parse(); 35 | 36 | testNetwork(); 37 | 38 | function testNetwork() { 39 | var data = collect.collectData(opts.pos, opts.neg, opts.sample ? 1 : 0, undefined, 40 | undefined, params); 41 | console.log("testing on", data.length); 42 | 43 | console.log("feature size", data[0].input.length); 44 | 45 | var json = require(opts.json); 46 | var network = new brain.NeuralNetwork({ 47 | binaryThresh: opts.threshold 48 | }).fromJSON(json); 49 | 50 | var stats = network.test(data); 51 | 52 | console.log("error: " + stats.error); 53 | console.log("precision: " + stats.precision) 54 | console.log("recall: " + stats.recall) 55 | console.log("accuracy: " + stats.accuracy) 56 | 57 | console.log(stats.truePos + " true positives"); 58 | console.log(stats.trueNeg + " true negatives"); 59 | console.log(stats.falsePos + " false positives"); 60 | console.log(stats.falseNeg + " false negatives"); 61 | console.log(stats.total + " total"); 62 | } 63 | -------------------------------------------------------------------------------- /training/neuralnet/train-network.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"), 2 | brain = require("brain"), 3 | path = require("path"), 4 | nomnom = require("nomnom"), 5 | utils = require("../../utils"), 6 | collect = require("../collect"); 7 | 8 | var opts = nomnom.options({ 9 | pos: { 10 | abbr: 'p', 11 | list: true, 12 | required: true, 13 | help: "Directory of cat head images" 14 | }, 15 | neg: { 16 | abbr: 'n', 17 | list: true, 18 | required: true, 19 | help: "Directory of negative images" 20 | }, 21 | testPos: { 22 | list: true, 23 | help: "Directory of positive test images" 24 | }, 25 | testNeg: { 26 | list: true, 27 | help: "Directory of negative test images" 28 | }, 29 | outfile: { 30 | default: __dirname + "/network.json", 31 | help: "file to save network JSON to" 32 | }, 33 | sample: { 34 | flag: true, 35 | help: "whether to sub-sample the negative images", 36 | hidden: true 37 | }, 38 | posLimit: { 39 | default: 10000, 40 | help: "maximum number of positive images to use" 41 | }, 42 | negLimit: { 43 | default: 10000, 44 | help: "maximum number of negative images to use" 45 | } 46 | }).colors().parse(); 47 | 48 | var params = { 49 | HOG: { 50 | cellSize: 4, 51 | blockSize: 2, 52 | blockStride: 1, 53 | bins: 6, 54 | norm: "L2" 55 | }, 56 | nn: { 57 | hiddenLayers: [10, 10], 58 | learningRate: 0.2 59 | }, 60 | train: { 61 | errorThresh: 0.008, 62 | log: true, 63 | logPeriod: 1 64 | } 65 | }; 66 | 67 | trainNetwork(params) 68 | 69 | function trainNetwork(params) { 70 | var samples = opts.sample ? 1 : 0; 71 | var data = collect.collectData(opts.pos, opts.neg, samples, 72 | opts.posLimit, opts.negLimit, params); 73 | 74 | console.log("training on", data.length); 75 | console.log("feature size:", data[0].input.length) 76 | 77 | var network = new brain.NeuralNetwork(params.nn); 78 | 79 | var stats = network.train(data, params.train); 80 | 81 | console.log("stats:", stats); 82 | console.log("parameters:", params); 83 | 84 | var json = JSON.stringify(network.toJSON(), 4) 85 | 86 | fs.writeFile(opts.outfile, json, function (err) { 87 | if (err) throw err; 88 | console.log('saved network to', opts.outfile); 89 | }); 90 | 91 | if (opts.testPos && opts.testNeg) { 92 | testNetwork(network); 93 | } 94 | } 95 | 96 | function testNetwork(network) { 97 | var data = collect.collectData(opts.testPos, opts.testNeg, opts.sample ? 1 : 0, 98 | undefined, undefined, params); 99 | console.log("testing on", data.length); 100 | console.log("feature size", data[0].input.length); 101 | 102 | console.time("TEST"); 103 | 104 | var stats = network.test(data); 105 | 106 | console.timeEnd("TEST"); 107 | 108 | console.log("error: " + stats.error); 109 | console.log("precision: " + stats.precision) 110 | console.log("recall: " + stats.recall) 111 | console.log("accuracy: " + stats.accuracy) 112 | 113 | console.log(stats.truePos + " true positives"); 114 | console.log(stats.trueNeg + " true negatives"); 115 | console.log(stats.falsePos + " false positives"); 116 | console.log(stats.falseNeg + " false negatives"); 117 | console.log(stats.total + " total"); 118 | } 119 | -------------------------------------------------------------------------------- /training/svm/cross-validate.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"), 2 | path = require("path"), 3 | nomnom = require("nomnom"), 4 | svm = require("svm"), 5 | utils = require("../../utils"), 6 | _ = require("underscore"), 7 | collect = require("../collect"); 8 | 9 | var opts = nomnom.options({ 10 | pos: { 11 | abbr: 'p', 12 | list: true, 13 | required: true, 14 | help: "Directory of positive training images" 15 | }, 16 | neg: { 17 | abbr: 'n', 18 | list: true, 19 | required: true, 20 | help: "Directory of negative training images" 21 | }, 22 | sample: { 23 | flag: true, 24 | help: "Sub-sample negative images" 25 | }, 26 | limit: { 27 | default: 10000, 28 | help: "Max images to collect from each directory" 29 | } 30 | }).colors().parse(); 31 | 32 | 33 | var combos = [ 34 | { 35 | HOG: { 36 | cellSize: 4, 37 | blockSize: 2, 38 | blockStride: 1, 39 | bins: 7, 40 | norm: "L2" 41 | }, 42 | svm: { 43 | numpasses: 5, 44 | C: 0.001, 45 | } 46 | }, 47 | { 48 | HOG: { 49 | cellSize: 4, 50 | blockSize: 2, 51 | blockStride: 1, 52 | bins: 9, 53 | norm: "L2" 54 | }, 55 | svm: { 56 | numpasses: 5, 57 | C: 0.001, 58 | } 59 | }, 60 | { 61 | HOG: { 62 | cellSize: 4, 63 | blockSize: 2, 64 | blockStride: 1, 65 | bins: 6, 66 | norm: "L2" 67 | }, 68 | svm: { 69 | numpasses: 5, 70 | C: 0.001, 71 | } 72 | } 73 | ]; 74 | 75 | console.log("testing", combos.length, "combinations"); 76 | 77 | testAll(combos); 78 | 79 | function testAll(combos) { 80 | var tests = []; 81 | 82 | for (var i = 0; i < combos.length; i++) { 83 | var params = combos[i]; 84 | var samples = opts.sample ? 1 : 0; 85 | var data = collect.collectData(opts.pos, opts.neg, samples, 86 | opts.limit, opts.limit, params); 87 | 88 | console.log("testing", i + 1 + ": " + JSON.stringify(params), "on " + data.length) 89 | 90 | var stats = testParams(data, params); 91 | var test = { 92 | params: params, 93 | featureSize: stats.featureSize, 94 | avgs: stats.avgs, 95 | stats: stats.stats 96 | }; 97 | tests.push(test); 98 | 99 | console.log(test); 100 | 101 | if (i == combos.length - 1) { 102 | console.log("\n" + getPrintout(tests)); 103 | 104 | fs.writeFile('tests.json', JSON.stringify(tests, 4), function (err) { 105 | if (err) throw err; 106 | console.log('saved tests to tests.json'); 107 | }); 108 | } 109 | } 110 | } 111 | 112 | function testParams(data, params) { 113 | var stats = crossValidate(data, params.svm); 114 | stats.featureSize = data[0].input.length; 115 | 116 | return stats; 117 | } 118 | 119 | function getPrintout(tests) { 120 | tests.sort(function(test1, test2) { 121 | return test1.stats.falsePos > test2.stats.falsePos; 122 | }); 123 | var lines = tests.map(function(test) { 124 | return JSON.stringify(test.params) + " " 125 | + "size: " + test.featureSize + " " 126 | + "p: " + test.stats.precision.toFixed(3) + " " 127 | + "r: " + test.stats.recall.toFixed(3) + " " 128 | + "a: " + test.stats.accuracy.toFixed(3) + " " 129 | + "fp: " + test.stats.falsePos; 130 | }); 131 | return lines.join("\n"); 132 | } 133 | 134 | 135 | function testPartition(trainSet, testSet, params) { 136 | var SVM = new svm.SVM(); 137 | var inputs = new Array(trainSet.length); 138 | var labels = new Int8Array(trainSet.length); 139 | 140 | for (var i = 0; i < trainSet.length; i++) { 141 | inputs[i] = trainSet[i].input; 142 | labels[i] = trainSet[i].output[0] || -1; 143 | } 144 | 145 | var beginTrain = Date.now(); 146 | 147 | var trainingStats = SVM.train(inputs, labels, params); 148 | 149 | var beginTest = Date.now(); 150 | 151 | var truePos = 0, trueNeg = 0, falsePos = 0, falseNeg = 0; 152 | 153 | for (var i = 0; i < testSet.length; i++) { 154 | var output = testSet[i].output[0]; 155 | input = testSet[i].input; 156 | var result = SVM.predict([input])[0]; 157 | 158 | if (result == 1 && output == 1) { 159 | truePos++; 160 | } 161 | else if (result == -1 && output == 0) { 162 | trueNeg++; 163 | } 164 | else if (result == 1 && output == 0) { 165 | falsePos++; 166 | } 167 | else if (result == -1 && output == 1) { 168 | falseNeg++; 169 | } 170 | } 171 | 172 | var endTest = Date.now(); 173 | 174 | var stats = { 175 | trainTime : beginTest - beginTrain, 176 | trainTimePerIter: (beginTest - beginTrain) / trainingStats.iters, 177 | testTime : endTest - beginTest, 178 | iterations: trainingStats.iters, 179 | falsePos: falsePos, 180 | truePos: truePos, 181 | falseNeg: falseNeg, 182 | trueNeg: trueNeg, 183 | total: testSet.length 184 | }; 185 | 186 | return stats; 187 | } 188 | 189 | function crossValidate(data, params) { 190 | var k = 4; 191 | var size = data.length / k; 192 | 193 | var avgs = { 194 | trainTime : 0, 195 | testTime : 0, 196 | iterations: 0, 197 | trainTimePerIter: 0 198 | }; 199 | 200 | var stats = { 201 | truePos: 0, 202 | trueNeg: 0, 203 | falsePos: 0, 204 | falseNeg: 0, 205 | total: 0 206 | }; 207 | 208 | var results = _.range(k).map(function(i) { 209 | var dclone = _(data).clone(); 210 | var testSet = dclone.splice(i * size, size); 211 | var trainSet = dclone; 212 | 213 | var result = testPartition(trainSet, testSet, params); 214 | 215 | _(avgs).each(function(sum, stat) { 216 | avgs[stat] = sum + result[stat]; 217 | }); 218 | 219 | _(stats).each(function(sum, stat) { 220 | stats[stat] = sum + result[stat]; 221 | }) 222 | 223 | return result; 224 | }); 225 | 226 | _(avgs).each(function(sum, i) { 227 | avgs[i] = sum / k; 228 | }); 229 | 230 | stats.precision = stats.truePos / (stats.truePos + stats.falsePos); 231 | stats.recall = stats.truePos / (stats.truePos + stats.falseNeg); 232 | stats.accuracy = (stats.trueNeg + stats.truePos) / stats.total; 233 | 234 | stats.testSize = size; 235 | stats.trainSize = data.length - size; 236 | 237 | return { 238 | avgs: avgs, 239 | stats: stats, 240 | sets: results 241 | }; 242 | } 243 | -------------------------------------------------------------------------------- /training/svm/mine-negatives.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"), 2 | path = require("path"), 3 | svm = require("svm"), 4 | nomnom = require("nomnom"), 5 | params = require("./params"), 6 | features = require("../features"), 7 | utils = require("../../utils"), 8 | collect = require("../collect"); 9 | 10 | var opts = nomnom.options({ 11 | negDir: { 12 | position: 0, 13 | default: __dirname + "/collection/NEGATIVES/", 14 | required: true, 15 | help: "Directory of negatives" 16 | }, 17 | minedDir: { 18 | position: 1, 19 | default: __dirname + "/collection/MINED_NEGATIVES/", 20 | required: true, 21 | help: "Directory to put mined hard negatives in" 22 | }, 23 | jsonFile: { 24 | default: __dirname + "/svm.json", 25 | help: "Neural network JSON file" 26 | }, 27 | samples: { 28 | default: 1, 29 | help: "How many times to sub-sample full negative image" 30 | }, 31 | limit: { 32 | default: undefined, 33 | help: "Max number of negative images to process from directory" 34 | } 35 | }).colors().parse(); 36 | 37 | var obj = require(opts.jsonFile); 38 | 39 | var SVM = new svm.SVM(); 40 | SVM.fromJSON(obj); 41 | 42 | mineNegatives(); 43 | 44 | function mineNegatives() { 45 | var files = fs.readdirSync(opts.negDir); 46 | 47 | var images = files.filter(function(file) { 48 | return (path.extname(file) == ".png" 49 | || path.extname(file) == ".jpg"); 50 | }); 51 | images = images.slice(0, opts.limit); 52 | 53 | console.time("mined in"); 54 | console.log("mining negatives from " + images.length); 55 | 56 | var falsePositives = 0; 57 | for (var i = 0; i < images.length; i++) { 58 | var image = images[i]; 59 | var file = opts.negDir + "/" + image; 60 | 61 | try { 62 | var canvas = utils.drawImgToCanvasSync(file); 63 | } 64 | catch (e) { 65 | console.log(e, file); 66 | fs.unlinkSync(file); 67 | console.log("deleted", file); 68 | } 69 | var samples = collect.extractSamples(canvas, opts.samples); 70 | 71 | for (var j = 0; j < samples.length; j++) { 72 | var fp = testSample(image, samples[j]); 73 | falsePositives += fp ? 1 : 0; 74 | } 75 | } 76 | console.log(falsePositives + " hard negatives mined"); 77 | console.timeEnd("mined in"); 78 | } 79 | 80 | function testSample(file, canvas) { 81 | var fts = features.extractFeatures(canvas, params.HOG); 82 | 83 | var result = SVM.predict([fts])[0]; 84 | 85 | if (result == 1) { 86 | console.log("false positive", file); 87 | // write this image to the directory of mined negative images 88 | var rand = Math.floor(Math.random() * 1000); 89 | var file = opts.minedDir + "/" + rand + "_" + path.basename(file); 90 | utils.writeCanvasToFileSync(canvas, file); 91 | return true; 92 | } 93 | return false; 94 | } 95 | -------------------------------------------------------------------------------- /training/svm/params.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | HOG: { 3 | cellSize: 4, 4 | blockSize: 2, 5 | blockStride: 1, 6 | bins: 7, 7 | norm: "L2" 8 | }, 9 | svm: { 10 | numpasses: 5, 11 | C: 0.001, 12 | } 13 | }; -------------------------------------------------------------------------------- /training/svm/test-svm.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"), 2 | path = require("path"), 3 | nomnom = require("nomnom"), 4 | svm = require("svm"), 5 | params = require("./params"), 6 | utils = require("../../utils"), 7 | collect = require("../collect"); 8 | 9 | var opts = nomnom.options({ 10 | pos: { 11 | abbr: 'p', 12 | list: true, 13 | required: true, 14 | help: "Directory of positive test images" 15 | }, 16 | neg: { 17 | abbr: 'n', 18 | list: true, 19 | required: true, 20 | help: "Directory of negative test images" 21 | }, 22 | jsonFile: { 23 | default: __dirname + "/svm.json", 24 | help: "SVM JSON file" 25 | }, 26 | sample: { 27 | flag: true, 28 | help: "sub-sample the negative images" 29 | } 30 | }).colors().parse(); 31 | 32 | testSVM(); 33 | 34 | 35 | function testSVM() { 36 | var json = require(opts.jsonFile) 37 | 38 | var SVM = new svm.SVM(); 39 | SVM.fromJSON(json); 40 | 41 | var data = collect.collectData(opts.pos, opts.neg, opts.sample ? 1 : 0, 42 | undefined, undefined, params); 43 | 44 | console.time("TEST") 45 | var truePos = 0, trueNeg = 0, falsePos = 0, falseNeg = 0; 46 | for (var i = 0; i < data.length; i++) { 47 | var output = data[i].output[0]; 48 | input = data[i].input; 49 | var result = SVM.predict([input])[0]; 50 | 51 | if (result == 1 && output == 1) { 52 | truePos++; 53 | } 54 | else if (result == -1 && output == 0) { 55 | trueNeg++; 56 | } 57 | else if (result == 1 && output == 0) { 58 | falsePos++; 59 | } 60 | else if (result == -1 && output == 1) { 61 | falseNeg++; 62 | } 63 | } 64 | console.timeEnd("TEST"); 65 | 66 | console.log("precision: " + truePos / (truePos + falsePos)) 67 | console.log("recall: " + truePos / (truePos + falseNeg)) 68 | 69 | console.log(truePos + " true positives"); 70 | console.log(trueNeg + " true negatives"); 71 | console.log(falsePos + " false positives"); 72 | console.log(falseNeg + " false negatives"); 73 | console.log(data.length + " total"); 74 | } 75 | -------------------------------------------------------------------------------- /training/svm/train-svm.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"), 2 | path = require("path"), 3 | nomnom = require("nomnom"), 4 | svm = require("svm"), 5 | utils = require("../../utils"), 6 | collect = require("../collect"); 7 | 8 | var opts = nomnom.options({ 9 | pos: { 10 | abbr: 'p', 11 | list: true, 12 | required: true, 13 | help: "Directory of positive training images" 14 | }, 15 | neg: { 16 | abbr: 'n', 17 | list: true, 18 | required: true, 19 | help: "Directory of negative training images" 20 | }, 21 | testPos: { 22 | list: true, 23 | help: "Directory of positive test images" 24 | }, 25 | testNeg: { 26 | list: true, 27 | help: "Directory of negative test images" 28 | }, 29 | outfile: { 30 | default: __dirname + "/svm.json", 31 | help: "file to save SVM JSON to" 32 | }, 33 | sample: { 34 | flag: true, 35 | help: "whether to sub-sample the negative images", 36 | hidden: true 37 | }, 38 | posLimit: { 39 | default: 10000, 40 | help: "maximum number of positive images to use" 41 | }, 42 | negLimit: { 43 | default: 10000, 44 | help: "maximum number of negative images to use" 45 | } 46 | }).colors().parse(); 47 | 48 | var params = { 49 | HOG: { 50 | cellSize: 4, 51 | blockSize: 2, 52 | blockStride: 1, 53 | bins: 7, 54 | norm: "L2" 55 | }, 56 | svm: { 57 | numpasses: 3, 58 | C: 0.001, 59 | kernel: 'linear' 60 | } 61 | }; 62 | 63 | trainSVM(params) 64 | 65 | function trainSVM(params) { 66 | var samples = opts.sample ? 1 : 0; 67 | var data = collect.collectData(opts.pos, opts.neg, samples, 68 | opts.posLimit, opts.negLimit, params); 69 | 70 | var inputs = []; 71 | var labels = []; 72 | 73 | for (var i = 0; i < data.length; i++) { 74 | inputs[i] = data[i].input; 75 | labels[i] = data[i].output[0] || -1; 76 | } 77 | 78 | console.log("training on", data.length); 79 | console.log("feature size", inputs[0].length); 80 | 81 | var SVM = new svm.SVM(); 82 | 83 | console.time("TRAIN"); 84 | var stats = SVM.train(inputs, labels, params.svm); 85 | console.timeEnd("TRAIN"); 86 | 87 | console.log("stats:", stats); 88 | console.log("parameters:", params); 89 | 90 | var obj = SVM.toJSON(); 91 | var json = JSON.stringify(obj, 4); 92 | 93 | fs.writeFile(opts.outfile, json, function (err) { 94 | if (err) throw err; 95 | console.log('saved svm JSON to', opts.outfile); 96 | }); 97 | 98 | testSVM(SVM); 99 | } 100 | 101 | function testSVM(SVM) { 102 | var data = collect.collectData(opts.testPos, opts.testNeg, opts.sample ? 1 : 0, 103 | undefined, undefined, params); 104 | 105 | console.time("TEST") 106 | var truePos = 0, trueNeg = 0, falsePos = 0, falseNeg = 0; 107 | for (var i = 0; i < data.length; i++) { 108 | var output = data[i].output[0]; 109 | input = data[i].input; 110 | var result = SVM.predict([input])[0]; 111 | 112 | if (result == 1 && output == 1) { 113 | truePos++; 114 | } 115 | else if (result == -1 && output == 0) { 116 | trueNeg++; 117 | } 118 | else if (result == 1 && output == 0) { 119 | falsePos++; 120 | } 121 | else if (result == -1 && output == 1) { 122 | falseNeg++; 123 | } 124 | } 125 | console.timeEnd("TEST"); 126 | 127 | console.log("precision: " + truePos / (truePos + falsePos)) 128 | console.log("recall: " + truePos / (truePos + falseNeg)) 129 | 130 | console.log(truePos + " true positives"); 131 | console.log(trueNeg + " true negatives"); 132 | console.log(falsePos + " false positives"); 133 | console.log(falseNeg + " false negatives"); 134 | console.log(data.length + " total"); 135 | } 136 | -------------------------------------------------------------------------------- /utils.js: -------------------------------------------------------------------------------- 1 | var url = require("url"), 2 | fs = require("fs"), 3 | http = require("http"), 4 | Canvas = require("canvas"); 5 | 6 | exports.dataToCanvas = function(imagedata) { 7 | img = new Canvas.Image(); 8 | img.src = new Buffer(imagedata, 'binary'); 9 | 10 | var canvas = new Canvas(img.width, img.height); 11 | var ctx = canvas.getContext('2d'); 12 | ctx.patternQuality = "best"; 13 | 14 | ctx.drawImage(img, 0, 0, img.width, img.height, 15 | 0, 0, img.width, img.height); 16 | return canvas; 17 | } 18 | 19 | exports.drawImgToCanvas = function(file, callback) { 20 | fs.readFile(file, function(err, data) { 21 | if (err) { 22 | return callback(err); 23 | } 24 | try { 25 | var canvas = exports.dataToCanvas(data); 26 | } catch(err) { 27 | return callback(err); 28 | } 29 | callback(null, canvas); 30 | }); 31 | } 32 | 33 | exports.drawImgToCanvasSync = function(file) { 34 | var data = fs.readFileSync(file); 35 | if (!data.length) { 36 | throw "empty file"; 37 | } 38 | var canvas = exports.dataToCanvas(data); 39 | return canvas; 40 | } 41 | 42 | exports.writeCanvasToFile = function(canvas, file, callback) { 43 | var buffer = canvas.toBuffer(); // png data 44 | fs.writeFile(file, buffer, callback); 45 | } 46 | 47 | exports.writeCanvasToFileSync = function(canvas, file) { 48 | var buffer = canvas.toBuffer(); // png data 49 | fs.writeFileSync(file, buffer); 50 | } 51 | 52 | exports.saveImgToFile = function(file, imagedata) { 53 | fs.writeFile(file, imagedata, 'binary', function(err) { 54 | if (err) throw err; 55 | }) 56 | } 57 | 58 | exports.resizeCanvas = function(canvas, width, height) { 59 | var resizeCanvas = new Canvas(width, height); 60 | var ctx = resizeCanvas.getContext('2d'); 61 | ctx.patternQuality = "best"; 62 | 63 | ctx.drawImage(canvas, 0, 0, canvas.width, canvas.height, 64 | 0, 0, width, height); 65 | 66 | return resizeCanvas; 67 | } 68 | --------------------------------------------------------------------------------