diff options
| author | Tim Redfern <tim@eclectronics.org> | 2014-05-22 08:36:24 +0100 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2014-05-22 08:36:24 +0100 |
| commit | bb6498e5ff6a8a8af8c06300dac051659a37e89b (patch) | |
| tree | 873cd3f3eba85e38c12995b077ce0db9ee82afab | |
| parent | ebc874413991fbc3d07493ece55f88f23e437af6 (diff) | |
NT figuring out type system
| -rw-r--r-- | NT/src/cvimage.cpp | 252 | ||||
| -rw-r--r-- | NT/src/cvimage.h | 302 | ||||
| -rw-r--r-- | NT/src/nodes.h | 41 | ||||
| -rw-r--r-- | NT/src/nodes_audio_analysis.h | 10 | ||||
| -rw-r--r-- | NT/src/nodes_source.h | 77 | ||||
| -rw-r--r-- | NT/src/rotor.h | 5 |
6 files changed, 664 insertions, 23 deletions
diff --git a/NT/src/cvimage.cpp b/NT/src/cvimage.cpp new file mode 100644 index 0000000..b255848 --- /dev/null +++ b/NT/src/cvimage.cpp @@ -0,0 +1,252 @@ +#include "cvimage.h" + +using namespace std; + +namespace Rotor { + //space out to 32 bit RGB padding for cairo + void Image::convert24(){ + cv::cvtColor(rgb,rgb, CV_RGBA2RGB); + } + void Image::convert32(){ + cv::cvtColor(rgb,rgb, CV_RGB2RGBA); + } + 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; + } + else { + rgb+=other.rgb; + } + return *this; + } + Image & Image::operator*=(const Image &other) { + if (other.w!=w||other.h!=h) { + cerr<<"Rotor: cannot multiply images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl; + } + else { + //rgb/=other.rgb; //does funny glitchy stuff + //could use cv::Mat.mul() here + for (int i=0;i<w*h*3;i++){ + //calculate with tables + rgb.data[i]=pixels.multiply[rgb.data[i]][other.rgb.data[i]]; + } + } + return *this; + } + 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; + } + else { + rgb^=other.rgb; + } + return *this; + } + Image & Image::add_wrap(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; + } + else { + for (int i=0;i<w*h*3;i++){ + //creates rainbow overload, openCV doesn't do this + rgb.data[i]=(unsigned char)(((int)other.rgb.data[i]+(int)rgb.data[i])); + } + } + return *this; + } + Image & Image::divide_wrap(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; + } + else { + for (int i=0;i<w*h*3;i++){ + //creates rainbow overload, openCV doesn't do this + rgb/=other.rgb; //does funny glitchy stuff + } + } + return *this; + } + //THIS OPENCV VERSION IS SLOWER THAN THE OLDSKOOL VERSION BELOW + Image & Image::alpha_blend_cv(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; + for (int i=0;i<3;i++) { + compchans.push_back(ichans[i].mul(iA,1.0/255.0)+ochans[i].mul(other.alpha,1.0/255.0)); + } + 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-other.alpha.data[i/3]))>>8)+((((int)other.rgb.data[i])*((int)other.alpha.data[i/3]))>>8)); + //} + } + + 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 { + for (int i=0;i<w*h*3;i++) { + rgb.data[i]=(uint8_t)(((((int)rgb.data[i])*(0xFF-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 { + cv::cvtColor(other.rgb,alpha,CV_RGB2GRAY); + } + return *this; + } + Image & Image::alpha_from_cv(cv::Mat &other){ + //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 { + if (other.channels()==1) { + alpha=other; + } + else cv::cvtColor(other,alpha,CV_RGB2GRAY); + //} + return *this; + } + Image & Image::overlay(const Image &other){ + if (other.w!=w||other.h!=h) { + cerr<<"Rotor: cannot overlay images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl; + //why not?? + } + else { + for (int i=0;i<h*w*3;i++) { + rgb.data[i]=pixels.overlay[rgb.data[i]][other.rgb.data[i]]; + } + } + return *this; + } + Image & Image::min(const Image &other) { + if (other.w!=w||other.h!=h) { + cerr<<"Rotor: cannot min images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl; + } + else { + for (int i=0;i<w*h*3;i++){ + //calculate with tables + rgb.data[i]=pixels.min[rgb.data[i]][other.rgb.data[i]]; + } + } + return *this; + } + Image & Image::max(const Image &other) { + if (other.w!=w||other.h!=h) { + cerr<<"Rotor: cannot min images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl; + } + else { + for (int i=0;i<w*h*3;i++){ + //calculate with tables + rgb.data[i]=pixels.max[rgb.data[i]][other.rgb.data[i]]; + } + } + return *this; + } + Image & Image::operator=(const Image &other) { + //can be optimised? was trying to use other.data.clone() + if (setup(other.w,other.h)){ + //for (int i=0;i<h*w*3;i++) { + // rgb.data[i]=other.rgb.data[i]; + //} + memcpy(rgb.data,other.rgb.data,h*w*3); //saves ~2.4 ms copying a 640x360 image + + } + 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 + Image & Image::operator*=(const double &amount) { + //cerr<<"amount: "<<amount<<endl; + //rgb*=amount; + uint8_t amt=(uint8_t)(amount*255.0); + for (int i=0;i<h*w*3;i++) { + rgb.data[i]=pixels.multiply[rgb.data[i]][amt]; + } + //again this is faster + return *this; + } + Image & Image::operator+=(const double &amount) { + rgb+=(amount*255.0); + return *this; + } + Image & Image::operator-=(const double &amount) { + rgb-=(amount*255.0); + return *this; + } + Image & Image::operator/=(const double &amount) { + rgb/=amount; + return *this; + } + Image * Image::operator*(const double &amount) { + //LEAK!! even if the image is deleted!! opencv?? + Image *other=new Image(w,h); + other->rgb=rgb*amount; + return other; + } + Image * Image::operator+(const double &amount) { + uint8_t amt=(uint8_t)(amount*255.0); + Image *other=new Image(w,h); + other->rgb=rgb+amt; + return other; + } + Image * Image::operator-(const double &amount) { + uint8_t amt=(uint8_t)(amount*255.0); + Image *other=new Image(w,h); + other->rgb=rgb-amt; + return other; + } + Image * Image::operator/(const double &amount) { + Image *other=new Image(w,h); + other->rgb=rgb/amount; + return other; + } + cv::Mat& Image::get_mipmap(int level){ + if (mipmaps.find(level)!=mipmaps.end()) return mipmaps[level]; + //levels start at 1 + int nw=std::max(1.0,w/pow(2,level)); + int nh=std::max(1.0,h/pow(2,level)); + cv::Mat mip;; + cv::resize(rgb,mip,cv::Size(nw,nh),0,0,cv::INTER_AREA ); + mipmaps[level]=mip; + return mipmaps[level]; + + } +} diff --git a/NT/src/cvimage.h b/NT/src/cvimage.h new file mode 100644 index 0000000..d3f824c --- /dev/null +++ b/NT/src/cvimage.h @@ -0,0 +1,302 @@ +#ifndef ROTOR_CVIMAGE +#define ROTOR_CVIMAGE + +#include <math.h> +#include <cv.h> +#include <highgui.h> +#include <unordered_map> + +//converting to use a cv image... +//cv::Mat supports most of what we want here +//need to think +//http://answers.opencv.org/question/8202/using-external-image-data-in-a-cvmat/ + +//all access to the image is presently through a pointer to the data +//cv::Mat supports this + +//how will copying work? +//Rotor::Image will contain a cv::Mat object which may own its data or inherit it +//cv::Mat should take care of reference counting + +//can cv::Mat + +namespace Rotor { + class pixeltables{ + //handy pixel arithmetic lookup tables as nested arrays + //so - pixels.add[0x78][0x66]; will give the precalculated result of adding with saturation + // pixels.mono_weights[0][0x100]; will give the red component to convert to mono + public: + pixeltables(){ + add=new uint8_t*[256]; + multiply=new uint8_t*[256]; + overlay=new uint8_t*[256]; + min=new uint8_t*[256]; + max=new uint8_t*[256]; + for (int i=0;i<256;i++){ + add[i]=new uint8_t[256]; + multiply[i]=new uint8_t[256]; + overlay[i]=new uint8_t[256]; + min[i]=new uint8_t[256]; + max[i]=new uint8_t[256]; + for (int j=0;j<256;j++){ + add[i][j]=(uint8_t)std::min(i+j,0xFF); + multiply[i][j]=(uint8_t)(((double)i)*(((double)j)/255.0)); + overlay[i][j]=j<128?(uint8_t)((i*j)>>7):255-(((0xFF-i)*(0xFF-j))>>7); + min[i][j]=j<i?j:i; + max[i][j]=j>i?j:i; + } + } + mono_weights=new uint8_t*[3]; + double weights[3]={0.2989, 0.5870, 0.1140}; + for (int i=0;i<3;i++) { + mono_weights[i]=new uint8_t[256]; + for (int j=0;j<256;j++){ + mono_weights[i][j]=(uint8_t)(((double)j)*weights[i]); + } + } + } + virtual ~pixeltables(){ + for (int i=0;i<256;i++){ + delete[] add[i]; + delete[] multiply[i]; + delete[] overlay[i]; + delete[] min[i]; + delete[] max[i]; + } + delete[] add; + delete[] multiply; + delete[] overlay; + delete[] min; + delete[] max; + for (int i=0;i<3;i++) { + delete[] mono_weights[i]; + } + delete[] mono_weights; + } + uint8_t **add; + uint8_t **multiply; + uint8_t **overlay; + uint8_t **mono_weights; + uint8_t **max; + uint8_t **min; + }; + static pixeltables pixels; + class Image{ + //transform should be a method of image + public: + Image(){ + zero(); + }; + Image(int _w,int _h){ + zero(); + setup(_w,_h); + }; + Image(const Image &mom) { + // copy constructor + zero(); + rgb=mom.rgb.clone(); + w=mom.w; + h=mom.h; + RGBdata=rgb.data; //can move to use the bare pointer eventually + ownsRGBdata=false; //always just deallocate cv::Mat from stack + } + ~Image() { + free(); + }; + void free(){ + if (RGBdata&&ownsRGBdata) delete[] RGBdata; + if (Adata&&ownsAdata) delete[] Adata; + if (Zdata&&ownsZdata) delete[] Zdata; + rgb.release(); + alpha.release(); + zero(); + } + void zero(){ + RGBdata=nullptr; + Adata=nullptr; + Zdata=nullptr; + w=0; + h=0; + ownsRGBdata=ownsAdata=ownsZdata=false; + } + //space out to 32 bit RGB padding for cairo + void convert24(); + void convert32(); + int getStride(){ + return w*3; + } + bool clear(){ + rgb.setTo(0); + return true; + }; + bool setup(int _w,int _h){ //set up with internal data + if (_w==0||_h==0||(_w*_h*3)>10000000) { + //some kind of elusive thing that shows up only in non debug builds + std::cerr<<"Error! cvimage: request to set up image at "<<_w<<"x"<<_h<<std::endl; + return false; + } + if ((w!=_w)|(h!=_h)){ + free(); + rgb.create(_h,_w,CV_8UC3); + RGBdata=rgb.data; //can move to use the bare pointer eventually + ownsRGBdata=false; //will not be necessary + w=_w; + h=_h; + } + return true; + /* + if (w!=_w||h!=_h||!ownsRGBdata||!ownsAdata||!ownsZdata){ + free(); + w=_w; + h=_h; + RGBdata=new uint8_t[w*h*3]; + Adata=new uint8_t[w*h]; + Zdata=new uint16_t[w*h]; + ownsRGBdata=ownsAdata=ownsZdata=true; + return true; + } + else return false; + */ + } + bool read_file(std::string &filename){ + rgb=cv::imread(filename,CV_LOAD_IMAGE_COLOR); + if (rgb.empty()) return false; + RGBdata=rgb.data; + ownsRGBdata=false; + w=rgb.rows; + h=rgb.cols; + return true; + } + bool setup_fromRGB(int _w,int _h,uint8_t *pRGBdata,int linepadding=0){ + //here the data belongs to libavcodec or other + //could move to using cv::Mat there also and just passing cv:Mat over + + //linepadding causes crash, but it doesn't seem to be necessary + // Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP) + rgb=cv::Mat(_h,_w,CV_8UC3,pRGBdata,(_w*3)+linepadding); + //std::cerr<<"created cv::Mat with step= "<<rgb.step<<",should be "<<((_w*3)+linepadding)<<std::endl; + + RGBdata=rgb.data; //can move to use the bare pointer eventually + ownsRGBdata=false; //will not be necessary + w=_w; + h=_h; + return true; + /* + if (w!=_w||h!=_h||ownsRGBdata||!ownsAdata||!ownsZdata){ + free(); + w=_w; + h=_h; + RGBdata=pRGBdata; + Adata=new uint8_t[w*h]; + Zdata=new uint16_t[w*h]; + ownsRGBdata=false; + ownsAdata=ownsZdata=true; + return true; + } + return false; + */ + } + bool setup_fromMat(cv::Mat& othermat){ + //here the mat belongs to another object + if (othermat.channels()==1) { + cv::cvtColor(othermat, rgb, CV_GRAY2RGB); + } + else rgb=othermat; + RGBdata=rgb.data; //can move to use the bare pointer eventually + ownsRGBdata=false; //will not be necessary + w=rgb.rows; + h=rgb.cols; + return true; + } + //leaks + Image* clone(){ + Image *t=new Image(); + t->rgb=rgb.clone(); + t->w=w; + t->h=h; + t->RGBdata=t->rgb.data; //can move to use the bare pointer eventually + t->ownsRGBdata=false; //always just deallocate cv::Mat from stack + /* + for (int i=0;i<w*h*3;i++) { + t->RGBdata[i]=RGBdata[i]; + } + */ + return t; + } + void crop(int _w,int _h){ //change borders, crop/ extend, centred + cv::Mat source; + int X,Y,W,H; + //do crop part + if ( _w<w||_h<h){ + //create crop rectangle xywh + X=Y=0; + W=w; + H=h; + if (_w<w){ + W=_w; + X=(w-_w)/2; + w=_w; + } + if (_h<h){ + H=_h; + Y=(h-_h)/2; + h=_h; + } + cv::Mat cropped; + CvRect r=cvRect(X,Y,W,H) ; + rgb(r).copyTo(source); + } + else source=rgb; + copyMakeBorder(source,rgb,(_h-h)/2,(_h-h)/2,(_w-w)/2,(_w-w)/2,cv::BORDER_REPLICATE); + w=rgb.rows; + h=rgb.cols; + } + void resize(int _w,int _h){ + cv::resize(rgb,rgb,cv::Size(_w,_h),0,0,cv::INTER_LINEAR ); + w=rgb.rows; + h=rgb.cols; + } + Image & operator=(const Image &other); + //believe these still work, don't know if these optimisations are better than opencvs.. + Image & operator+=(const Image &other); + Image & operator*=(const Image &other); + Image & operator^=(const Image &other); + Image & alpha_blend(const Image &other); + Image & alpha_blend_cv(const Image &other); + Image & alpha_merge(const Image &other); + Image & alpha_from_cv(cv::Mat &other); + Image & add_wrap(const Image &other); + Image & divide_wrap(const Image &other); + Image & overlay(const Image &other); + Image & min(const Image &other); + Image & max(const Image &other); + Image & operator*=(const double &amount); + Image & operator+=(const double &amount); + Image & operator-=(const double &amount); + Image & operator/=(const double &amount); + Image * operator*(const double &amount); + Image * operator+(const double &amount); + Image * operator-(const double &amount); + Image * operator/(const double &amount); + uint8_t *RGBdata; + uint8_t *Adata; + uint16_t *Zdata; + int h,w; + bool ownsRGBdata,ownsAdata,ownsZdata; //better done through auto_ptr? + + //making the interface for mip mapping + //should reduce in powers of 2 + // + + cv::Mat rgb; + cv::Mat alpha; + + //store a library of mipmaps + std::unordered_map<int,cv::Mat> mipmaps; + + cv::Mat& get_mipmap(int level); + + }; +} + +#endif diff --git a/NT/src/nodes.h b/NT/src/nodes.h index 6bfb6f5..f6a8a0d 100644 --- a/NT/src/nodes.h +++ b/NT/src/nodes.h @@ -7,11 +7,27 @@ using namespace std; namespace Rotor{ - class Double_node: public Node_type<double> { - public: - Double_node(){}; - }; - class Time: public Double_node { + typedef Node_type<double> Number_node; + typedef Node_type<string> String_node; + typedef Node_type<Image> Image_node; + + typedef Variable_type<double> Number_inlet; + typedef Variable_type<string> String_inlet; + typedef Variable_type<Image> Image_inlet; + + typedef Variable_array_type<double> Number_array; + typedef Variable_array_type<string> String_array; + typedef Variable_array_type<Image> Image_array; + + + //colour node could be an alias of vec3f node and they could be interchangeable? + //image node + //vector_image node: supporting scalable images + //image cache types? + //timeline type could get around the big problem with needing to find keyframes + + //basic test nodes + class Time: public Number_node { public: Time(){ type="time"; @@ -24,12 +40,11 @@ namespace Rotor{ init(settings); }; const double &get_output(const Frame_parameters &frame){ - value=frame.time; - return value; + result=frame.time; + return result; } Time* clone(Json::Value &_settings) { return new Time(_settings);}; private: - double value; }; class Multiply: public Double_node { public: @@ -58,12 +73,7 @@ namespace Rotor{ } Multiply* clone(Json::Value &_settings) { return new Multiply(_settings);}; private: - Variable_array_type<double> *factors; - double result; - }; - class String_node: public Node_type<string> { - public: - String_node(){}; + Double_array *factors; }; class Print: public String_node { public: @@ -86,8 +96,7 @@ namespace Rotor{ } Print* clone(Json::Value &_settings) { return new Print(_settings);}; private: - Variable_type<double> *inlet; - std::string result; + Double_inlet *inlet; }; } diff --git a/NT/src/nodes_audio_analysis.h b/NT/src/nodes_audio_analysis.h index 00f4303..6523c71 100644 --- a/NT/src/nodes_audio_analysis.h +++ b/NT/src/nodes_audio_analysis.h @@ -76,18 +76,18 @@ namespace Rotor { if (i->second.values.size()) v1=i->second.values[0]; switch (mode->get()){ case VAMPHOST_Timeline: - value= (((frame.time-lk-lk)/(uk-lk))+ln); + result= (((frame.time-lk-lk)/(uk-lk))+ln); case VAMPHOST_Timesteps: - value= (double)ln; + result= (double)ln; case VAMPHOST_Valueline: - value= ((frame.time-lk)/(uk-lk))+v1; //((((time.time-lk)/(uk-lk))*(v2-v1))+v1); + result= ((frame.time-lk)/(uk-lk))+v1; //((((time.time-lk)/(uk-lk))*(v2-v1))+v1); case VAMPHOST_Values: - value= v1; + result= v1; } //} //return (--features.end())->second.values[0]; } - return value; + return result; } string get_features(); void print_summary(){ diff --git a/NT/src/nodes_source.h b/NT/src/nodes_source.h new file mode 100644 index 0000000..08da163 --- /dev/null +++ b/NT/src/nodes_source.h @@ -0,0 +1,77 @@ +#ifndef ROTOR_NODES_SOURCE +#define ROTOR_NODES_SOURCE + +#include "rotor.h" + +namespace Rotor { + class Signal_colour: public Image_node { + public: + Signal_colour(){ + selector=create_inlet<double>("selector"); + create_attribute("palette","palette list of web colours","Colour palette","000000"); + title="Signal colour"; + description="Cycles through a palette of background colours according to selector signal"; + NODEID="a2183fe0-2d09-11e3-9a64-538ee2cf40bc"; + }; + Signal_colour(map<string,string> &settings):Signal_colour() { + base_settings(settings); + for (uint32_t i=0;i<attributes["palette"]->value.size()/6;i++){ + palette.push_back(Colour(attributes["palette"]->value.substr(i*6,6))); + } + prevcol=-1; + }; + ~Signal_colour(){}; + Image *output(const Frame_spec &frame){ + if (palette.size()) { + int col=((int)inputs[0]->get((Time_spec)frame))%palette.size(); + //if (col!=prevcol) cerr<<"colour now "<<palette[col].r<<","<<palette[col].g<<","<<palette[col].b<<endl; + //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; + } + Signal_colour* clone(map<string,string> &_settings) { return new Signal_colour(_settings);}; + private: + vector<Colour> palette; + int prevcol; + Number_inlet *selector; + }; + class Signal_greyscale: public Image_node { + //Draws signal bars in greyscale + public: + Signal_greyscale(){ + create_signal_input("Signal","Signal input"); + title="Signal greyscale"; + description="Renders signal level as greyscale background"; + NODEID="ae91b8a0-2d09-11e3-aa7d-8b7f1ef1a439"; + }; + Signal_greyscale(map<string,string> &settings):Signal_greyscale() { + base_settings(settings); + prevcol=-1; + }; + ~Signal_greyscale(){}; + Image *output(const Frame_spec &frame){ + uint8_t col=((uint8_t)(inputs[0]->get((Time_spec)frame)*255.0)); + if (col!=prevcol){ //how about when starting a new render? + //for (int i=0;i<image.w*image.h*3;i++){ + // image.RGBdata[i]=col; + //} + prevcol=col; + memset(image.RGBdata,col,image.w*image.h*3); + } + return ℑ + + } + Signal_greyscale* clone(map<string,string> &_settings) { return new Signal_greyscale(_settings);}; + private: + uint8_t prevcol; + }; +} +#endif diff --git a/NT/src/rotor.h b/NT/src/rotor.h index 485ec8c..2ddf3ee 100644 --- a/NT/src/rotor.h +++ b/NT/src/rotor.h @@ -28,6 +28,7 @@ seperate framework? ie in Python- load server- send http commands #include "xmlIO.h" #include "libavwrapper.h" +#include "cvimage.h" #include "Poco/Logger.h" #include "Poco/Channel.h" @@ -330,7 +331,7 @@ namespace Rotor { template <class NT> class Node_type : public Node { public: - virtual const NT& get_output(const Frame_parameters &frame){return value;}; + virtual const NT& get_output(const Frame_parameters &frame){return result;}; void init(Json::Value settings){ if (!settings["vars"].empty()){ for ( uint32_t i = 0; i < settings["vars"].size(); ++i ) { @@ -357,7 +358,7 @@ namespace Rotor { return (dynamic_cast<Variable_array_type<IT>*>(vars[name])); } protected: - NT value; //every node has an internal value so it can return a reference + NT result; //internal value is returned as a reference }; } |
