summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rotord/src/nodes_filters.h246
-rw-r--r--rotord/src/nodes_maths.h8
-rwxr-xr-xrotord/src/rotor.cpp6
-rwxr-xr-xrotord/src/rotor.h311
4 files changed, 303 insertions, 268 deletions
diff --git a/rotord/src/nodes_filters.h b/rotord/src/nodes_filters.h
index 263b4b2..0cc1d77 100644
--- a/rotord/src/nodes_filters.h
+++ b/rotord/src/nodes_filters.h
@@ -31,6 +31,252 @@ namespace Rotor {
private:
float size;
};
+ class Luma_levels: public Image_node {
+ public:
+ Luma_levels(){
+ create_image_input("image input","Image input");
+ create_parameter("black_in","number","input black point","Input black point",0.0f,0.0f,1.0f);
+ create_parameter("white_in","number","input white point","Input white point",1.0f,0.0f,1.0f);
+ create_parameter("gamma","number","gamma level","Gamma",1.0f,0.0f,10.0f);
+ create_parameter("black_out","number","output black point","Output black point",0.0f,0.0f,1.0f);
+ create_parameter("white_out","number","output white point","Output white point",1.0f,0.0f,1.0f);
+ title="Luma levels";
+ description="Remap luma values of image";
+ LUT=nullptr;
+ };
+ Luma_levels(map<string,string> &settings):Luma_levels() {
+ base_settings(settings);
+ }
+ ~Luma_levels(){if (LUT) { delete[] LUT;} };
+ void generate_LUT(){
+ //can check here if anything has changed
+ if (LUT) delete[] LUT;
+ LUT=new unsigned char[256];
+ float fltmax=(255.0f/256.0f);
+ for (int i=0;i<256;i++){
+ LUT[i]=(unsigned char)(((pow(min(fltmax,max(0.0f,(((((float)i)/256.0f)-parameters["black_in"]->value)/(parameters["white_in"]->value-parameters["black_in"]->value)))),(1.0/parameters["gamma"]->value))*(parameters["white_out"]->value-parameters["black_out"]->value))+parameters["black_out"]->value)*255.0f);
+ }
+ }
+ void apply_LUT(const Image& in){
+ apply_LUT(in,image);
+ }
+ void apply_LUT(const Image& in,Image &out){ //facility to apply to other images for inherited classes
+ out.setup(in.w,in.h);
+ for (int i=0;i<out.w*out.h*3;i++){
+ out.RGBdata[i]=LUT[in.RGBdata[i]];
+ }
+ }
+ Image *output(const Frame_spec &frame){
+ Image *in=image_inputs[0]->get(frame);
+ if (in){
+ generate_LUT();
+ apply_LUT(*in);
+ }
+ return &image;
+ }
+ Luma_levels* clone(map<string,string> &_settings) { return new Luma_levels(_settings);};
+ protected:
+ unsigned char *LUT;
+ };
+ class Echo_trails: public Luma_levels {
+ //draw trail frames additively that fade off over time
+ //the hard thing here is how to cache frames, if its done cleverly it could have no impact when
+ //used linearly
+ //Image needs to overload operator+
+ //need a clever data structure to cache frames - maybe a map of Image pointers
+
+ //we know the frames we want to overlay as offsets ie -25,-20,-15,-10,-5
+ //do we keep 25 frames loaded in order to benefit? 25 PAL frames is 60MB so probably so
+ //OK so:
+ //make a new set of pointers
+ //identify if any of the new pointers can inherit old frames
+ //delete unneeded old frames
+ //load new frames
+ //do the calculations
+
+ //new set of pointers? or track frames by absolute frame number?
+ //with relative pointers and switching frames, could use auto_ptr?
+
+ //this cache mechanism should maybe be inheritable too?
+
+ //it could be hugely beneficial to only do the LUT once?
+ //although maybe the way to do the fading is to have a LUT for each frame?
+
+ //or is it actually best to use alpha keying after all!
+ public:
+ Echo_trails(){
+ //calls base class constructor first
+ create_parameter("number","number","number of echoes","Number echoes",25.0f);
+ create_parameter("fadeto","number","amount that echoes fade out","Fadout amount",1.0f,0.0f,1.0f);
+ create_attribute("mode","blend mode for echoes","Blend mode","screen",{"screen","wrap"});
+ title="Echo trails";
+ description="Draw trail frames additively that fade off over time";
+ };
+ Echo_trails(map<string,string> &settings):Echo_trails() {
+ base_settings(settings);
+ lastframe=-1;
+ }
+ ~Echo_trails(){
+ for (auto i:images) delete i.second;
+ };
+ Image *output(const Frame_spec &frame){
+ //check if cache is valid
+ if (images.size()){
+ if (frame.w!=image.w||frame.h!=image.h){ //or framerate changed?
+ //clear cache and start over
+ images.clear();
+ lastframe=-1;
+ //calculate frame interval
+ //interval=(int)(((duration/number)*frame.framerate)+0.5);
+ //total=interval*number;
+ }
+ }
+ int thisframe=frame.frame();
+ //iterate cache and throw out any obsolete frames
+ auto i = std::begin(images);
+ while (i != std::end(images)) {
+ // check if the image is in the range we need
+ if (thisframe-(*i).first>(int)parameters["number"]->value||thisframe-(*i).first<0) {
+ delete (*i).second;
+ i = images.erase(i);
+ }
+ else
+ ++i;
+ }
+ //if frame has already been calculated just return it
+ if (thisframe!=lastframe) {
+ Image *in=image_inputs[0]->get(frame);
+ if (in) {
+ generate_LUT();
+ //need a better strategy here, should be able to get each image once
+ //copy incoming image **writable
+ image=*(in);
+ images[thisframe]=new Image(frame.w,frame.h);
+ apply_LUT(image,*(images[thisframe]));
+ for (int i=1;i<(int)parameters["number"]->value;i++){
+ //check echo frame isn't at negative time
+ int absframe=thisframe-i;
+ if (absframe>-1){
+ //check if image is in the cache
+ if (images.find(absframe)==images.end()){
+ images[absframe]=new Image(frame.w,frame.h);
+ Frame_spec wanted=Frame_spec(absframe,frame.framerate,frame.duration,frame.w,frame.h);
+ apply_LUT(*(((Image_node*)image_inputs[0]->connection)->get_output(wanted)),*(images[absframe]));
+ }
+ if (fless(1.0f,parameters["fadeto"]->value)){
+ float amount=(((parameters["number"]->value-i)/parameters["number"]->value)*(1.0f-parameters["fadeto"]->value))+(1.0f-parameters["fadeto"]->value);
+ Image *temp=*images[absframe]*amount;
+ if (attributes["mode"]->value=="screen") {
+ image+=*temp;
+ }
+ else {
+ image.add_wrap(*temp);
+ }
+ delete temp;
+ }
+ else {
+ if (attributes["mode"]->value=="screen") image+=*(images[absframe]);
+ else image=image.add_wrap(*(images[absframe]));
+ }
+ }
+ }
+ //for (int i=0;i<frame.w*frame.h*3;i++){
+ // image->RGBdata[i]=LUT[in->RGBdata[i]];
+ //}
+ lastframe=thisframe;
+ }
+ }
+ return &image;
+ }
+ Echo_trails* clone(map<string,string> &_settings) { return new Echo_trails(_settings);};
+ protected:
+ int interval,total,lastframe; //number of frames between displayed echoes
+ unordered_map<int,Image*> images;
+ };
+ class RGB_levels: public Image_node {
+ public:
+ RGB_levels(){
+ create_image_input("image input","Image input");
+ create_parameter("red_black_in","number","Red input black-point","Red input black-point",0.0f,0.0f,1.0f);
+ create_parameter("red_white_in","number","Red input white-point","Red input white-point",1.0f,0.0f,1.0f);
+ create_parameter("red_gamma","number","Red gamma level","Red gamma",1.0f,0.01f,10.0f);
+ create_parameter("red_black_out","number","Red output black point","Red output black point",0.0f,0.0f,1.0f);
+ create_parameter("red_white_out","number","Red output white point","Red output white point",1.0f,0.0f,1.0f);
+ create_parameter("green_black_in","number","Green input black point","Green input black point",0.0f,0.0f,1.0f);
+ create_parameter("green_white_in","number","Green input white point","Green input white point",1.0f,0.0f,1.0f);
+ create_parameter("green_gamma","number","Green gamma level","Green gamma",1.0f,0.01f,10.0f);
+ create_parameter("green_black_out","number","Green output black point","Green output black point",0.0f,0.0f,1.0f);
+ create_parameter("green_white_out","number","Green output white point","Green output white point",1.0f,0.0f,1.0f);
+ create_parameter("blue_black_in","number","Blue input black point","Blue input black point",0.0f,0.0f,1.0f);
+ create_parameter("blue_white_in","number","Blue input white point","Blue input white point",1.0f,0.0f,1.0f);
+ create_parameter("blue_gamma","number","Blue gamma level","Blue gamma",1.0f,0.01f,10.0f);
+ create_parameter("blue_black_out","number","Blue output black point","Blue output black point",0.0f,0.0f,1.0f);
+ create_parameter("blue_white_out","number","Blue output white point","Blue output white point",1.0f,0.0f,1.0f);
+ title="RGB levels";
+ description="Remap RGB values of image";
+ LUT=nullptr;
+ };
+ RGB_levels(map<string,string> &settings):RGB_levels() {
+ base_settings(settings);
+ }
+ ~RGB_levels(){
+ if (LUT) {
+ for (int i=0;i<3;i++) {
+ delete[] LUT[i];
+ }
+ delete[] LUT;
+ }
+ };
+ void generate_LUT(){
+ //can check here if anything has changed
+ if (LUT) {
+ for (int i=0;i<3;i++) {
+ delete[] LUT[i];
+ }
+ delete[] LUT;
+ }
+ LUT=new unsigned char*[3];
+ for (int i=0;i<3;i++){
+ LUT[i]=new unsigned char[256];
+ }
+ float fltmax=(255.0f/256.0f);
+ for (int i=0;i<256;i++){
+ LUT[0][i]=(unsigned char)(((\
+ pow(min(fltmax,max(0.0f,(((((float)i)/256.0f)-parameters["red_black_in"]->value)/(parameters["red_white_in"]->value-parameters["red_black_in"]->value))))\
+ ,(1.0/parameters["red_gamma"]->value))\
+ *(parameters["red_white_out"]->value-parameters["red_black_out"]->value))+parameters["red_black_out"]->value)*255.0f);
+ LUT[1][i]=(unsigned char)(((\
+ pow(min(fltmax,max(0.0f,(((((float)i)/256.0f)-parameters["green_black_in"]->value)/(parameters["green_white_in"]->value-parameters["green_black_in"]->value))))\
+ ,(1.0/parameters["green_gamma"]->value))\
+ *(parameters["green_white_out"]->value-parameters["green_black_out"]->value))+parameters["green_black_out"]->value)*255.0f);
+ LUT[2][i]=(unsigned char)(((\
+ pow(min(fltmax,max(0.0f,(((((float)i)/256.0f)-parameters["blue_black_in"]->value)/(parameters["blue_white_in"]->value-parameters["blue_black_in"]->value))))\
+ ,(1.0/parameters["blue_gamma"]->value))\
+ *(parameters["blue_white_out"]->value-parameters["blue_black_out"]->value))+parameters["blue_black_out"]->value)*255.0f);
+ }
+ }
+ void apply_LUT(const Image& in){
+ apply_LUT(in,image);
+ }
+ void apply_LUT(const Image& in,Image &out){ //facility to apply to other images for inherited classes
+ for (int i=0;i<out.w*out.h;i++){
+ out.RGBdata[i*3]=LUT[0][in.RGBdata[i*3]];
+ out.RGBdata[i*3+1]=LUT[1][in.RGBdata[i*3+1]];
+ out.RGBdata[i*3+2]=LUT[2][in.RGBdata[i*3+2]];
+ }
+ }
+ Image *output(const Frame_spec &frame){
+ Image *in=image_inputs[0]->get(frame);
+ if (in){
+ generate_LUT();
+ apply_LUT(*in);
+ }
+ return &image;
+ }
+ RGB_levels* clone(map<string,string> &_settings) { return new RGB_levels(_settings);};
+ protected:
+ unsigned char **LUT;
+ };
}
diff --git a/rotord/src/nodes_maths.h b/rotord/src/nodes_maths.h
index 4ec2cf9..b1e20ca 100644
--- a/rotord/src/nodes_maths.h
+++ b/rotord/src/nodes_maths.h
@@ -25,7 +25,7 @@ namespace Rotor {
base_settings(settings);
}
Comparison* clone(map<string,string> &_settings) { return new Comparison(_settings);};
- const float output(const Time_spec &time) {
+ const float output(const Time_spec &time) {
switch (attributes["operator"]->intVal) {
case COMPARISON_Equal:
return fequal(parameters["value"]->value,inputs[0]->get(time))?1.0f:0.0f;
@@ -46,7 +46,7 @@ namespace Rotor {
return fless_or_equal(parameters["value"]->value,inputs[0]->get(time))?1.0f:0.0f;
break;
}
-
+
return 0.0f;
}
};
@@ -193,7 +193,7 @@ namespace Rotor {
create_signal_input("signal","Signal");
create_parameter("seed","number","Seed value","Seed",1.0f);
};
- Random(map<string,string> &settings) {
+ Random(map<string,string> &settings):Random() {
base_settings(settings);
};
Random* clone(map<string,string> &_settings) { return new Random(_settings);};
@@ -231,4 +231,4 @@ namespace Rotor {
};
}
-#endif \ No newline at end of file
+#endif
diff --git a/rotord/src/rotor.cpp b/rotord/src/rotor.cpp
index e205492..0284223 100755
--- a/rotord/src/rotor.cpp
+++ b/rotord/src/rotor.cpp
@@ -17,9 +17,6 @@ Node_factory::Node_factory(){
add_type("signal_colour",new Signal_colour());
add_type("signal_greyscale",new Signal_greyscale());
add_type("image_arithmetic",new Image_arithmetic());
- add_type("luma_levels",new Luma_levels());
- add_type("echo_trails",new Echo_trails());
- add_type("rgb_levels",new RGB_levels());
add_type("blend",new Blend());
add_type("mirror",new Mirror());
add_type("monochrome",new Monochrome());
@@ -38,6 +35,9 @@ Node_factory::Node_factory(){
add_type("hello",new Hello_draw());
//nodes_filters.h
add_type("blur",new Blur());
+ add_type("luma_levels",new Luma_levels());
+ add_type("echo_trails",new Echo_trails());
+ add_type("rgb_levels",new RGB_levels());
//video nodes
add_type("video_loader",new Video_loader());
add_type("video_output",new Video_output());
diff --git a/rotord/src/rotor.h b/rotord/src/rotor.h
index f7d6861..eb00104 100755
--- a/rotord/src/rotor.h
+++ b/rotord/src/rotor.h
@@ -95,7 +95,7 @@ namespace Rotor {
public:
virtual ~Image_input(){};
bool connect(Node *source);
- Image_input(const string &_desc,const string &_title,Node* _connect): Input(_desc,_title){
+ Image_input(const string &_desc,const string &_title,Node* _connect): Input(_desc,_title){
connect(_connect);
};
Image* get(const Frame_spec& time);
@@ -104,7 +104,7 @@ namespace Rotor {
public:
virtual ~Signal_input(){};
bool connect(Node *source);
- Signal_input(const string &_desc,const string &_title,Node* _connect): Input(_desc,_title){
+ Signal_input(const string &_desc,const string &_title,Node* _connect): Input(_desc,_title){
connect(_connect);
};
float get(const Time_spec& time);
@@ -112,7 +112,7 @@ namespace Rotor {
class Parameter: public Signal_input{
public:
virtual ~Parameter(){};
- void init(const float &_val){
+ void init(const float &_val){
value=_val;
}
Parameter(const string &_type,const string &_desc,const string &_title,float _value,float _min,float _max,Node* _connect): Signal_input(_desc,_title,_connect),value(_value),min(_min),max(_max),type(_type){};
@@ -204,17 +204,17 @@ namespace Rotor {
void create_image_input(const string &_title,const string &_desc,Node* _connect=nullptr) {
image_inputs.push_back(new Image_input(_desc,_title,_connect));
};
- Image *get_output(const Frame_spec &frame) {
+ Image *get_output(const Frame_spec &frame) {
image.setup(frame.w,frame.h);
update((Time_spec)frame);
- return output(frame);
+ return output(frame);
}
virtual const Image *output(const Frame_spec &frame)=0;
Image *get_preview(const Frame_spec &frame);
Image image;
private:
float image_time; //? could be used to detect image reuse?
-
+
};
class Audio_processor: public Signal_node {
public:
@@ -295,13 +295,13 @@ namespace Rotor {
return &image;
}
private:
-
+
};
class Invert: public Image_node {
public:
Invert(){
create_image_input("Image to invert","Image input");
- create_parameter("invert","number","Invert when greater than 0.0","Negative",1.0f,0.0f,1.0f);
+ create_parameter("invert","number","Invert when greater than 0.0","Negative",1.0f,0.0f,1.0f);
title="Negative";
description="Inverts the input picture";
};
@@ -446,259 +446,13 @@ namespace Rotor {
image=(*in);
image/=parameters["value"]->value;
break;
- }
+ }
}
return &image;
}
Image_arithmetic* clone(map<string,string> &_settings) { return new Image_arithmetic(_settings);};
private:
};
- class Luma_levels: public Image_node {
- public:
- Luma_levels(){
- create_image_input("image input","Image input");
- create_parameter("black_in","number","input black point","Input black point",0.0f,0.0f,1.0f);
- create_parameter("white_in","number","input white point","Input white point",1.0f,0.0f,1.0f);
- create_parameter("gamma","number","gamma level","Gamma",1.0f,0.0f,10.0f);
- create_parameter("black_out","number","output black point","Output black point",0.0f,0.0f,1.0f);
- create_parameter("white_out","number","output white point","Output white point",1.0f,0.0f,1.0f);
- title="Luma levels";
- description="Remap luma values of image";
- LUT=nullptr;
- };
- Luma_levels(map<string,string> &settings):Luma_levels() {
- base_settings(settings);
- }
- ~Luma_levels(){if (LUT) { delete[] LUT;} };
- void generate_LUT(){
- //can check here if anything has changed
- if (LUT) delete[] LUT;
- LUT=new unsigned char[256];
- float fltmax=(255.0f/256.0f);
- for (int i=0;i<256;i++){
- LUT[i]=(unsigned char)(((pow(min(fltmax,max(0.0f,(((((float)i)/256.0f)-parameters["black_in"]->value)/(parameters["white_in"]->value-parameters["black_in"]->value)))),(1.0/parameters["gamma"]->value))*(parameters["white_out"]->value-parameters["black_out"]->value))+parameters["black_out"]->value)*255.0f);
- }
- }
- void apply_LUT(const Image& in){
- apply_LUT(in,image);
- }
- void apply_LUT(const Image& in,Image &out){ //facility to apply to other images for inherited classes
- out.setup(in.w,in.h);
- for (int i=0;i<out.w*out.h*3;i++){
- out.RGBdata[i]=LUT[in.RGBdata[i]];
- }
- }
- Image *output(const Frame_spec &frame){
- Image *in=image_inputs[0]->get(frame);
- if (in){
- generate_LUT();
- apply_LUT(*in);
- }
- return &image;
- }
- Luma_levels* clone(map<string,string> &_settings) { return new Luma_levels(_settings);};
- protected:
- unsigned char *LUT;
- };
- class Echo_trails: public Luma_levels {
- //draw trail frames additively that fade off over time
- //the hard thing here is how to cache frames, if its done cleverly it could have no impact when
- //used linearly
- //Image needs to overload operator+
- //need a clever data structure to cache frames - maybe a map of Image pointers
-
- //we know the frames we want to overlay as offsets ie -25,-20,-15,-10,-5
- //do we keep 25 frames loaded in order to benefit? 25 PAL frames is 60MB so probably so
- //OK so:
- //make a new set of pointers
- //identify if any of the new pointers can inherit old frames
- //delete unneeded old frames
- //load new frames
- //do the calculations
-
- //new set of pointers? or track frames by absolute frame number?
- //with relative pointers and switching frames, could use auto_ptr?
-
- //this cache mechanism should maybe be inheritable too?
-
- //it could be hugely beneficial to only do the LUT once?
- //although maybe the way to do the fading is to have a LUT for each frame?
-
- //or is it actually best to use alpha keying after all!
- public:
- Echo_trails(){
- //calls base class constructor first
- create_parameter("number","number","number of echoes","Number echoes",25.0f);
- create_parameter("fadeto","number","amount that echoes fade out","Fadout amount",1.0f,0.0f,1.0f);
- create_attribute("mode","blend mode for echoes","Blend mode","screen",{"screen","wrap"});
- title="Echo trails";
- description="Draw trail frames additively that fade off over time";
- };
- Echo_trails(map<string,string> &settings):Echo_trails() {
- base_settings(settings);
- lastframe=-1;
- }
- ~Echo_trails(){
- for (auto i:images) delete i.second;
- };
- Image *output(const Frame_spec &frame){
- //check if cache is valid
- if (images.size()){
- if (frame.w!=image.w||frame.h!=image.h){ //or framerate changed?
- //clear cache and start over
- images.clear();
- lastframe=-1;
- //calculate frame interval
- //interval=(int)(((duration/number)*frame.framerate)+0.5);
- //total=interval*number;
- }
- }
- int thisframe=frame.frame();
- //iterate cache and throw out any obsolete frames
- auto i = std::begin(images);
- while (i != std::end(images)) {
- // check if the image is in the range we need
- if (thisframe-(*i).first>(int)parameters["number"]->value||thisframe-(*i).first<0) {
- delete (*i).second;
- i = images.erase(i);
- }
- else
- ++i;
- }
- //if frame has already been calculated just return it
- if (thisframe!=lastframe) {
- Image *in=image_inputs[0]->get(frame);
- if (in) {
- generate_LUT();
- //need a better strategy here, should be able to get each image once
- //copy incoming image **writable
- image=*(in);
- images[thisframe]=new Image(frame.w,frame.h);
- apply_LUT(image,*(images[thisframe]));
- for (int i=1;i<(int)parameters["number"]->value;i++){
- //check echo frame isn't at negative time
- int absframe=thisframe-i;
- if (absframe>-1){
- //check if image is in the cache
- if (images.find(absframe)==images.end()){
- images[absframe]=new Image(frame.w,frame.h);
- Frame_spec wanted=Frame_spec(absframe,frame.framerate,frame.duration,frame.w,frame.h);
- apply_LUT(*(((Image_node*)image_inputs[0]->connection)->get_output(wanted)),*(images[absframe]));
- }
- if (fless(1.0f,parameters["fadeto"]->value)){
- float amount=(((parameters["number"]->value-i)/parameters["number"]->value)*(1.0f-parameters["fadeto"]->value))+(1.0f-parameters["fadeto"]->value);
- Image *temp=*images[absframe]*amount;
- if (attributes["mode"]->value=="screen") {
- image+=*temp;
- }
- else {
- image.add_wrap(*temp);
- }
- delete temp;
- }
- else {
- if (attributes["mode"]->value=="screen") image+=*(images[absframe]);
- else image=image.add_wrap(*(images[absframe]));
- }
- }
- }
- //for (int i=0;i<frame.w*frame.h*3;i++){
- // image->RGBdata[i]=LUT[in->RGBdata[i]];
- //}
- lastframe=thisframe;
- }
- }
- return &image;
- }
- Echo_trails* clone(map<string,string> &_settings) { return new Echo_trails(_settings);};
- protected:
- int interval,total,lastframe; //number of frames between displayed echoes
- unordered_map<int,Image*> images;
- };
- class RGB_levels: public Image_node {
- public:
- RGB_levels(){
- create_image_input("image input","Image input");
- create_parameter("red_black_in","number","Red input black-point","Red input black-point",0.0f,0.0f,1.0f);
- create_parameter("red_white_in","number","Red input white-point","Red input white-point",1.0f,0.0f,1.0f);
- create_parameter("red_gamma","number","Red gamma level","Red gamma",1.0f,0.01f,10.0f);
- create_parameter("red_black_out","number","Red output black point","Red output black point",0.0f,0.0f,1.0f);
- create_parameter("red_white_out","number","Red output white point","Red output white point",1.0f,0.0f,1.0f);
- create_parameter("green_black_in","number","Green input black point","Green input black point",0.0f,0.0f,1.0f);
- create_parameter("green_white_in","number","Green input white point","Green input white point",1.0f,0.0f,1.0f);
- create_parameter("green_gamma","number","Green gamma level","Green gamma",1.0f,0.01f,10.0f);
- create_parameter("green_black_out","number","Green output black point","Green output black point",0.0f,0.0f,1.0f);
- create_parameter("green_white_out","number","Green output white point","Green output white point",1.0f,0.0f,1.0f);
- create_parameter("blue_black_in","number","Blue input black point","Blue input black point",0.0f,0.0f,1.0f);
- create_parameter("blue_white_in","number","Blue input white point","Blue input white point",1.0f,0.0f,1.0f);
- create_parameter("blue_gamma","number","Blue gamma level","Blue gamma",1.0f,0.01f,10.0f);
- create_parameter("blue_black_out","number","Blue output black point","Blue output black point",0.0f,0.0f,1.0f);
- create_parameter("blue_white_out","number","Blue output white point","Blue output white point",1.0f,0.0f,1.0f);
- title="RGB levels";
- description="Remap RGB values of image";
- LUT=nullptr;
- };
- RGB_levels(map<string,string> &settings):RGB_levels() {
- base_settings(settings);
- }
- ~RGB_levels(){
- if (LUT) {
- for (int i=0;i<3;i++) {
- delete[] LUT[i];
- }
- delete[] LUT;
- }
- };
- void generate_LUT(){
- //can check here if anything has changed
- if (LUT) {
- for (int i=0;i<3;i++) {
- delete[] LUT[i];
- }
- delete[] LUT;
- }
- LUT=new unsigned char*[3];
- for (int i=0;i<3;i++){
- LUT[i]=new unsigned char[256];
- }
- float fltmax=(255.0f/256.0f);
- for (int i=0;i<256;i++){
- LUT[0][i]=(unsigned char)(((\
- pow(min(fltmax,max(0.0f,(((((float)i)/256.0f)-parameters["red_black_in"]->value)/(parameters["red_white_in"]->value-parameters["red_black_in"]->value))))\
- ,(1.0/parameters["red_gamma"]->value))\
- *(parameters["red_white_out"]->value-parameters["red_black_out"]->value))+parameters["red_black_out"]->value)*255.0f);
- LUT[1][i]=(unsigned char)(((\
- pow(min(fltmax,max(0.0f,(((((float)i)/256.0f)-parameters["green_black_in"]->value)/(parameters["green_white_in"]->value-parameters["green_black_in"]->value))))\
- ,(1.0/parameters["green_gamma"]->value))\
- *(parameters["green_white_out"]->value-parameters["green_black_out"]->value))+parameters["green_black_out"]->value)*255.0f);
- LUT[2][i]=(unsigned char)(((\
- pow(min(fltmax,max(0.0f,(((((float)i)/256.0f)-parameters["blue_black_in"]->value)/(parameters["blue_white_in"]->value-parameters["blue_black_in"]->value))))\
- ,(1.0/parameters["blue_gamma"]->value))\
- *(parameters["blue_white_out"]->value-parameters["blue_black_out"]->value))+parameters["blue_black_out"]->value)*255.0f);
- }
- }
- void apply_LUT(const Image& in){
- apply_LUT(in,image);
- }
- void apply_LUT(const Image& in,Image &out){ //facility to apply to other images for inherited classes
- for (int i=0;i<out.w*out.h;i++){
- out.RGBdata[i*3]=LUT[0][in.RGBdata[i*3]];
- out.RGBdata[i*3+1]=LUT[1][in.RGBdata[i*3+1]];
- out.RGBdata[i*3+2]=LUT[2][in.RGBdata[i*3+2]];
- }
- }
- Image *output(const Frame_spec &frame){
- Image *in=image_inputs[0]->get(frame);
- if (in){
- generate_LUT();
- apply_LUT(*in);
- }
- return &image;
- }
- RGB_levels* clone(map<string,string> &_settings) { return new RGB_levels(_settings);};
- protected:
- unsigned char **LUT;
- };
#define BLEND_blend 1
#define BLEND_screen 2
#define BLEND_multiply 3
@@ -938,7 +692,6 @@ namespace Rotor {
Alpha_merge(){
create_image_input("image input","Image input");
create_image_input("alpha input","Alpha input");
- create_parameter("transformX","number","X transformation","Transform X",0.0f);
title="Alpha merge";
description="Alpha merge two images";
};
@@ -964,6 +717,42 @@ namespace Rotor {
}
private:
};
+ class Difference_matte: public Image_node {
+ public:
+ Difference_matte(){
+ create_image_input("image input","Image input");
+ create_image_input("background input","Background input");
+ create_parameter("threshold","number","Difference threshold","Threshold",0.05f,0.0f,1.0f);
+ title="Difference matte";
+ description="Create an alpha channel using a background reference picture";
+ };
+ Difference_matte(map<string,string> &settings):Difference_matte() {
+ base_settings(settings);
+ };
+ ~Difference_matte(){};
+ Difference_matte* clone(map<string,string> &_settings) { return new Difference_matte(_settings);};
+ Image *output(const Frame_spec &frame){
+ Image *in1=image_inputs[0]->get(frame);
+ if (in1){
+ //copy incoming image **writable
+ Image *in2=image_inputs[1]->get(frame);
+ if (in2) {
+ cv::cvtColor(in1->rgb,greyfg,CV_RGB2GRAY);
+ cv::cvtColor(in2->rgb,greybg,CV_RGB2GRAY);
+ //cv::absDiff(greybg,greyfg,greyDiff);
+ //adaptiveThreshold(greyDiff,parameters["threshold"].value,20,true,false); //int blockSize, int offset=0,bool invert=false, bool gauss=false);
+
+ image.alpha_merge(*in2);
+ return &image;
+ }
+ //if there aren't 2 image inputs connected just return the first
+ return in1;
+ }
+ return nullptr;
+ }
+ private:
+ cv::Mat greyfg,greybg,greyDiff;
+ };
#define VIDEOFRAMES_still 1
#define VIDEOFRAMES_blend 2
class Video_loader: public Image_node {
@@ -1049,7 +838,7 @@ namespace Rotor {
// XML.setValue("description",type.second->description,0);
//}
int j=0;
- for (auto& input: type.second->inputs) {
+ for (auto& input: type.second->inputs) {
XML.addTag("signal_input");
XML.addAttribute("signal_input","title",input->title,j);
XML.addAttribute("signal_input","description",input->description,j);
@@ -1057,7 +846,7 @@ namespace Rotor {
}
j=0;
if (dynamic_cast<Image_node*> (type.second)!=nullptr) {
- for (auto& input: (dynamic_cast<Image_node*>(type.second))->image_inputs) {
+ for (auto& input: (dynamic_cast<Image_node*>(type.second))->image_inputs) {
XML.addTag("image_input");
XML.addAttribute("image_input","title",input->title,j);
XML.addAttribute("image_input","description",input->description,j);
@@ -1065,7 +854,7 @@ namespace Rotor {
}
}
j=0;
- for (auto& parameter: type.second->parameters) {
+ for (auto& parameter: type.second->parameters) {
XML.addTag("parameter");
XML.addAttribute("parameter","name",parameter.first,j);
XML.addAttribute("parameter","type",parameter.second->type,j);
@@ -1077,7 +866,7 @@ namespace Rotor {
j++;
}
j=0;
- for (auto& attribute: type.second->attributes) {
+ for (auto& attribute: type.second->attributes) {
XML.addTag("attribute");
XML.addAttribute("attribute","name",attribute.first,j);
XML.addAttribute("attribute","title",attribute.second->title,j);
@@ -1160,4 +949,4 @@ namespace Rotor {
};
}
-#endif \ No newline at end of file
+#endif