summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rotord/src/nodes_transform.h315
-rwxr-xr-xrotord/src/rotor.cpp7
-rwxr-xr-xrotord/src/rotor.h156
3 files changed, 337 insertions, 141 deletions
diff --git a/rotord/src/nodes_transform.h b/rotord/src/nodes_transform.h
new file mode 100644
index 0000000..b7314bf
--- /dev/null
+++ b/rotord/src/nodes_transform.h
@@ -0,0 +1,315 @@
+#ifndef ROTOR_TRANSFORMS
+#define ROTOR_TRANSFORMS
+
+#include "rotor.h"
+
+namespace Rotor {
+ #define TRANSFORM_nearest 1
+ #define TRANSFORM_linear 2
+ #define TRANSFORM_area 3
+ #define TRANSFORM_cubic 4
+ #define TRANSFORM_lanczos 5
+ class Transformer: public Image_node {
+ //base class for nodes that transform
+ //what is the best coordinate system to use?
+ //origin: corner or centre
+ //units: pixel or fractional
+ //aspect: scaled or homogenous
+ public:
+ Transformer(){
+ create_parameter("transformX","number","X transformation","Transform X",0.0f);
+ create_parameter("transformY","number","Y transformation","Transform X",0.0f);
+ create_parameter("originX","number","X transformation origin","Origin X",0.5f);
+ 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"});
+ };
+ Transformer(map<string,string> &settings):Transformer() {
+ base_settings(settings);
+ };
+ ~Transformer(){
+ };
+ Transformer* clone(map<string,string> &_settings) { return new Transformer(_settings);};
+ 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;
+ float oY=parameters["originY"]->value;
+ float r=parameters["rotation"]->value;
+ float s=parameters["scale"]->value;
+
+ //do opencv transform
+ cv::Point2f srcTri[3], dstTri[3];
+ cv::Mat rot_mat(2,3,CV_32FC1);
+ cv::Mat trans_mat(2,3,CV_32FC1);
+
+ Image inter;
+ inter.setup(in->w,in->h);
+ // Compute matrix by creating triangle and transforming
+ //is there a better way - combine the 2? Just a bit of geometry
+ srcTri[0].x=0;
+ srcTri[0].y=0;
+ srcTri[1].x=in->w-1;
+ srcTri[1].y=0;
+ srcTri[2].x=0;
+ srcTri[2].y=in->h-1;
+ for (int i=0;i<3;i++){
+ dstTri[i].x=srcTri[i].x+(tX*in->w);
+ dstTri[i].y=srcTri[i].y+(tY*in->h);
+ }
+ trans_mat=getAffineTransform( srcTri, dstTri );
+ warpAffine( in->rgb, inter.rgb, trans_mat, inter.rgb.size(), filtmode, cv::BORDER_WRAP);
+
+
+ // Compute rotation matrix
+ //
+ cv::Point centre = cv::Point( oX*in->w, oY*in->h );
+
+ rot_mat = getRotationMatrix2D( centre, r, s );
+ // Do the transformation
+ //
+
+ warpAffine( inter.rgb, image.rgb, rot_mat, image.rgb.size(), filtmode, cv::BORDER_WRAP);
+ //BORDER_WRAP
+
+ //INTER_NEAREST - a nearest-neighbor interpolation
+ //INTER_LINEAR - a bilinear interpolation (used by default)
+ //INTER_AREA - resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method.
+ //INTER_CUBIC - a bicubic interpolation over 4x4 pixel neighborhood
+ //INTER_LANCZOS4 - a Lanczos interpolation over 8x8 pixel neighborhood
+
+ return &image;
+ }
+ return nullptr;
+ }
+ private:
+ };
+ class Transform: public Image_node {
+ //what is the best coordinate system to use?
+ //origin: corner or centre
+ //units: pixel or fractional
+ //aspect: scaled or homogenous
+ public:
+ Transform(){
+ create_image_input("image input","Image input");
+ create_parameter("transformX","number","X transformation","Transform X",0.0f);
+ create_parameter("transformY","number","Y transformation","Transform X",0.0f);
+ create_parameter("originX","number","X transformation origin","Origin X",0.5f);
+ 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";
+ };
+ Transform(map<string,string> &settings):Transform() {
+ base_settings(settings);
+ };
+ ~Transform(){
+ };
+ Transform* clone(map<string,string> &_settings) { return new Transform(_settings);};
+ 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;
+ float oY=parameters["originY"]->value;
+ float r=parameters["rotation"]->value;
+ float s=parameters["scale"]->value;
+
+ //do opencv transform
+ cv::Point2f srcTri[3], dstTri[3];
+ cv::Mat rot_mat(2,3,CV_32FC1);
+ cv::Mat trans_mat(2,3,CV_32FC1);
+
+ Image inter;
+ inter.setup(in->w,in->h);
+ // Compute matrix by creating triangle and transforming
+ //is there a better way - combine the 2? Just a bit of geometry
+ srcTri[0].x=0;
+ srcTri[0].y=0;
+ srcTri[1].x=in->w-1;
+ srcTri[1].y=0;
+ srcTri[2].x=0;
+ srcTri[2].y=in->h-1;
+ for (int i=0;i<3;i++){
+ dstTri[i].x=srcTri[i].x+(tX*in->w);
+ dstTri[i].y=srcTri[i].y+(tY*in->h);
+ }
+ trans_mat=getAffineTransform( srcTri, dstTri );
+ warpAffine( in->rgb, inter.rgb, trans_mat, inter.rgb.size(), filtmode, cv::BORDER_WRAP);
+
+
+ // Compute rotation matrix
+ //
+ cv::Point centre = cv::Point( oX*in->w, oY*in->h );
+
+ rot_mat = getRotationMatrix2D( centre, r, s );
+ // Do the transformation
+ //
+
+ warpAffine( inter.rgb, image.rgb, rot_mat, image.rgb.size(), filtmode, cv::BORDER_WRAP);
+ //BORDER_WRAP
+
+ //INTER_NEAREST - a nearest-neighbor interpolation
+ //INTER_LINEAR - a bilinear interpolation (used by default)
+ //INTER_AREA - resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method.
+ //INTER_CUBIC - a bicubic interpolation over 4x4 pixel neighborhood
+ //INTER_LANCZOS4 - a Lanczos interpolation over 8x8 pixel neighborhood
+
+ return &image;
+ }
+ return nullptr;
+ }
+ private:
+ };
+ //Transform and Still could inherit from a transformer node
+ class Still_image: public Image_node {
+ public:
+ Still_image(){
+ create_parameter("transformX","number","X transformation","Transform X",0.0f);
+ create_parameter("transformY","number","Y transformation","Transform X",0.0f);
+ create_parameter("originX","number","X transformation origin","Origin X",0.5f);
+ 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"});
+ create_attribute("filename","name of image file to load","File name","");
+ title="Still image";
+ description="Load a still image and apply 2D transformation";
+ };
+ Still_image(map<string,string> &settings):Still_image() {
+ base_settings(settings);
+ if (attributes["filename"]->value!=""){
+ string filewithpath=find_setting(settings,"media_path","")+attributes["filename"]->value;
+ if (still.read_file(filewithpath)) {
+ cerr<<"Still_image: loaded "<<filewithpath<<endl;
+ }
+ else cerr<<"Still_image: could not load "<<filewithpath<<endl;
+ }
+ };
+ ~Still_image(){
+ };
+ Still_image* clone(map<string,string> &_settings) { return new Still_image(_settings);};
+ Image *output(const Frame_spec &frame){
+ if (!still.rgb.empty()){
+ 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;
+ float oY=parameters["originY"]->value;
+ float r=parameters["rotation"]->value;
+ float s=parameters["scale"]->value;
+
+ cerr<<"still: xform "<<tX<<","<<tY<<" rotate "<<r<<", scale "<<s<<" from "<<oX<<","<<oY<<endl;
+
+ //do opencv transform
+ cv::Point2f srcTri[3], dstTri[3];
+ cv::Mat rot_mat(2,3,CV_32FC1);
+ cv::Mat trans_mat(2,3,CV_32FC1);
+
+ Image inter;
+ inter.setup(still.w,still.h);
+ // Compute matrix by creating triangle and transforming
+ //is there a better way - combine the 2? Just a bit of geometry
+ srcTri[0].x=0;
+ srcTri[0].y=0;
+ srcTri[1].x=still.w-1;
+ srcTri[1].y=0;
+ srcTri[2].x=0;
+ srcTri[2].y=still.h-1;
+ for (int i=0;i<3;i++){
+ dstTri[i].x=srcTri[i].x+(tX*still.w);
+ dstTri[i].y=srcTri[i].y+(tY*still.h);
+ }
+ trans_mat=getAffineTransform( srcTri, dstTri );
+ warpAffine( still.rgb, inter.rgb, trans_mat, inter.rgb.size(), filtmode, cv::BORDER_WRAP);
+
+
+ // Compute rotation matrix
+ //
+ cv::Point centre = cv::Point( oX*inter.w, oY*inter.h );
+
+ rot_mat = getRotationMatrix2D( centre, r, s );
+ // Do the transformation
+ //
+
+ warpAffine( inter.rgb, image.rgb, rot_mat, image.rgb.size(), filtmode, cv::BORDER_WRAP);
+ //BORDER_WRAP
+
+ //INTER_NEAREST - a nearest-neighbor interpolation
+ //INTER_LINEAR - a bilinear interpolation (used by default)
+ //INTER_AREA - resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method.
+ //INTER_CUBIC - a bicubic interpolation over 4x4 pixel neighborhood
+ //INTER_LANCZOS4 - a Lanczos interpolation over 8x8 pixel neighborhood
+
+ return &image;
+ }
+ else return nullptr;
+ }
+ private:
+ Image still;
+ };
+}
+
+#endif
diff --git a/rotord/src/rotor.cpp b/rotord/src/rotor.cpp
index 591045d..f1a2605 100755
--- a/rotord/src/rotor.cpp
+++ b/rotord/src/rotor.cpp
@@ -3,6 +3,7 @@
#include "nodes_maths.h"
#include "nodes_drawing.h"
#include "nodes_filters.h"
+#include "nodes_transform.h"
using namespace Rotor;
using Poco::Logger;
@@ -10,6 +11,7 @@ Node_factory::Node_factory(){
//for now, statically load prototype map in constructor
add_type("time",new Time());
add_type("track_time",new Track_time());
+ add_type("at_track_time",new At_track_time());
add_type("signal_output",new Signal_output());
add_type("testcard",new Testcard());
add_type("invert",new Invert());
@@ -20,7 +22,6 @@ Node_factory::Node_factory(){
add_type("blend",new Blend());
add_type("mirror",new Mirror());
add_type("monochrome",new Monochrome());
- add_type("transform",new Transform());
add_type("alpha_merge",new Alpha_merge());
add_type("difference_matte",new Difference_matte());
//nodes_audio_analysis.h
@@ -40,11 +41,13 @@ Node_factory::Node_factory(){
add_type("luma_levels",new Luma_levels());
add_type("echo_trails",new Echo_trails());
add_type("rgb_levels",new RGB_levels());
+ //nodes_transform.h
+ add_type("transform",new Transform());
+ add_type("still_image",new Still_image());
//video nodes
add_type("video_loader",new Video_loader());
add_type("video_output",new Video_output());
add_type("video_feedback",new Video_feedback());
- add_type("still_image",new Still_image());
}
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 2b18061..cb466d2 100755
--- a/rotord/src/rotor.h
+++ b/rotord/src/rotor.h
@@ -303,6 +303,23 @@ namespace Rotor {
return time.time/time.duration;
}
};
+ class At_track_time: public Signal_node {
+ public:
+ At_track_time(){
+ create_signal_input("signal","Signal Input");
+ create_parameter("time","number","Track time to evaluate","Time",0.0f);
+ title="@Track time";
+ description="Gets input from a different point in the track";
+ };
+ At_track_time(map<string,string> &settings): At_track_time() {
+ base_settings(settings);
+ };
+ At_track_time* clone(map<string,string> &_settings) { return new At_track_time(_settings);};
+ const float output(const Time_spec &time) {
+ Time_spec t=Time_spec(parameters["time"]->value*time.duration,time.framerate,time.duration);
+ return inputs[0]->get(t);
+ }
+ };
class Signal_output: public Signal_node {
public:
Signal_output(){
@@ -678,145 +695,6 @@ 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
- //units: pixel or fractional
- //aspect: scaled or homogenous
- public:
- Transform(){
- create_image_input("image input","Image input");
- create_parameter("transformX","number","X transformation","Transform X",0.0f);
- create_parameter("transformY","number","Y transformation","Transform X",0.0f);
- create_parameter("originX","number","X transformation origin","Origin X",0.5f);
- 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";
- };
- Transform(map<string,string> &settings):Transform() {
- base_settings(settings);
- };
- ~Transform(){
- };
- Transform* clone(map<string,string> &_settings) { return new Transform(_settings);};
- 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;
- float oY=parameters["originY"]->value;
- float r=parameters["rotation"]->value;
- float s=parameters["scale"]->value;
-
- //do opencv transform
- cv::Point2f srcTri[3], dstTri[3];
- cv::Mat rot_mat(2,3,CV_32FC1);
- cv::Mat trans_mat(2,3,CV_32FC1);
-
- Image inter;
- inter.setup(in->w,in->h);
- // Compute matrix by creating triangle and transforming
- //is there a better way - combine the 2? Just a bit of geometry
- srcTri[0].x=0;
- srcTri[0].y=0;
- srcTri[1].x=in->w-1;
- srcTri[1].y=0;
- srcTri[2].x=0;
- srcTri[2].y=in->h-1;
- for (int i=0;i<3;i++){
- dstTri[i].x=srcTri[i].x+(tX*in->w);
- dstTri[i].y=srcTri[i].y+(tY*in->h);
- }
- trans_mat=getAffineTransform( srcTri, dstTri );
- warpAffine( in->rgb, inter.rgb, trans_mat, inter.rgb.size(), filtmode, cv::BORDER_WRAP);
-
-
- // Compute rotation matrix
- //
- cv::Point centre = cv::Point( oX*in->w, oY*in->h );
-
- rot_mat = getRotationMatrix2D( centre, r, s );
- // Do the transformation
- //
-
- warpAffine( inter.rgb, image.rgb, rot_mat, image.rgb.size(), filtmode, cv::BORDER_WRAP);
- //BORDER_WRAP
-
- //INTER_NEAREST - a nearest-neighbor interpolation
- //INTER_LINEAR - a bilinear interpolation (used by default)
- //INTER_AREA - resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method.
- //INTER_CUBIC - a bicubic interpolation over 4x4 pixel neighborhood
- //INTER_LANCZOS4 - a Lanczos interpolation over 8x8 pixel neighborhood
-
- return &image;
- }
- return nullptr;
- }
- private:
- };
- class Still_image: public Image_node {
- public:
- Still_image(){
- create_parameter("transformX","number","X transformation","Transform X",0.0f);
- create_parameter("transformY","number","Y transformation","Transform X",0.0f);
- create_parameter("originX","number","X transformation origin","Origin X",0.5f);
- 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"});
- create_attribute("filename","name of image file to load","File name","");
- title="Still image";
- description="Load a still image and apply 2D transformation";
- };
- Still_image(map<string,string> &settings):Still_image() {
- base_settings(settings);
- if (attributes["filename"]->value!=""){
- string filewithpath=find_setting(settings,"media_path","")+attributes["filename"]->value;
- if (image.read_file(filewithpath)) {
- cerr<<"Still_image: loaded "<<filewithpath<<endl;
- }
- else cerr<<"Still_image: could not load "<<filewithpath<<endl;
- }
- };
- ~Still_image(){
- };
- Still_image* clone(map<string,string> &_settings) { return new Still_image(_settings);};
- Image *output(const Frame_spec &frame){
- if (!image.rgb.empty()){
-
- }
- else return nullptr;
- }
- private:
- };
class Alpha_merge: public Image_node {
public:
Alpha_merge(){