Skip to content

Commit 0dc3682

Browse files
committed
Added benchmarks, cleanup
1 parent e1378ea commit 0dc3682

8 files changed

+121
-30
lines changed

.npmignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
node_modules
2+
examples
3+
*.jpg
4+
*.html
5+
.500px-consumer-key
6+
my_*
7+
doc
8+
bower.json
9+
Gruntfile.js

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,11 @@ The API is not yet finalized. Look at the code and expect changes.
5757
You can run the tests using grunt test. Alternatively you can also just run grunt (the default task) and open http://localhost:8000/test/.
5858
The test coverage for smartcrop.js is very limited at the moment. I expect to improve this as the code matures and the concepts solidify.
5959

60+
## Benchmark
61+
There are benchmarks for both the browser (test/benchmark.html) and node (node test/benchmark-node.js [requires node-canvas])
62+
both powered by [benchmark.js](http://benchmarkjs.com).
63+
64+
If you just want some rough numbers: It takes < 100 ms to find a square crop of a 640x427 picture on an i7.
65+
6066
## License
6167
Copyright (c) 2014 Jonas Wanger, licensed under the MIT License (enclosed)

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"grunt-rsync": "~0.5.0",
1313
"grunt": "^0.4.4",
1414
"mocha": "^1.18.2",
15-
"chai": "^1.9.1"
15+
"chai": "^1.9.1",
16+
"benchmark": "~1.0.0"
1617
},
1718
"license": "MIT",
1819
"repository": {

smartcrop.js

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -127,40 +127,22 @@ SmartCrop.prototype = {
127127
c.height = h;
128128
return c;
129129
},
130-
saturation: function(r, g, b){
131-
var maximum = max(r/255, g/255, b/255), minumum = min(r/255, g/255, b/255);
132-
if(maximum === minumum){
133-
return 0;
134-
}
135-
var l = (maximum + minumum) / 2,
136-
d = maximum-minumum;
137-
return l > 0.5 ? d/(2-maximum-minumum) : d/(maximum+minumum);
138-
},
139-
cie: function(r, g, b){
140-
return 0.5126*b + 0.7152*g + 0.0722*r;
141-
},
142130
edgeDetect: function(i, o){
143131
var id = i.data,
144132
od = o.data,
145133
w = i.width,
146-
h = i.height,
147-
cie = this.cie;
148-
function sample(p) {
149-
return cie(id[p], id[p+1], id[p+2]);
150-
}
134+
h = i.height;
151135
for(var y = 0; y < h; y++) {
152136
for(var x = 0; x < w; x++) {
153137
var p = (y*w+x)*4,
154138
lightness;
155139
if(x === 0 || x >= w-1 || y === 0 || y >= h-1){
156-
lightness = sample(p);
140+
lightness = sample(id, p);
157141
}
158142
else {
159-
lightness = sample(p)*4 - sample(p-w*4) - sample(p-4) - sample(p+4) - sample(p+w*4);
143+
lightness = sample(id, p)*4 - sample(id, p-w*4) - sample(id, p-4) - sample(id, p+4) - sample(id, p+w*4);
160144
}
161-
od[p] = lightness;
162145
od[p+1] = lightness;
163-
od[p+2] = lightness;
164146
}
165147
}
166148
},
@@ -173,7 +155,7 @@ SmartCrop.prototype = {
173155
for(var y = 0; y < h; y++) {
174156
for(var x = 0; x < w; x++) {
175157
var p = (y*w+x)*4,
176-
lightness = this.cie(id[p], id[p+1], id[p+2])/255,
158+
lightness = cie(id[p], id[p+1], id[p+2])/255,
177159
skin = this.skinColor(id[p], id[p+1], id[p+2]);
178160
if(skin > options.skinThreshold && lightness >= options.skinBrightnessMin && lightness <= options.skinBrightnessMax){
179161
od[p] = (skin-options.skinThreshold)*(255/(1-options.skinThreshold));
@@ -195,10 +177,10 @@ SmartCrop.prototype = {
195177
for(var y = 0; y < h; y++) {
196178
for(var x = 0; x < w; x++) {
197179
var p = (y*w+x)*4,
198-
lightness = this.cie(id[p], id[p+1], id[p+2])/255,
199-
saturation = this.saturation(id[p], id[p+1], id[p+2]);
200-
if(saturation > options.saturationThreshold && lightness >= options.saturationBrightnessMin && lightness <= options.saturationBrightnessMax){
201-
od[p+2] = (saturation-options.saturationThreshold)*(255/(1-options.saturationThreshold));
180+
lightness = cie(id[p], id[p+1], id[p+2])/255,
181+
sat = saturation(id[p], id[p+1], id[p+2]);
182+
if(sat > options.saturationThreshold && lightness >= options.saturationBrightnessMin && lightness <= options.saturationBrightnessMax){
183+
od[p+2] = (sat-options.saturationThreshold)*(255/(1-options.saturationThreshold));
202184
}
203185
else {
204186
od[p+2] = 0;
@@ -393,9 +375,7 @@ function extend(o){
393375
var arg = arguments[i];
394376
if(arg){
395377
for(var name in arg){
396-
if(arg.hasOwnProperty(name)){
397-
o[name] = arg[name];
398-
}
378+
o[name] = arg[name];
399379
}
400380
}
401381
}
@@ -409,6 +389,24 @@ function thirds(x){
409389
return Math.max(1.0-x*x, 0.0);
410390
}
411391

392+
function cie(r, g, b){
393+
return 0.5126*b + 0.7152*g + 0.0722*r;
394+
}
395+
function sample(id, p) {
396+
return cie(id[p], id[p+1], id[p+2]);
397+
}
398+
function saturation(r, g, b){
399+
var maximum = max(r/255, g/255, b/255), minumum = min(r/255, g/255, b/255);
400+
if(maximum === minumum){
401+
return 0;
402+
}
403+
var l = (maximum + minumum) / 2,
404+
d = maximum-minumum;
405+
return l > 0.5 ? d/(2-maximum-minumum) : d/(maximum+minumum);
406+
}
407+
408+
409+
412410

413411

414412

test/benchmark-node.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// npm install microtime canvas
2+
// then run from base directory:
3+
// node test/benchmark-node.js
4+
//
5+
var Benchmark = require('benchmark'),
6+
fs = require('fs'),
7+
Canvas = require('canvas'),
8+
SmartCrop = require('../smartcrop');
9+
10+
var img = new Canvas.Image();
11+
img.src = fs.readFileSync('examples/images/flickr/kitty.jpg');
12+
function canvasFactory(w, h){ return new Canvas(w, h); }
13+
var benchmark = new Benchmark('SmartCrop.crop()', function(deferred){
14+
SmartCrop.crop(img, {width: 256, height: 256, canvasFactory: canvasFactory}, function(){
15+
deferred.resolve();
16+
});
17+
}, {
18+
defer: true,
19+
maxTime: 30,
20+
onCycle: function(){
21+
console.log(benchmark.toString());
22+
console.log((1/(benchmark.stats.mean+benchmark.stats.moe)).toFixed(2));
23+
console.log(benchmark.stats.mean.toFixed(3));
24+
},
25+
onComplete: function(){
26+
//console.log(benchmark.stats);
27+
console.log((1/(benchmark.stats.mean+benchmark.stats.moe)).toFixed(2));
28+
console.log((1/(benchmark.stats.mean)).toFixed(2));
29+
console.log(benchmark.stats.mean);
30+
console.log(benchmark.toString());
31+
}
32+
}).run();

test/benchmark.html

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<html>
2+
<head>
3+
<meta charset="utf-8">
4+
<title>smartcrop.js benchmark</title>
5+
</head>
6+
<body>
7+
<h1>smartcrop.js benchmark</h1>
8+
<div id=status></div>
9+
<pre id=raw>Running</pre>
10+
<script src="../node_modules/benchmark/benchmark.js"></script>
11+
<script src="../smartcrop.js"></script>
12+
<script src="../examples/jquery.js"></script>
13+
<script src="benchmark.js"></script>
14+
</body>
15+
</html>

test/benchmark.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
(function(){
2+
var KITTY = '/examples/images/flickr/kitty.jpg',
3+
raw = $('#raw'),
4+
status = $('#status');
5+
6+
var benchmark = new Benchmark('SmartCrop.crop()', function(deferred){
7+
SmartCrop.crop(img, {width: 256, height: 256}, function(){
8+
deferred.resolve();
9+
});
10+
}, {
11+
defer: true,
12+
maxTime: 30,
13+
onCycle: function(){
14+
status.text(benchmark.toString());
15+
},
16+
onComplete: function(){
17+
console.log('complete', arguments);
18+
status.text(benchmark.toString());
19+
raw.text(JSON.stringify(benchmark.stats, null, ' '));
20+
}
21+
}),
22+
img = new Image();
23+
// add tests
24+
img.src = KITTY;
25+
img.onload = function(){
26+
benchmark.run({ 'async': true });
27+
};
28+
29+
})();

test/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<script src="../node_modules/mocha/mocha.js"></script>
1010
<script src="../node_modules/chai/chai.js"></script>
1111
<script src="../smartcrop.js"></script>
12+
1213
<script>
1314
mocha.setup('bdd')
1415
window.expect = chai.expect;

0 commit comments

Comments
 (0)