summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rotord/cvimage.cpp62
-rw-r--r--rotord/cvimage.h3
-rwxr-xr-xrotord/rotor.cpp5
-rwxr-xr-xrotord/rotor.h36
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: