mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-15 12:50:04 +01:00
Updated Readme and Code Comments
This commit is contained in:
80
README.md
80
README.md
@@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
3
index.js
3
index.js
@@ -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');
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user