Restored Sequencer Module Structure

This commit is contained in:
Chinmay Pandhare
2017-06-18 12:03:18 +05:30
parent f13da0fb19
commit ba4863c201
8 changed files with 104 additions and 77 deletions

View File

@@ -21,45 +21,60 @@ It is also for prototyping some other related ideas:
* cascading changes -- change an earlier step's settings, and see those changes affect later steps * cascading changes -- change an earlier step's settings, and see those changes affect later steps
* "small modules"-based extensibility: see [Contributing](#contributing), below * "small modules"-based extensibility: see [Contributing](#contributing), below
## Usage ## Examples:
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: ## Using the library:
### Initializing the Sequencer
The Image Sequencer Library exports a function ImageSequencer which initializes a sequencer. The Image Sequencer Library exports a function ImageSequencer which initializes a sequencer.
```js ```js
var sequencer = ImageSequencer(); var sequencer = ImageSequencer();
``` ```
### Loading Images into the Sequencer
Image Sequencer has an array of images which gets stored in `sequencer.images` in this case. 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`. Images can be loaded into this array by the method `loadImages`.
loadImages accepts 1, 2, or 3 parameters. loadImages accepts 1, 2, or 3 parameters.
3/2 parameters :
```js * 3/2 parameters :
sequencer.loadImages(image_name,image_src,optional_callback); ```js
``` sequencer.loadImages(image_name,
1/2 parameters (JSON) : image_src,optional_callback);
```js ```
sequencer.loadImages({ * 1/2 parameters (JSON) :
image_name_1: image_src, ```js
image_name_2: image_src, sequencer.loadImages({
... image_name_1: image_src,
}, optional_callback); image_name_2: image_src,
``` ...
}, optional_callback);
```
### Adding Steps on Images
After loading the image, we can add modules to the image using the addSteps method. 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. 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. In all the following examples, `image_name` and `module_name` may be a string or an array of strings.
```js ```js
sequencer.addSteps(image_name,module_name,optional_options); sequencer.addSteps(image_name,module_name,optional_options);
``` ```
If no Image Name is specified, the module is added to **all** images. If no Image Name is specified, the module is added to **all** images.
```js ```js
sequencer.addSteps(module_name,optional_options); sequencer.addSteps(module_name,optional_options);
``` ```
All this can be passed in as JSON: All this can be passed in as JSON:
```js ```js
sequencer.addSteps({ sequencer.addSteps({
image_name: {name: module_name, o: optional_options}, image_name: {name: module_name, o: optional_options},
@@ -68,26 +83,36 @@ sequencer.addSteps({
}); });
``` ```
### Running the Sequencer
After adding the steps, now we must generate output for each of the step via the `run` method. 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. 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 ```js
sequencer.run(); //All images from first step sequencer.run(); //All images from first step
``` ```
```js ```js
sequencer.run(image,from); //Image 'image' from 'from' sequencer.run(image,from); //Image 'image' from 'from'
``` ```
image may either be an array or a string. image may either be an array or a string.
An optional callback may also be passed. An optional callback may also be passed.
### Removing Steps from an Image
Steps can be removed using the `removeSteps` method. It accepts `image` and `index` as parameters. 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. Either, both, or none of them can be an array. JSON input is also accepted.
```js ```js
sequencer.removeSteps("image",[steps]); sequencer.removeSteps("image",[steps]);
``` ```
```js ```js
sequencer.removeSteps("image",step); sequencer.removeSteps("image",step);
``` ```
```js ```js
sequencer.removeSteps({ sequencer.removeSteps({
image: [steps], image: [steps],
@@ -96,6 +121,8 @@ sequencer.removeSteps({
}); });
``` ```
### Inserting steps on an image
Steps can be inserted using the `insertSteps` method. It accepts `image`, `index`, `module_name` and `optional_options` as parameters. `image` may be an array. `optional_options` is an object. The rest are literals. JSON Input is supported too. If no image is provided, Steps will be inserted on all images. Indexes can be negative. Negative sign with an index means that counting will be done in reverse order. If the index is out of bounds, the counting will wrap in the original direction of counting. Steps can be inserted using the `insertSteps` method. It accepts `image`, `index`, `module_name` and `optional_options` as parameters. `image` may be an array. `optional_options` is an object. The rest are literals. JSON Input is supported too. If no image is provided, Steps will be inserted on all images. Indexes can be negative. Negative sign with an index means that counting will be done in reverse order. If the index is out of bounds, the counting will wrap in the original direction of counting.
```js ```js
sequencer.insertSteps("image",index,"module_name",o); sequencer.insertSteps("image",index,"module_name",o);
@@ -126,19 +153,28 @@ Most contribution (we imagine) would be in the form of API-compatible modules, w
To add a module to Image Sequencer, it must have the following method; you can wrap an existing module to add them: To add a module to Image Sequencer, it must have the following method; you can wrap an existing module to add them:
* `module.draw(image)` * `module.draw()`
The `draw()` method should accept an `image` parameter, which will be a native JavaScript image object (i.e. `new Image()`). The `draw(input,callback)` method should accept an `input` parameter, which will be an object of the form:
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: ```js
input = {
src: "datauri here",
format: "jpeg/png/etc"
}
```
The `image` object is essentially the output of the previous step.
The draw method must, when it is complete, pass the output image to the method `this.output = modified_input`, which will send the output to the next module in the chain. For example:
```js ```js
function draw(image) { function draw(image) {
// do some stuff with the image // do some stuff with the image
options.output(image); this.output = image;
callback();
} }
``` ```

View File

@@ -2,10 +2,10 @@ 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','do-nothing']); sequencer.addSteps(['do-nothing','do-nothing-pix','do-nothing-pix','ndvi-red']);
sequencer.run();
sequencer.removeSteps(1); sequencer.removeSteps(1);
sequencer.insertSteps({ sequencer.insertSteps({
red: [{index: -1, name: 'do-nothing', o:{}}] red: [{index: -1, name: 'do-nothing', o:{}}]
}); });
sequencer.run();
}); });

