summaryrefslogtreecommitdiff
path: root/rotord/src/nodes_transform.h
diff options
context:
space:
mode:
authorTim Redfern <tim@eclectronics.org>2013-08-30 12:20:25 +0100
committerTim Redfern <tim@eclectronics.org>2013-08-30 12:20:25 +0100
commit9570eb7a5eb70128f7b986a281dd163263858ba1 (patch)
tree50c682657dc59422491f894e799e3da634abd4cd /rotord/src/nodes_transform.h
parent3a66eefd5021f3f93d2f2ce7a10d8c31dafa76d8 (diff)
@track time
Diffstat (limited to 'rotord/src/nodes_transform.h')
-rw-r--r--rotord/src/nodes_transform.h315
1 files changed, 315 insertions, 0 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