diff options
Diffstat (limited to 'rotord/src/nodes_transform.h')
| -rw-r--r-- | rotord/src/nodes_transform.h | 315 |
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 ℑ + } + 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 ℑ + } + 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 ℑ + } + else return nullptr; + } + private: + Image still; + }; +} + +#endif |
