diff options
| author | Tim Redfern <tim@eclectronics.org> | 2013-08-26 13:18:02 +0100 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2013-08-26 13:18:02 +0100 |
| commit | 8bc47c7a4ec05f1d1e29de283a47923a1d6d340b (patch) | |
| tree | bad28e2ed4fb55c1c3855a9df96716a20a4fde95 /rotord/src | |
| parent | 084697db61ba3adfee7fbd054d8d5ac7a0c62485 (diff) | |
finished json loader
Diffstat (limited to 'rotord/src')
| -rw-r--r-- | rotord/src/graph.cpp | 13 | ||||
| -rw-r--r-- | rotord/src/nodes_filters.h | 11 | ||||
| -rw-r--r-- | rotord/src/nodes_maths.h | 10 | ||||
| -rwxr-xr-x | rotord/src/rotor.cpp | 1 | ||||
| -rwxr-xr-x | rotord/src/rotor.h | 171 |
5 files changed, 177 insertions, 29 deletions
diff --git a/rotord/src/graph.cpp b/rotord/src/graph.cpp index 139873f..5871b7b 100644 --- a/rotord/src/graph.cpp +++ b/rotord/src/graph.cpp @@ -43,6 +43,9 @@ bool Graph::video_render(const string &output_filename,const string &audio_filen } if (find_node("video_output")) { Video_output *video_output=dynamic_cast<Video_output*>(find_node("video_output")); + for (auto f: find_nodes("video_feedback")){ + (dynamic_cast<Video_feedback*>(f))->set_feedback(&(video_output->image)); + } return video_output->render(duration,framerate,output_filename,audio_filename,progress,outW,outH); } @@ -167,10 +170,10 @@ bool Graph::parseJson(string &data,string &media_path){ for (int l=0;l<jnodes[i]["parameters"].size();l++){ string parameter=jnodes[i]["parameters"][l]["name"].asString(); - /* + if (nodes[nodeID]->parameters.find(parameter)!=nodes[nodeID]->parameters.end()) { - string val=jnodes[i]["parameters"][l]["value"].asString(); - if (val!="") nodes[nodeID]->parameters.find(parameter)->second->value=ofToFloat(val); + float val=jnodes[i]["parameters"][l]["value"].asFloat(); + nodes[nodeID]->parameters.find(parameter)->second->value=val; string fromID=jnodes[i]["parameters"][l]["from"].asString(); if (nodes.find(fromID)!=nodes.end()) { if (!nodes[nodeID]->parameters[parameter]->connect(nodes[fromID])){ @@ -181,8 +184,8 @@ bool Graph::parseJson(string &data,string &media_path){ } else if (fromID!="") cerr << "Rotor: linking parameter " << parameter << " of node: '" << nodeID << "', cannot find target '" << fromID << "'" << endl; } - else cerr << "Rotor: cannot find parameter input '" << parameter << "' of "<<settings["type"]<<" "<< nodeID << endl; - */ + else cerr << "Rotor: cannot find parameter '" << parameter << "' of "<<settings["type"]<<" "<< nodeID << endl; + } // diff --git a/rotord/src/nodes_filters.h b/rotord/src/nodes_filters.h index 0cc1d77..4e2826f 100644 --- a/rotord/src/nodes_filters.h +++ b/rotord/src/nodes_filters.h @@ -12,7 +12,7 @@ namespace Rotor { create_parameter("size","number","Blur window size","Size",1.0f); create_image_input("image input","Image input"); }; - Blur(map<string,string> &settings) { + Blur(map<string,string> &settings):Blur() { base_settings(settings); }; ~Blur(){ @@ -48,7 +48,7 @@ namespace Rotor { base_settings(settings); } ~Luma_levels(){if (LUT) { delete[] LUT;} }; - void generate_LUT(){ + void generate_LUT(){ //can check here if anything has changed if (LUT) delete[] LUT; LUT=new unsigned char[256]; @@ -227,7 +227,7 @@ namespace Rotor { delete[] LUT; } }; - void generate_LUT(){ + void generate_LUT(){ //can check here if anything has changed if (LUT) { for (int i=0;i<3;i++) { @@ -264,6 +264,9 @@ namespace Rotor { out.RGBdata[i*3+1]=LUT[1][in.RGBdata[i*3+1]]; out.RGBdata[i*3+2]=LUT[2][in.RGBdata[i*3+2]]; } + if (!in.alpha.empty()){ + out.alpha=in.alpha; + } } Image *output(const Frame_spec &frame){ Image *in=image_inputs[0]->get(frame); @@ -280,4 +283,4 @@ namespace Rotor { } -#endif
\ No newline at end of file +#endif diff --git a/rotord/src/nodes_maths.h b/rotord/src/nodes_maths.h index eb685eb..760040d 100644 --- a/rotord/src/nodes_maths.h +++ b/rotord/src/nodes_maths.h @@ -61,12 +61,14 @@ namespace Rotor { #define ARITHMETIC_cos 8 #define ARITHMETIC_ease 9 #define ARITHMETIC_jolt 10 +#define ARITHMETIC_floor 11 +#define ARITHMETIC_2pow 12 class Arithmetic: public Signal_node { public: Arithmetic(){ create_signal_input("signal","Signal"); create_parameter("value","number","Value or signal for operation","Value",1.0f); - create_attribute("operator","operator for image","Operator","+",{"+","-","*","/","%","^","sin","cos","ease","jolt"}); + create_attribute("operator","operator for image","Operator","+",{"+","-","*","/","%","^","sin","cos","ease","jolt","floor","2pow"}); title="Arithmetic"; description="Performs arithmetic on a signal with a signal or value"; }; @@ -116,6 +118,12 @@ namespace Rotor { case ARITHMETIC_jolt: return ((1.0-parameters["value"]->value)*in)+(parameters["value"]->value*(0.5f+((sin((fmod(in,1.0f)+1.0f)*M_PI))*0.5f))); break; + case ARITHMETIC_floor: + return floor(in); + break; + case ARITHMETIC_2pow: + return pow(2,in); + break; } } } diff --git a/rotord/src/rotor.cpp b/rotord/src/rotor.cpp index 8883a71..8b52301 100755 --- a/rotord/src/rotor.cpp +++ b/rotord/src/rotor.cpp @@ -43,6 +43,7 @@ Node_factory::Node_factory(){ //video nodes add_type("video_loader",new Video_loader()); add_type("video_output",new Video_output()); + add_type("video_feedback",new Video_feedback()); } bool Signal_input::connect(Node* source) { connection=dynamic_cast<Signal_node*>(source); diff --git a/rotord/src/rotor.h b/rotord/src/rotor.h index 2549683..da1ac8a 100755 --- a/rotord/src/rotor.h +++ b/rotord/src/rotor.h @@ -257,7 +257,7 @@ namespace Rotor { lut=nullptr; }; ~LUT(){if (lut) { delete[] lut;} }; - void generate(float black_in,float white_in,float black_out,float white_out,float gamma){ + void generate(float black_in,float white_in,float black_out,float white_out,float gamma){ //can check here if anything has changed if (lut) delete[] lut; lut=new unsigned char[256]; @@ -434,14 +434,14 @@ namespace Rotor { Image *output(const Frame_spec &frame){ if (palette.size()) { int col=((int)inputs[0]->get((Time_spec)frame))%palette.size(); - if (col!=prevcol){ //how about when starting a new render? + //if (col!=prevcol){ //how about when starting a new render? for (int i=0;i<image.w*image.h;i++){ image.RGBdata[i*3]=palette[col].r; image.RGBdata[i*3+1]=palette[col].g; image.RGBdata[i*3+2]=palette[col].b; } prevcol=col; - } + //} return ℑ } return nullptr; @@ -679,6 +679,11 @@ namespace Rotor { } private: }; + #define TRANSFORM_nearest 1 + #define TRANSFORM_linear 2 + #define TRANSFORM_area 3 + #define TRANSFORM_cubic 4 + #define TRANSFORM_lanczos 5 class Transform: public Image_node { //what is the best coordinate system to use? //origin: corner or centre @@ -693,6 +698,7 @@ namespace Rotor { create_parameter("originY","number","Y transformation origin","Origin Y",0.5f); create_parameter("rotation","number","Rotation about origin","Rotation",0.0f); create_parameter("scale","number","Scale about origin","Scale",1.0f); + create_attribute("filter","Filtering mode","Filter mode","linear",{"nearest","linear","area","cubic","lanczos"}); title="Transform"; description="Apply 2D transformation"; }; @@ -705,6 +711,25 @@ namespace Rotor { Image *output(const Frame_spec &frame){ Image *in=image_inputs[0]->get(frame); if (in){ + int filtmode; + switch(attributes["filter"]->intVal){ + case TRANSFORM_nearest: + filtmode=cv::INTER_NEAREST; + break; + case TRANSFORM_linear: + filtmode=cv::INTER_LINEAR; + break; + case TRANSFORM_area: + filtmode=cv::INTER_AREA; + break; + case TRANSFORM_cubic: + filtmode=cv::INTER_CUBIC; + break; + case TRANSFORM_lanczos: + filtmode=cv::INTER_LANCZOS4; + break; + } + float tX=parameters["transformX"]->value; float tY=parameters["transformY"]->value; float oX=parameters["originX"]->value; @@ -732,7 +757,7 @@ namespace Rotor { dstTri[i].y=srcTri[i].y+(tY*in->h); } trans_mat=getAffineTransform( srcTri, dstTri ); - warpAffine( in->rgb, inter.rgb, trans_mat, inter.rgb.size(), cv::INTER_LINEAR, cv::BORDER_WRAP); + warpAffine( in->rgb, inter.rgb, trans_mat, inter.rgb.size(), filtmode, cv::BORDER_WRAP); // Compute rotation matrix @@ -742,7 +767,8 @@ namespace Rotor { rot_mat = getRotationMatrix2D( centre, r, s ); // Do the transformation // - warpAffine( inter.rgb, image.rgb, rot_mat, image.rgb.size(), cv::INTER_LINEAR, cv::BORDER_WRAP); + + warpAffine( inter.rgb, image.rgb, rot_mat, image.rgb.size(), filtmode, cv::BORDER_WRAP); //BORDER_WRAP //INTER_NEAREST - a nearest-neighbor interpolation @@ -793,49 +819,123 @@ namespace Rotor { 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); + create_parameter("threshold","number","Difference threshold","Threshold",0.2f,0.0f,1.0f); + create_parameter("feather","number","Feather width","Feather",0.1f,0.0f,1.0f); + create_parameter("weight_h","number","H component weight","Weight H",0.5f,0.0f,1.0f); + create_parameter("weight_s","number","S component weight","Weight S",0.5f,0.0f,1.0f); + create_parameter("weight_v","number","V component weight","Weight V",0.5f,0.0f,1.0f); + create_parameter("blursize","number","Blur size","Blur size",2.0f,0.0f,10.0f); create_attribute("mode","Output {image|alpha}","output mode","alpha",{"image","alpha"}); title="Difference matte"; description="Create an alpha channel using a background reference picture"; + LUT=nullptr; }; Difference_matte(map<string,string> &settings):Difference_matte() { base_settings(settings); }; - ~Difference_matte(){}; + ~Difference_matte(){if (LUT) delete[] LUT;}; 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){ Image *in2=image_inputs[1]->get(frame); if (in2) { - + generate_LUT(); + + /* cv::cvtColor(in1->rgb,greyfg,CV_RGB2GRAY); cv::cvtColor(in2->rgb,greybg,CV_RGB2GRAY); cv::absdiff(greyfg,greybg,greyDiff); //parameters["threshold"]->value cv::threshold(greyDiff,mask,parameters["threshold"]->value,255,CV_THRESH_BINARY); //int block_size=3, double param1=5); //int blockSize, int offset=0,bool invert=false, bool gauss=false); - + //cv::adaptiveThreshold(greyDiff,mask,255,CV_ADAPTIVE_THRESH_GAUSSIAN_C,CV_THRESH_BINARY, 3,5); //int block_size=3, double param1=5); //int blockSize, int offset=0,bool invert=false, bool gauss=false); + */ + + cv::cvtColor(in1->rgb, hsv1, CV_RGB2HSV); + cv::cvtColor(in2->rgb, hsv2, CV_RGB2HSV); + + mask.create(frame.h,frame.w,CV_8UC1); + lutmask.create(frame.h,frame.w,CV_8UC1); + + //get euclidean distance in HSV space + int dist,d; + uint8_t m; + + float weights[3] = {parameters["weight_h"]->value,parameters["weight_s"]->value,parameters["weight_v"]->value}; + float weight_total=255.0f/pow(pow(weights[0]*255,2)+pow(weights[1]*255,2)+pow(weights[2]*255,2),0.5); + + for (int i=0;i<frame.w*frame.h;i++){ + dist=0; + for (int j=0;j<3;j++){ + d=((int)hsv1.data[i*3+j])-((int)hsv2.data[i*3+j]); + dist+=(d*d)*weights[j]; + } + uint8_t id=(uint8_t)(sqrt((float)dist)*weight_total); + mask.data[i]=id; + } + + /* + + for (int i=0;i<frame.w*frame.h;i++){ + dist=0; + for (int j=0;j<3;j++){ + d=((int)hsv1.data[i*3+j])-((int)hsv2.data[i*3+j]); + dist+=(abs(d))*weights[j]; + } + uint8_t id=(uint8_t)(((float)dist)/weight_total); + m=LUT[id]; + mask.data[i]=m; + } + */ + + //cv::bilateralFilter(mask,filtmask, 4,8,2 ); + //cv::GaussianBlur(mask,filtmask,cv::Size( 4, 4 ), 2, 2); + + int ksize=max((ceil(parameters["blursize"]->value/2.0)*2)+1,1.0); + //nb this doesn't do the intended: create 'continuously variable' blur + cv::GaussianBlur(mask,filtmask,cvSize(ksize,ksize),parameters["blursize"]->value); + + + for (int i=0;i<frame.w*frame.h;i++){ + lutmask.data[i]=LUT[filtmask.data[i]]; + } + + image=(*in1); if (attributes["mode"]->value=="image"){ - image.setup_fromMat(mask); + cv::cvtColor(lutmask, image.rgb, CV_GRAY2RGB); } - else image.alpha_from_cv(mask); + else image.alpha_from_cv(lutmask); return ℑ - - //cv::cvtColor(in1->rgb, hsv1, CV_RGB2HSV); - //cv::cvtColor(in2->rgb, hsv2, CV_RGB2HSV); - + + + } //if there aren't 2 image inputs connected just return the first return in1; } return nullptr; } + void generate_LUT(){ + //can check here if anything has changed + //cerr<<"generating LUT: threshold "<<parameters["threshold"]->value<<", feather "<<parameters["feather"]->value<<endl; + if (LUT) delete[] LUT; + LUT=new uint8_t[256]; + float fltmax=(255.0f/256.0f); + float minf=max(0.0f,parameters["threshold"]->value-(parameters["feather"]->value*0.5f)); + float maxf=min(1.0f,parameters["threshold"]->value+(parameters["feather"]->value*0.5f)); + for (int i=0;i<256;i++){ + LUT[i]=(uint8_t)(min(1.0f,max(0.0f,((((float)i)/255.0f)-minf)/(maxf-minf)))*255.0f); + // cerr<<((int)LUT[i])<<" "; + } + //cerr<<endl; + } private: - cv::Mat greyfg,greybg,greyDiff,mask; + cv::Mat greyfg,greybg,greyDiff,mask,filtmask,lutmask; cv::Mat hsv1,hsv2; + uint8_t *LUT; }; #define VIDEOFRAMES_frame 1 #define VIDEOFRAMES_blend 2 @@ -878,7 +978,14 @@ namespace Rotor { }; ~Video_output(){ }; Image *output(const Frame_spec &frame){ - return image_inputs[0]->get(frame); + Image *in=image_inputs[0]->get(frame); + if (in){ + //make copy of the image, for feedback + //optimise? + image=(*in); + return ℑ + } + return nullptr; }; Video_output* clone(map<string,string> &_settings) { return new Video_output(_settings);}; bool render(const float duration, const float framerate,const string &output_filename,const string &audio_filename,float& progress,int w,int h); @@ -886,6 +993,32 @@ namespace Rotor { private: }; + class Video_feedback: public Image_node { + public: + Video_feedback(){ + title="Video feedback"; + description="Repeats output of the last frame"; + feedback=nullptr; + }; + Video_feedback(map<string,string> &settings):Video_feedback() { + base_settings(settings); + }; + ~Video_feedback(){ }; + void set_feedback(Image *iptr){ + feedback=iptr; + } + Image *output(const Frame_spec &frame){ + if (feedback->RGBdata){ + return feedback; + } + image.setup(frame.w,frame.h); + image.clear(); + return ℑ + }; + Video_feedback* clone(map<string,string> &_settings) { return new Video_feedback(_settings);}; + private: + Image *feedback; + }; //------------------------------------------------------------------- class Node_factory{ public: @@ -983,7 +1116,7 @@ namespace Rotor { if (type.second->description!="") { //blank description = internal/ testing node list_node(type,XML,i); i++; - } + } } } void list_nodes(Json::Value &JSON){ @@ -1051,7 +1184,7 @@ namespace Rotor { } } JSON["nodeslist"].append(node); - } + } } } private: |
