Updated Readme and Code Comments

This commit is contained in:
Chinmay Pandhare
2017-06-16 11:02:23 +05:30
parent 65cc3585dc
commit 1b67d52a96
4 changed files with 182 additions and 64 deletions

View File

@@ -7,7 +7,7 @@ aka "Consequencer"
## Why ## Why
Image Sequencer is different from other image processing systems in that it's non-destructive: instead of modifying the original image, it creates a new image at each step in a sequence. This is because it: Image Sequencer is different from other image processing systems in that it's non-destructive: instead of modifying the original image, it creates a new image at each step in a sequence. This is because it:
* produces a legible trail of operations, to "show your work" for evidential, educational, or reproducibility reasons * produces a legible trail of operations, to "show your work" for evidential, educational, or reproducibility reasons
* makes the creation of new tools or "modules" simpler -- each must accept an input image, and produce an output image * makes the creation of new tools or "modules" simpler -- each must accept an input image, and produce an output image
@@ -28,9 +28,78 @@ Examples:
* [Basic example](https://jywarren.github.io/image-sequencer/) * [Basic example](https://jywarren.github.io/image-sequencer/)
* [NDVI example](https://jywarren.github.io/image-sequencer/examples/ndvi/) - related to [Infragram.org](http://infragram.org) * [NDVI example](https://jywarren.github.io/image-sequencer/examples/ndvi/) - related to [Infragram.org](http://infragram.org)
Using the library:
The Image Sequencer Library exports a function ImageSequencer which initializes a sequencer.
```js
var sequencer = ImageSequencer();
```
Image Sequencer has an array of images which gets stored in `sequencer.images` in this case.
Images can be loaded into this array by the method `loadImages`.
loadImages accepts 1, 2, or 3 parameters.
3/2 parameters :
```js
sequencer.loadImages(image_name,image_src,optional_callback);
```
1/2 parameters (JSON) :
```js
sequencer.loadImages({
image_name_1: image_src,
image_name_2: image_src,
...
}, optional_callback);
```
After loading the image, we can add modules to the image using the addSteps method.
The options argument (object) is an optional parameter to pass in arguments to the module.
In all the following examples, `image_name` and `module_name` may be a string or an array of strings.
```js
sequencer.addSteps(image_name,module_name,optional_options);
```
If no Image Name is specified, the module is added to **all** images.
```js
sequencer.addSteps(module_name,optional_options);
```
All this can be passed in as JSON:
```js
sequencer.addSteps({
image_name: {name: module_name, o: optional_options},
image_name: {name: module_name, o: optional_options},
...
});
```
After adding the steps, now we must generate output for each of the step via the `run` method.
The `run` method accepts parameters `image` and `from`. `from` is the index from where the function starts generating output. By default, it will run across all the steps. (from = 1) If no image is specified, the sequencer will be run over all the images.
```js
sequencer.run(); //All images from first step
```
```js
sequencer.run(image,from); //Image 'image' from 'from'
```
image may either be an array or a string.
An optional callback may also be passed.
Steps can be removed using the `removeSteps` method. It accepts `image` and `index` as parameters.
Either, both, or none of them can be an array. JSON input is also accepted. This method automatically triggers the `run` method as a callback.
```js
sequencer.removeSteps("image",[steps]);
```
```js
sequencer.removeSteps("image",step);
```
```js
sequencer.removeSteps({
image: [steps],
image: [steps],
...
});
```
## Contributing ## Contributing
Happily accepting pull requests; to edit the core library, modify files in `/src/`. To build, run `npm install` and `grunt build`. Happily accepting pull requests; to edit the core library, modify files in `/src/`. To build, run `npm install` and `grunt build`.
### Contributing modules ### Contributing modules
@@ -42,7 +111,7 @@ To add a module to Image Sequencer, it must have the following method; you can w
* `module.draw(image)` * `module.draw(image)`
The `draw()` method should accept an `image` parameter, which will be a native JavaScript image object (i.e. `new Image()`). The `draw()` method should accept an `image` parameter, which will be a native JavaScript image object (i.e. `new Image()`).
The draw method must, when it is complete, pass the output image to the method `options.output(image)`, which will send the output to the next module in the chain. For example: The draw method must, when it is complete, pass the output image to the method `options.output(image)`, which will send the output to the next module in the chain. For example:
@@ -220,8 +289,3 @@ Possible web-based commandline interface: https://hyper.is/?
* vectorize * vectorize
* edge detect * edge detect
* direction find (vectorize and colorize) * direction find (vectorize and colorize)

View File

@@ -2,7 +2,8 @@ console.log('\x1b[31m%s\x1b[0m',"This is the output of the module");
require('./src/ImageSequencer'); require('./src/ImageSequencer');
sequencer = ImageSequencer(); sequencer = ImageSequencer();
sequencer.loadImages({red:'examples/red.jpg'},function(){ sequencer.loadImages({red:'examples/red.jpg'},function(){
sequencer.addSteps(['do-nothing','do-nothing-pix','do-nothing']); sequencer.addSteps(['do-nothing','do-nothing-pix','do-nothing','do-nothing']);
sequencer.addSteps(['do-nothing','do-nothing-pix','do-nothing','do-nothing']);
sequencer.run(); sequencer.run();
sequencer.removeSteps(1); sequencer.removeSteps(1);
sequencer.insertSteps(1,'do-nothing'); sequencer.insertSteps(1,'do-nothing');

View File

@@ -28,6 +28,17 @@ ImageSequencer = function ImageSequencer(options) {
} }
} }
function copy(a) {
if (!typeof(a) == "object") return a;
if (objTypeOf(a) == "Array") return a.slice();
if (objTypeOf(a) == "Object") return JSON.parse(JSON.stringify(a));
return a;
}
function makeArray(input) {
return (objTypeOf(input)=="Array")?input:[input];
}
var image, var image,
steps = [], steps = [],
modules = require('./Modules'), modules = require('./Modules'),
@@ -37,14 +48,14 @@ ImageSequencer = function ImageSequencer(options) {
// if (options.imageSelect || options.inBrowser) addStep('image-select'); // if (options.imageSelect || options.inBrowser) addStep('image-select');
// else if (options.imageUrl) loadImage(imageUrl); // else if (options.imageUrl) loadImage(imageUrl);
function addStep(image, name, o) { function addStep(image, name, o_) {
log('\x1b[36m%s\x1b[0m','adding step \"' + name + '\" to \"' + image + '\".'); log('\x1b[36m%s\x1b[0m','adding step \"' + name + '\" to \"' + image + '\".');
o = o || {}; o = {};
o.id = options.sequencerCounter++; //Gives a Unique ID to each step o.id = options.sequencerCounter++; //Gives a Unique ID to each step
o.name = o.name || name; o.name = o_.name || name;
o.selector = o.selector || 'ismod-' + name; o.selector = o_.selector || 'ismod-' + name;
o.container = o.container || options.selector; o.container = o_.container || options.selector;
o.image = image; o.image = image;
var module = modules[name](o); var module = modules[name](o);
@@ -61,38 +72,52 @@ ImageSequencer = function ImageSequencer(options) {
else defaultSetupModule.apply(module); // run default setup() in scope of module (is this right?) else defaultSetupModule.apply(module); // run default setup() in scope of module (is this right?)
// tell the UI that a step has been added. // tell the UI that a step has been added.
return true; return true;
} }
function addSteps(){ function addSteps(){
argtype = []; args = [];
json_q = {}; json_q = {};
for (i in images) { for (i in images) {
lastimage = i; lastimage = i;
} }
for (var arg in arguments) { for (var arg in arguments) {
argtype.push(objTypeOf(arguments[arg])); args.push(copy(arguments[arg]));
} }
if (arguments.length == 1) { if (args.length == 1) {
if(argtype[0] == "Object") if(objTypeOf(args[0]) == "Object") //addSteps(JSON)
json_q = arguments[0]; json_q = arguments[0];
else else { //addSteps(name) => addSteps([image],[name])
for (i in images) args.splice(0,0,[]);
json_q[i] = (argtype[0]=="Array")?arguments[0]:[arguments[0]]; for (img in images) args[0].push(img);
}
} }
else if (arguments.length == 2) { if (args.length == 2) {
if(argtype[1]=="String") arguments[1] = [arguments[1]]; //addSteps(name,o) => addSteps([image],[name],o)
if(argtype[0]=="String") if (objTypeOf(args[1])=="Object") {
json_q[arguments[0]] = arguments[1]; args.splice(0,0,[]);
else if(argtype[0]=="Array") for (img in images) args[0].push(img);
for (var i in arguments[0]) { }
json_q[arguments[0][i]] = arguments[1]; else { //addSteps(image,name) => addSteps([image],[name],o)
args[2] = {};
}
}
if (args.length == 3) { //addSteps(image,name,o) => addSteps(JSON)
args[0] = makeArray(args[0]);
args[1] = makeArray(args[1]);
for (img in args[0]) {
json_q[args[0][img]] = [];
for (step in args[1]) {
json_q[args[0][img]].push({
name: args[1][step],
o: args[2]
});
} }
}
} }
for (i in json_q) for (i in json_q)
for (j in json_q[i]) for (j in json_q[i])
addStep.call(this,i,json_q[i][j]); addStep.call(this,i,json_q[i][j].name,json_q[i][j].o);
} }
@@ -109,32 +134,32 @@ ImageSequencer = function ImageSequencer(options) {
function removeSteps(image,index) { function removeSteps(image,index) {
run = {}; run = {};
this_ = this; this_ = this;
args = [];
for(var arg in arguments) args.push(copy(arguments[arg]));
json_q = {};
if(arguments.length==2) { if(args.length==1) {
removeStep(image,index); if (objTypeOf(args[0])=="Object") { //removeSteps(JSON)
run[image] = index; json_q = args[0];
} }
else if(arguments.length==1) { else { //removeSteps(index) => removeSteps([image],[index])
if (typeof(arguments[0])=="number" || objTypeOf(arguments[0])=="Array") { args.splice(0,0,[]);
indx = arguments[0]; for(img in images) args[0].push(img);
arguments[0] = {};
for (img in this_.images) arguments[0][img] = indx;
} }
if (objTypeOf(arguments[0])=='Object') {
for (img in arguments[0]) {
var indexes = arguments[0][img];
if (typeof(indexes) == "number")
{removeStep(img,indexes); run[img]=indexes;}
else if (objTypeOf(indexes) == "Array") {
indexes = indexes.sort(function(a,b){return b-a});
run[img] = indexes[indexes.length-1];
for (i in indexes)
removeStep(img,indexes[i]);
}
}
} // end if argument is object
} }
if(args.length==2) { //removeSteps(image,index) => removeSteps(JSON)
args[0] = makeArray(args[0]);
args[1] = makeArray(args[1]);
for(img in args[0]) {
json_q[args[0][img]] = args[1];
}
}
for (img in json_q) {
indices = json_q[img].sort(function(a,b){return b-a});
run[img] = indices[indices.length-1];
for (i in indices)
removeStep(img,indices[i]);
}
this.run(run) this.run(run)
} }
@@ -229,10 +254,16 @@ ImageSequencer = function ImageSequencer(options) {
this_ = this; this_ = this;
runimg = {}; runimg = {};
json_q = {}; json_q = {};
args = [];
for (var arg in arguments) args.push(copy(arguments[arg]));
for (var arg in args)
if(objTypeOf(args[arg]) == "Function")
var callback = args.splice(arg,1)[0];
for (image in images) { for (image in images) {
runimg[image] = 0; runimg[image] = 0;
} }
function drawStep(drawarray,pos) { function drawStep(drawarray,pos) {
if(pos==drawarray.length) if(objTypeOf(callback)=='Function') callback();
if(pos>=drawarray.length) return true; if(pos>=drawarray.length) return true;
image = drawarray[pos].image; image = drawarray[pos].image;
i = drawarray[pos].i; i = drawarray[pos].i;

View File

@@ -29,30 +29,52 @@ test('loadImages loads a step', function (t){
t.end(); t.end();
}); });
test('addStep adds a step', function (t) { test('addSteps("image","name") adds a step', function (t) {
sequencer.addSteps('test','do-nothing'); sequencer.addSteps('test','do-nothing');
t.equal(sequencer.images.test.steps[1].options.name, "do-nothing"); t.equal(sequencer.images.test.steps[1].options.name, "do-nothing");
t.equal(sequencer.images.test.steps.length, 2, "It Does!") t.equal(sequencer.images.test.steps.length, 2, "It Does!")
t.end(); t.end();
}); });
test('addSteps("name") adds a step', function (t) {
sequencer.addSteps('do-nothing');
t.equal(sequencer.images.test.steps[2].options.name, "do-nothing");
t.equal(sequencer.images.test.steps.length, 3, "It Does!")
t.end();
});
test('addSteps(["name"]) adds a step', function (t) {
sequencer.addSteps(['do-nothing','do-nothing-pix']);
t.equal(sequencer.images.test.steps[3].options.name, "do-nothing");
t.equal(sequencer.images.test.steps[4].options.name, "do-nothing-pix");
t.equal(sequencer.images.test.steps.length, 5, "It Does!")
t.end();
});
test('addSteps("name",o) adds a step', function (t) {
sequencer.addSteps('do-nothing',{});
t.equal(sequencer.images.test.steps[5].options.name, "do-nothing");
t.equal(sequencer.images.test.steps.length, 6, "It Does!")
t.end();
});
test('addSteps("image","name",o) adds a step', function (t) {
sequencer.addSteps('test','do-nothing',{});
t.equal(sequencer.images.test.steps[6].options.name, "do-nothing");
t.equal(sequencer.images.test.steps.length, 7, "It Does!")
t.end();
});
test('removeSteps removes a step', function (t) { test('removeSteps removes a step', function (t) {
sequencer.removeSteps('test',1); sequencer.removeSteps('test',1);
t.equal(sequencer.images.test.steps.length, 1, "It Does!"); t.equal(sequencer.images.test.steps.length, 6, "It Does!");
t.end(); t.end();
}); });
test('insertStep inserts a step', function (t) { test('insertStep inserts a step', function (t) {
sequencer.insertSteps('test',1,'do-nothing'); sequencer.insertSteps('test',1,'do-nothing');
t.equal(sequencer.images.test.steps[1].options.name, "do-nothing"); t.equal(sequencer.images.test.steps[1].options.name, "do-nothing");
t.equal(sequencer.images.test.steps.length, 2, "It Does!"); t.equal(sequencer.images.test.steps.length, 7, "It Does!");
t.end();
});
test('run creates output of steps', function (t) {
sequencer.run();
var steps = sequencer.images.test.steps
var type = typeof(steps[steps.length-1].output)
t.equal(type,"object");
t.end(); t.end();
}); });