mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-08 09:20:10 +01:00
Compare commits
5 Commits
ndvi-expla
...
v1.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d887f5eb61 | ||
|
|
3b791ad58b | ||
|
|
fba80bb151 | ||
|
|
0ceb36ffde | ||
|
|
edaa8895c7 |
@@ -31,17 +31,64 @@ Any module must follow this basic format:
|
||||
|
||||
```js
|
||||
module.exports = function ModuleName(options,UI) {
|
||||
|
||||
options = options || {};
|
||||
options.title = "Title of the Module";
|
||||
UI.onSetup(options.step);
|
||||
var output;
|
||||
|
||||
function draw(input,callback) {
|
||||
|
||||
UI.onDraw(options.step);
|
||||
|
||||
var output = /*do something with the input*/ ;
|
||||
var output = function(input){
|
||||
/* do something with the input */
|
||||
return input;
|
||||
}
|
||||
|
||||
this.output = output;
|
||||
this.output = output(input);
|
||||
options.step.output = output.src;
|
||||
callback();
|
||||
UI.onComplete(options.step);
|
||||
}
|
||||
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
```
|
||||
The default loading spinner can be optionally overriden with a custom progress object to draw progress on the CLI, following is a basic module format for the same
|
||||
|
||||
```js
|
||||
module.exports = function ModuleName(options,UI) {
|
||||
|
||||
options = options || {};
|
||||
options.title = "Title of the Module";
|
||||
UI.onSetup(options.step);
|
||||
var output;
|
||||
|
||||
function draw(input,callback,progressObj) {
|
||||
|
||||
/* If you wish to supply your own progress bar you need to override progressObj */
|
||||
|
||||
progressObj.stop() // Stop the current progress spinner
|
||||
|
||||
progressObj.overrideFlag = true; // Tell image sequencer that you will supply your own progressBar
|
||||
|
||||
/* Override the object and give your own progress Bar */
|
||||
progressObj = /* Your own progress Object */
|
||||
|
||||
UI.onDraw(options.step);
|
||||
|
||||
var output = function(input){
|
||||
/* do something with the input */
|
||||
return input;
|
||||
};
|
||||
|
||||
this.output = output();
|
||||
options.step.output = output.src;
|
||||
callback();
|
||||
UI.onComplete(options.step);
|
||||
@@ -89,6 +136,8 @@ When you have done your calculations and produced an image output, you are requi
|
||||
to set `this.output` to an object similar to what the input object was, call
|
||||
`callback()`, and set `options.step.output` equal to the output DataURL
|
||||
|
||||
* `progressObj` is an optional Object which handles the progress output of the step in the CLI, this is not consumed unless a custom progress bar needs to be drawn, for which this default spinner should be stopped with `progressObj.stop()` and image-sequencer is informed about the custom progress bar with `progressObj.overrideFlag = true;` following which this object can be overriden with custom progress object.
|
||||
|
||||
### UI Methods
|
||||
|
||||
The module is responsible for emitting various events for the UI to capture. There are
|
||||
|
||||
21142
dist/image-sequencer.js
vendored
21142
dist/image-sequencer.js
vendored
File diff suppressed because one or more lines are too long
2
dist/image-sequencer.min.js
vendored
2
dist/image-sequencer.min.js
vendored
File diff suppressed because one or more lines are too long
10
index.js
10
index.js
@@ -2,6 +2,7 @@
|
||||
|
||||
require('./src/ImageSequencer');
|
||||
sequencer = ImageSequencer({ui: false});
|
||||
var Spinner = require('ora')
|
||||
|
||||
var program = require('commander');
|
||||
var readlineSync = require('readline-sync');
|
||||
@@ -109,12 +110,19 @@ sequencer.loadImages(program.image,function(){
|
||||
sequencer.addSteps(step, options);
|
||||
});
|
||||
|
||||
var spinnerObj = Spinner('Your Image is being processed..').start();
|
||||
|
||||
// Run the sequencer.
|
||||
sequencer.run(function(){
|
||||
sequencer.run(spinnerObj,function(){
|
||||
|
||||
// Export all images or final image as binary files.
|
||||
sequencer.exportBin(program.output,program.basic);
|
||||
|
||||
//check if spinner was not overriden stop it
|
||||
if(!spinnerObj.overrideFlag) {
|
||||
spinnerObj.succeed()
|
||||
console.log(`\nDone!!`)
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "image-sequencer",
|
||||
"version": "1.0.0",
|
||||
"version": "1.2.0",
|
||||
"description": "A modular JavaScript image manipulation library modeled on a storyboard.",
|
||||
"main": "src/ImageSequencer.js",
|
||||
"scripts": {
|
||||
@@ -32,6 +32,7 @@
|
||||
"jsqr": "^0.2.2",
|
||||
"lodash": "^4.17.5",
|
||||
"ndarray-gaussian-filter": "^1.0.0",
|
||||
"ora": "^2.0.0",
|
||||
"pace": "0.0.4",
|
||||
"readline-sync": "^1.4.7",
|
||||
"save-pixels": "~2.3.4",
|
||||
|
||||
@@ -114,7 +114,13 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
return this;
|
||||
}
|
||||
|
||||
function run(t_image,t_from) {
|
||||
function run(spinnerObj,t_image,t_from) {
|
||||
let progressObj;
|
||||
if(arguments[0] != 'test'){
|
||||
progressObj = spinnerObj
|
||||
delete arguments['0']
|
||||
}
|
||||
|
||||
var this_ = (this.name == "ImageSequencer")?this:this.sequencer;
|
||||
var args = (this.name == "ImageSequencer")?[]:[this.images];
|
||||
for (var arg in arguments) args.push(copy(arguments[arg]));
|
||||
@@ -126,7 +132,7 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
|
||||
var json_q = formatInput.call(this_,args,"r");
|
||||
|
||||
require('./Run')(this_, json_q, callback);
|
||||
require('./Run')(this_, json_q, callback,progressObj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ function ReplaceImage(ref,selector,steps,options) {
|
||||
|
||||
function make(url) {
|
||||
tempSequencer.loadImage(url, function(){
|
||||
this.addSteps(steps).run(function(out){
|
||||
this.addSteps(steps).run({stop:function(){}},function(out){
|
||||
img.src = out;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
function Run(ref, json_q, callback) {
|
||||
function Run(ref, json_q, callback,progressObj) {
|
||||
if(!progressObj) progressObj = {stop: function(){}}
|
||||
|
||||
function drawStep(drawarray, pos) {
|
||||
if (pos == drawarray.length && drawarray[pos - 1] !== undefined) {
|
||||
@@ -17,7 +18,7 @@ function Run(ref, json_q, callback) {
|
||||
var input = ref.images[image].steps[i - 1].output;
|
||||
ref.images[image].steps[i].draw(ref.copy(input), function onEachStep() {
|
||||
drawStep(drawarray, ++pos);
|
||||
});
|
||||
},progressObj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,10 @@ module.exports = function Blur(options,UI){
|
||||
UI.onSetup(options.step);
|
||||
var output;
|
||||
|
||||
function draw(input,callback){
|
||||
function draw(input,callback,progressObj){
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
// Tell the UI that a step is being drawn
|
||||
UI.onDraw(options.step);
|
||||
|
||||
@@ -11,7 +11,16 @@ module.exports = function Brightness(options,UI){
|
||||
UI.onSetup(options.step);
|
||||
var output;
|
||||
|
||||
function draw(input,callback){
|
||||
function draw(input,callback,progressObj){
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
/*
|
||||
In this case progress is handled by changepixel internally otherwise progressObj
|
||||
needs to be overriden and used
|
||||
For eg. progressObj = new SomeProgressModule()
|
||||
*/
|
||||
|
||||
// Tell the UI that a step is being drawn
|
||||
UI.onDraw(options.step);
|
||||
|
||||
@@ -8,7 +8,10 @@ module.exports = function Dynamic(options,UI) {
|
||||
var output;
|
||||
|
||||
// This function is called on every draw.
|
||||
function draw(input,callback) {
|
||||
function draw(input,callback,progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
// Tell the UI that the step is being drawn
|
||||
UI.onDraw(options.step);
|
||||
@@ -35,6 +38,10 @@ module.exports = function Dynamic(options,UI) {
|
||||
});
|
||||
|
||||
function changePixel(r, g, b, a) {
|
||||
|
||||
/* neighbourpixels can be calculated by
|
||||
this.getNeighbourPixel.fun(x,y) or this.getNeighborPixel.fun(x,y)
|
||||
*/
|
||||
var combined = (r + g + b) / 3.000;
|
||||
return [
|
||||
options.red_function(r, g, b, a),
|
||||
@@ -44,6 +51,17 @@ module.exports = function Dynamic(options,UI) {
|
||||
];
|
||||
}
|
||||
|
||||
/* Functions to get the neighbouring pixel by position (x,y) */
|
||||
function getNeighbourPixel(pixels,curX,curY,distX,distY){
|
||||
return [
|
||||
pixels.get(curX+distX,curY+distY,0)
|
||||
,pixels.get(curX+distX,curY+distY,1)
|
||||
,pixels.get(curX+distX,curY+distY,2)
|
||||
,pixels.get(curX+distX,curY+distY,3)
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
function output(image,datauri,mimetype){
|
||||
|
||||
// This output is accessible by Image Sequencer
|
||||
@@ -59,6 +77,8 @@ module.exports = function Dynamic(options,UI) {
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
getNeighbourPixel: getNeighbourPixel,
|
||||
getNeighborPixel: getNeighbourPixel,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
inBrowser: options.inBrowser,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
const _ = require('lodash')
|
||||
var pace = require('pace')
|
||||
|
||||
//define kernels for the sobel filter
|
||||
const kernelx = [[-1,0,1],[-2,0,2],[-1,0,1]],
|
||||
@@ -12,7 +11,6 @@ let weakEdgePixels = []
|
||||
let notInUI
|
||||
module.exports = exports = function(pixels,highThresholdRatio,lowThresholdRatio,inBrowser){
|
||||
notInUI = !inBrowser
|
||||
if(notInUI) var progressbar1 = pace((pixels.shape[0] * pixels.shape[1]))
|
||||
for(var x = 0; x < pixels.shape[0]; x++) {
|
||||
angles.push([])
|
||||
mags.push([])
|
||||
@@ -33,7 +31,6 @@ module.exports = exports = function(pixels,highThresholdRatio,lowThresholdRatio
|
||||
|
||||
mags.slice(-1)[0].push(pixel[3])
|
||||
angles.slice(-1)[0].push(result.angle)
|
||||
if(notInUI)progressbar1.op()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +72,6 @@ function changePixel(pixels,val,a,x,y){
|
||||
function nonMaxSupress(pixels) {
|
||||
angles = angles.map((arr)=>arr.map(convertToDegrees))
|
||||
|
||||
if(notInUI) var progressbar2 = pace((pixels.shape[0] * pixels.shape[1]))
|
||||
for(let i = 1;i<pixels.shape[0]-1;i++){
|
||||
for(let j=1;j<pixels.shape[1]-1;j++){
|
||||
|
||||
@@ -118,7 +114,6 @@ function nonMaxSupress(pixels) {
|
||||
else
|
||||
pixels.set(i,j,3,0)
|
||||
|
||||
if(notInUI) progressbar2.op()
|
||||
}
|
||||
}
|
||||
return pixels
|
||||
@@ -133,7 +128,6 @@ var findMaxInMatrix = arr => Math.max(...arr.map(el=>el.map(val=>!!val?val:0)).m
|
||||
function doubleThreshold(pixels,highThresholdRatio,lowThresholdRatio){
|
||||
const highThreshold = findMaxInMatrix(mags) * 0.2
|
||||
const lowThreshold = highThreshold * lowThresholdRatio
|
||||
if(notInUI) var progressbar3 = pace((pixels.shape[0] * pixels.shape[1]))
|
||||
|
||||
for(let i =0;i<pixels.shape[0];i++){
|
||||
for(let j=0;j<pixels.shape[1];j++){
|
||||
@@ -144,7 +138,6 @@ function doubleThreshold(pixels,highThresholdRatio,lowThresholdRatio){
|
||||
?strongEdgePixels.push(pixelPos)
|
||||
:weakEdgePixels.push(pixelPos)
|
||||
:pixels.set(i,j,3,0)
|
||||
if(notInUI) progressbar3.op()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,10 @@ module.exports = function edgeDetect(options,UI) {
|
||||
var output;
|
||||
|
||||
// The function which is called on every draw.
|
||||
function draw(input,callback) {
|
||||
function draw(input,callback,progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
// Tell UI that a step is being drawn.
|
||||
UI.onDraw(options.step);
|
||||
|
||||
@@ -11,7 +11,10 @@ module.exports = function GreenChannel(options,UI) {
|
||||
UI.onSetup(options.step);
|
||||
var output;
|
||||
|
||||
function draw(input,callback) {
|
||||
function draw(input,callback,progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
// Tell UI that a step is being drawn
|
||||
UI.onDraw(options.step);
|
||||
|
||||
@@ -12,8 +12,10 @@ module.exports = function Invert(options,UI) {
|
||||
var output;
|
||||
|
||||
// The function which is called on every draw.
|
||||
function draw(input,callback) {
|
||||
function draw(input,callback,progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
// Tell UI that a step is being drawn.
|
||||
UI.onDraw(options.step);
|
||||
|
||||
|
||||
@@ -11,7 +11,10 @@ module.exports = function NdviRed(options,UI) {
|
||||
var output;
|
||||
|
||||
// The function which is called on every draw.
|
||||
function draw(input,callback) {
|
||||
function draw(input,callback,progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
// Tell the UI that a step is being drawn.
|
||||
UI.onDraw(options.step);
|
||||
|
||||
@@ -11,7 +11,10 @@ module.exports = function Saturation(options,UI) {
|
||||
UI.onSetup(options.step);
|
||||
var output;
|
||||
|
||||
function draw(input,callback) {
|
||||
function draw(input,callback,progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
// Tell UI that a step is being drawn
|
||||
UI.onDraw(options.step);
|
||||
|
||||
@@ -8,7 +8,10 @@ module.exports = function SegmentedColormap(options,UI) {
|
||||
var output;
|
||||
|
||||
// This function is called on every draw.
|
||||
function draw(input,callback) {
|
||||
function draw(input,callback,progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
// Tell the UI that the step is being drawn
|
||||
UI.onDraw(options.step);
|
||||
|
||||
@@ -22,12 +22,24 @@ module.exports = function PixelManipulation(image, options) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(options.getNeighbourPixel){
|
||||
options.getNeighbourPixel.fun = function (distX,distY) {
|
||||
return options.getNeighbourPixel(pixels,x,y,distX,distY);
|
||||
};
|
||||
}
|
||||
|
||||
// iterate through pixels;
|
||||
// this could possibly be more efficient; see
|
||||
// https://github.com/p-v-o-s/infragram-js/blob/master/public/infragram.js#L173-L181
|
||||
|
||||
if(!options.inBrowser)
|
||||
var pace = require('pace')((pixels.shape[0] * pixels.shape[1]))
|
||||
if(!options.inBrowser){
|
||||
try{
|
||||
var pace = require('pace')((pixels.shape[0] * pixels.shape[1]));
|
||||
}
|
||||
catch(e){
|
||||
options.inBrowser = true;
|
||||
}
|
||||
}
|
||||
|
||||
for(var x = 0; x < pixels.shape[0]; x++) {
|
||||
for(var y = 0; y < pixels.shape[1]; y++) {
|
||||
|
||||
@@ -15,12 +15,13 @@ var sequencer = ImageSequencer({ ui: false });
|
||||
var qr = require('./images/IS-QR.js');
|
||||
var test_png = require('./images/test.png.js');
|
||||
var test_gif = require('./images/test.gif.js');
|
||||
var spinner = require('ora')('').start()
|
||||
|
||||
sequencer.loadImages(test_png);
|
||||
sequencer.addSteps(['invert','invert']);
|
||||
|
||||
test("Preload", function(t) {
|
||||
sequencer.run(function(){
|
||||
sequencer.run(spinner,function(){
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
@@ -51,7 +52,7 @@ test("Twice inverted image is identical to original image", function (t) {
|
||||
|
||||
test("Decode QR module works properly :: setup", function (t) {
|
||||
sequencer.loadImage(qr,function(){
|
||||
this.addSteps('decode-qr').run(function(){
|
||||
this.addSteps('decode-qr').run(spinner.start(),function(){
|
||||
t.end();
|
||||
});
|
||||
})
|
||||
@@ -64,7 +65,7 @@ test("Decode QR module works properly :: teardown", function (t) {
|
||||
|
||||
test("PixelManipulation works for PNG images", function (t) {
|
||||
sequencer.loadImages(test_png,function(){
|
||||
this.addSteps('invert').run(function(out){
|
||||
this.addSteps('invert').run(spinner.start(),function(out){
|
||||
t.equal(1,1)
|
||||
t.end();
|
||||
});
|
||||
@@ -73,9 +74,10 @@ test("PixelManipulation works for PNG images", function (t) {
|
||||
|
||||
test("PixelManipulation works for GIF images", function (t) {
|
||||
sequencer.loadImages(test_gif,function(){
|
||||
this.addSteps('invert').run(function(out){
|
||||
this.addSteps('invert').run(spinner,function(out){
|
||||
t.equal(1,1)
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
});
|
||||
spinner.stop(true)
|
||||
|
||||
Reference in New Issue
Block a user