View File

@@ -58,9 +58,10 @@ ImageSequencer = function ImageSequencer(options) {
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].call(this.images,o);
images[image].steps.push(module); images[image].steps.push(module);
function defaultSetupModule() { function defaultSetupModule() {
if (options.ui && options.ui!="none") module.options.ui = options.ui({ if (options.ui && options.ui!="none") module.options.ui = options.ui({
selector: o.selector, selector: o.selector,
@@ -160,7 +161,7 @@ ImageSequencer = function ImageSequencer(options) {
for (i in indices) for (i in indices)
removeStep(img,indices[i]); removeStep(img,indices[i]);
} }
this.run(run) // this.run(run); // This is creating problems
} }
function insertStep(image, index, name, o) { function insertStep(image, index, name, o) {
@@ -242,28 +243,25 @@ ImageSequencer = function ImageSequencer(options) {
} // end if argument is object } // end if argument is object
} }
this.run(run) // this.run(run); // This is Creating issues
} }
function run(t_image,t_from) { function run(t_image,t_from) {
log('\x1b[32m%s\x1b[0m',"Running the Sequencer!"); log('\x1b[32m%s\x1b[0m',"Running the Sequencer!");
this_ = this; this_ = this;
runimg = {};
json_q = {}; json_q = {};
args = []; args = [];
for (var arg in arguments) args.push(copy(arguments[arg])); for (var arg in arguments) args.push(copy(arguments[arg]));
for (var arg in args) for (var arg in args)
if(objTypeOf(args[arg]) == "Function") if(objTypeOf(args[arg]) == "Function")
var callback = args.splice(arg,1)[0]; var callback = args.splice(arg,1)[0];
for (image in images) {
runimg[image] = 0;
}
function drawStep(drawarray,pos) { function drawStep(drawarray,pos) {
if(pos==drawarray.length) if(objTypeOf(callback)=='Function') callback(); 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;
images[image].steps[i].draw.call(this_,function(){ input = images[image].steps[i-1].output;
images[image].steps[i].draw(copy(input),function(){
drawStep(drawarray,++pos); drawStep(drawarray,++pos);
}); });
} }
@@ -279,6 +277,11 @@ ImageSequencer = function ImageSequencer(options) {
drawStep(drawarray,0); drawStep(drawarray,0);
} }
function filter(json_q){ function filter(json_q){
for (image in json_q) {
if (json_q[image]==0 && this_.images[image].steps.length==1)
delete json_q[image];
else json_q[image]++;
}
for (image in json_q) { for (image in json_q) {
prevstep = images[image].steps[json_q[image]-1]; prevstep = images[image].steps[json_q[image]-1];
while (typeof(prevstep) == "undefined" || typeof(prevstep.output) == "undefined") { while (typeof(prevstep) == "undefined" || typeof(prevstep.output) == "undefined") {

View File

@@ -4,26 +4,17 @@
module.exports = function DoNothing(options) { module.exports = function DoNothing(options) {
options = options || {}; options = options || {};
options.title = "Do Nothing"; options.title = "Do Nothing";
this_ = this;
var output
var image; function draw(input,callback) {
var output; this.output = input;
function draw(callback) {
step = require('./_Step')(this,options);
newdata = step[0];
pos = step[1];
thisimage.steps[pos].output = {src:newdata.src,format:newdata.format};
callback(); callback();
} }
function get() {
return image;
}
return { return {
options: options, options: options,
draw: draw, draw: draw,
get: get,
output: output output: output
} }
} }

View File

@@ -6,23 +6,22 @@ module.exports = function GreenChannel(options) {
options = options || {}; options = options || {};
options.title = "Green channel only"; options.title = "Green channel only";
options.description = "Displays only the green channel of an image"; options.description = "Displays only the green channel of an image";
var output;
//function setup() {} // optional //function setup() {} // optional
function draw(callback) { function draw(input,callback) {
step = require('./_Step')(this,options); this_ = this;
newdata = step[0];
pos = step[1];
function changePixel(r, g, b, a) { function changePixel(r, g, b, a) {
return [r, g, b, a]; return [r, g, b, a];
} }
function output(image,datauri,mimetype){ function output(image,datauri,mimetype){
images[image].steps[pos].output = {src:datauri,format:mimetype} this_.output = {src:datauri,format:mimetype}
} }
return require('./PixelManipulation.js')(newdata, { return require('./PixelManipulation.js')(input, {
output: output, output: output,
changePixel: changePixel, changePixel: changePixel,
format: newdata.format, format: input.format,
image: options.image, image: options.image,
callback: callback callback: callback
}); });
@@ -31,6 +30,7 @@ module.exports = function GreenChannel(options) {
return { return {
options: options, options: options,
//setup: setup, // optional //setup: setup, // optional
draw: draw draw: draw,
output: output
} }
} }

View File

@@ -6,23 +6,22 @@ module.exports = function GreenChannel(options) {
options = options || {}; options = options || {};
options.title = "Green channel only"; options.title = "Green channel only";
options.description = "Displays only the green channel of an image"; options.description = "Displays only the green channel of an image";
var output;
//function setup() {} // optional //function setup() {} // optional
function draw(callback) { function draw(input,callback) {
step = require('./_Step')(this,options); this_ = this;
newdata = step[0];
pos = step[1];
function changePixel(r, g, b, a) { function changePixel(r, g, b, a) {
return [0, g, 0, a]; return [0, g, 0, a];
} }
function output(image,datauri,mimetype){ function output(image,datauri,mimetype){
images[image].steps[pos].output = {src:datauri,format:mimetype} this_.output = {src:datauri,format:mimetype}
} }
return require('./PixelManipulation.js')(newdata, { return require('./PixelManipulation.js')(input, {
output: output, output: output,
changePixel: changePixel, changePixel: changePixel,
format: newdata.format, format: input.format,
image: options.image, image: options.image,
callback: callback callback: callback
}); });
@@ -31,6 +30,7 @@ module.exports = function GreenChannel(options) {
return { return {
options: options, options: options,
//setup: setup, // optional //setup: setup, // optional
draw: draw draw: draw,
output: output
} }
} }

View File

@@ -5,24 +5,23 @@ module.exports = function NdviRed(options) {
options = options || {}; options = options || {};
options.title = "NDVI for red-filtered cameras (blue is infrared)"; options.title = "NDVI for red-filtered cameras (blue is infrared)";
var output;
//function setup() {} // optional //function setup() {} // optional
function draw(callback) { function draw(input,callback) {
step = require('./_Step')(this,options); this_ = this;
newdata = step[0];
pos = step[1];
function changePixel(r, g, b, a) { function changePixel(r, g, b, a) {
var ndvi = 255 * (b - r) / (1.00 * b + r); var ndvi = 255 * (b - r) / (1.00 * b + r);
return [ndvi, ndvi, ndvi, a]; return [ndvi, ndvi, ndvi, a];
} }
function output(image,datauri,mimetype){ function output(image,datauri,mimetype){
images[image].steps[pos].output = {src:datauri,format:mimetype} this_.output = {src:datauri,format:mimetype}
} }
return require('./PixelManipulation.js')(newdata, { return require('./PixelManipulation.js')(input, {
output: output, output: output,
changePixel: changePixel, changePixel: changePixel,
format: newdata.format, format: input.format,
image: options.image, image: options.image,
callback: callback callback: callback
}); });

View File

@@ -1,11 +1,9 @@
module.exports = function(ref,options) { module.exports = function(ref,image,pos) {
images = ref.images; images = ref.images;
thisimage = images[options.image]; thisimage = images[image];
for (i in thisimage.steps){ var thisstep = thisimage[pos];
if (thisimage.steps[i].options.id == options.id) pos = i; console.log(thisstep);
return function(img) {
thisstep.output = img;
} }
olddata = thisimage.steps[pos-1].output;
if (typeof(olddata) == 'undefined') return false;
var newdata = JSON.parse(JSON.stringify(olddata));
return [newdata,pos];
} }