diff options
| -rw-r--r-- | rotord/cvimage.cpp | 62 | ||||
| -rw-r--r-- | rotord/cvimage.h | 3 | ||||
| -rwxr-xr-x | rotord/rotor.cpp | 5 | ||||
| -rwxr-xr-x | rotord/rotor.h | 36 |
4 files changed, 101 insertions, 5 deletions
diff --git a/rotord/cvimage.cpp b/rotord/cvimage.cpp index 3a070a9..2130fc6 100644 --- a/rotord/cvimage.cpp +++ b/rotord/cvimage.cpp @@ -3,7 +3,6 @@ using namespace std; namespace Rotor { - //believe these still work, don't know if these optimisations are better than opencvs.. Image & Image::operator+=(const Image &other) { if (other.w!=w||other.h!=h) { cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl; @@ -28,12 +27,71 @@ namespace Rotor { } else { for (int i=0;i<w*h*3;i++){ - //creates rainbow overload + //creates rainbow overload, openCV doesn't do this RGBdata[i]=(unsigned char)(((int)other.RGBdata[i]+(int)RGBdata[i])); } } return *this; } + Image & Image::alpha_blend(const Image &other) { + if (other.w!=w||other.h!=h) { + cerr<<"Rotor: cannot blend images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl; + //why not?? + } + else if (!other.alpha.data){ + //default to full on alpha + rgb=other.rgb.clone(); + } + else { + //overlay the other image based on its alpha values + //https://gist.github.com/Brick85/5009046 - this is a dumb way to do it? + //how to invert a matrix? + //'invert' is matrix invert - different + //subtract from a scalar (1) ? + //vector<cv::Mat> ichans,ochans; + //vector<cv::Mat> compchans; + //cv::split(rgb,ichans); + //cv::split(other.rgb,ochans); + //uint8_t b=0xFF; + //cv::Mat iA=b-other.alpha; + //cv::Mat iA=cv::Mat(h,w,CV_8UC1); + //for (int i=0;i<w*h;i++) iA.data[i]=(uint8_t)0xFF-other.alpha.data[i]; + //for (int i=0;i<3;i++) { + // compchans.push_back((ichans[i]/iA)+(ochans[i]/other.alpha)); //.mul(iA,1.0/255.0)); //+ochans[i].mul(other.alpha)); + //} + //merge(compchans,rgb); + //rgb+=other.rgb; + for (int i=0;i<w*h*3;i++) { + rgb.data[i]=(uint8_t)(((((int)rgb.data[i])*(0xFF-((int)other.alpha.data[i/3])))>>8)+((((int)other.rgb.data[i])*((int)other.alpha.data[i/3])>>8))); + + } + } + + return *this; + } + Image & Image::alpha_merge(const Image &other) { + //converts the incoming image to monochrome and inserts it into the alpha channel of this image + if (other.w!=w||other.h!=h) { + cerr<<"Rotor: cannot merge alpha with different size! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl; + } + else { + alpha=cv::Mat(h,w,CV_8UC1); + //cv::cvtColor(other.rgb,alpha,CV_RGB2GRAY); + for (int i=0;i<w*h;i++) { + uint8_t v=0; + for (int j=0;j<3;j++){ + v+=pixels.mono_weights[j][other.rgb.data[i*3+j]]; + } + alpha.data[i]=v; + } + } + return *this; + } + //channel rearrangement + //RGBAZ - these are channels 0-4 + //HSB - can also have these virtual channels 5-7 + //convert channels- int outChannel[5] - {0,1,2,-5,4} - this mapping sends inverted brightness to alpha + //scalar operations allocate a new image. //maybe this could not be the case if the data is owned by this image? //need to look into auto_ptr diff --git a/rotord/cvimage.h b/rotord/cvimage.h index 6c237b4..7935ded 100644 --- a/rotord/cvimage.h +++ b/rotord/cvimage.h @@ -161,6 +161,8 @@ namespace Rotor { Image & operator+=(const Image &other); Image & operator*=(const Image &other); Image & add_wrap(const Image &other); + Image & alpha_blend(const Image &other); + Image & alpha_merge(const Image &other); Image & operator*=(const float &amount); Image * operator*(const float &amount); Image * operator+(const float &amount); @@ -173,5 +175,6 @@ namespace Rotor { bool ownsRGBdata,ownsAdata,ownsZdata; //better done through auto_ptr? cv::Mat rgb; + cv::Mat alpha; }; } diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp index 90d23d9..a1163fe 100755 --- a/rotord/rotor.cpp +++ b/rotord/rotor.cpp @@ -30,6 +30,7 @@ Node_factory::Node_factory(){ add_type("mirror",new Mirror()); add_type("monochrome",new Monochrome()); add_type("transform",new Transform()); + add_type("alpha_merge",new Alpha_merge()); } bool Signal_input::connect(Signal_node* source) { @@ -39,7 +40,7 @@ bool Signal_input::connect(Signal_node* source) { } else return false; } -void Parameter_input::update(const Time_spec& time){ //gets input and updates variable +void Parameter_input::update(const Time_spec& time){ //gets input and updates variable if (receiver){ *receiver=((Signal_node*)connection)->get_output(time); } @@ -51,7 +52,7 @@ bool Image_input::connect(Image_node* source) { } else return false; } -void Node::update_params(const Time_spec& time){ //compute connected parameters +void Node::update_params(const Time_spec& time){ //compute connected parameters for (auto p:parameter_inputs){ p->update(time); } diff --git a/rotord/rotor.h b/rotord/rotor.h index f630391..1f4c423 100755 --- a/rotord/rotor.h +++ b/rotord/rotor.h @@ -1005,6 +1005,7 @@ namespace Rotor { #define BLEND_screen 1 #define BLEND_multiply 2 #define BLEND_blend 3 + #define BLEND_alpha 4 class Blend: public Image_node { public: Blend(){image=nullptr;}; @@ -1016,6 +1017,7 @@ namespace Rotor { if (_mode=="screen") mode=BLEND_screen; if (_mode=="multiply") mode=BLEND_multiply; if (_mode=="blend") mode=BLEND_blend; + if (_mode=="alpha") mode=BLEND_alpha; }; void link_params() { for (auto p:parameter_inputs){ @@ -1039,12 +1041,16 @@ namespace Rotor { case BLEND_multiply: (*image)*=(*(((Image_node*)image_inputs[1]->connection)->get_output(frame))); break; - case BLEND_blend: + case BLEND_alpha: + (*image)=(*image).alpha_blend(*(((Image_node*)image_inputs[1]->connection)->get_output(frame))); + break; + case BLEND_blend: //has to be last because of initialser of *in? go figure (*image)*=(1.0f-amount); Image *in=(*(((Image_node*)image_inputs[1]->connection)->get_output(frame)))*amount; (*image)+=(*in); delete in; break; + } return image; } @@ -1246,6 +1252,34 @@ namespace Rotor { float tX,tY,oX,oY,r,s; //todo - quality settings }; + class Alpha_merge: public Image_node { + public: + Alpha_merge(){image=nullptr;}; + Alpha_merge(map<string,string> &settings) { + base_settings(settings); + }; + ~Alpha_merge(){ if (image) delete image;}; + Alpha_merge* clone(map<string,string> &_settings) { return new Alpha_merge(_settings);}; + Image *output(const Frame_spec &frame){ + if (image_inputs.size()) { + if (image_inputs[0]->connection){ + //copy incoming image **writable + if (image) delete image; + image=(((Image_node*)image_inputs[0]->connection)->get_output(frame))->clone(); + if (image_inputs.size()>1) { + if (image_inputs[1]->connection) { + image->alpha_merge(*((Image_node*)image_inputs[0]->connection)->get_output(frame)); + } + } + //if there aren't 2 image inputs connected just return the first + return image; + } + } + return nullptr; + } + private: + Image *image; //is an image generator + }; //------------------------------------------------------------------- class Node_factory{ public: |
