From bb6498e5ff6a8a8af8c06300dac051659a37e89b Mon Sep 17 00:00:00 2001 From: Tim Redfern Date: Thu, 22 May 2014 08:36:24 +0100 Subject: NT figuring out type system --- NT/src/cvimage.cpp | 252 +++++++++++++++++++++++++++++++++++ NT/src/cvimage.h | 302 ++++++++++++++++++++++++++++++++++++++++++ NT/src/nodes.h | 41 +++--- NT/src/nodes_audio_analysis.h | 10 +- NT/src/nodes_source.h | 77 +++++++++++ NT/src/rotor.h | 5 +- 6 files changed, 664 insertions(+), 23 deletions(-) create mode 100644 NT/src/cvimage.cpp create mode 100644 NT/src/cvimage.h create mode 100644 NT/src/nodes_source.h (limited to 'NT') 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 "< ichans,ochans; + vector 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>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 "<>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 "<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 +#include +#include +#include + +//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]=ji?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<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;iRGBdata[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 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 { - public: - Double_node(){}; - }; - class Time: public Double_node { + typedef Node_type Number_node; + typedef Node_type String_node; + typedef Node_type Image_node; + + typedef Variable_type Number_inlet; + typedef Variable_type String_inlet; + typedef Variable_type Image_inlet; + + typedef Variable_array_type Number_array; + typedef Variable_array_type String_array; + typedef Variable_array_type 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 *factors; - double result; - }; - class String_node: public Node_type { - 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 *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("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 &settings):Signal_colour() { + base_settings(settings); + for (uint32_t i=0;ivalue.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 "< &_settings) { return new Signal_colour(_settings);}; + private: + vector 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 &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 &_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 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*>(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 }; } -- cgit v1.2.3