最近遇到一个函数,在调用的时候出现问题,记录下实现过程。
#ifndef MLS_DEFORMATION_H #define MLS_DEFORMATION_H #include <vector> #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> using namespace cv; using namespace std; class MLSDeformation//父类 { public: virtual bool InitMLSD(const cv::Mat& oriImg,const std::vector<cv::Point2i>&src_pt,int alpha=1, int gridsize=5);//定义成虚函数是为了方便子类改写 virtual cv::Mat Deformation(const std::vector<cv::Point2i> &dst_pt)=0;//=0说明这个函数没有实现完 explicit MLSDeformation();// 指定这个构造器只能被明确的调用/使用, 不能作为类型转换操作符被隐含的使用。 virtual ~MLSDeformation(); protected: cv::Mat getDeformationImg(); void meanMat(cv::Mat& mat, int i, int j);//对mat(i,j)进行gridsize的中值(当mean为空时),不包括像素为空的坐标 void repairMat(cv::Mat& mat);//变形后的mat有些位置没有像素点,使用中值滤波填补 int gridsize_; int alpha_;///weight_计算相关 int n_point_;///控制点数 cv::Mat src_img_;//原图像 int src_width_; int src_height_; std::vector<cv::Point2d> pi_point_;//原控制点 std::vector<cv::Point2d> qi_point_;//变形后的控制点 ///参数信息 double*weight_;//权重w*h*pt double*sum_weight_;//w*h cv::Point2d*deformation_pt_;//对应目标坐标 cv::Point2d pstart_, qstart_; std::vector<cv::Point2d> pdiff_, qdiff_; }; class MLSDAffine :public MLSDeformation//继承主类的子类 { public: virtual bool InitMLSD(const cv::Mat& oriImg,const std::vector<cv::Point2i>&src_pt,int alpha=1, int gridsize=5);//写成virtual完全是因为从主类拷贝过来的,也可以认为方便接下来的子类继承他 virtual cv::Mat Deformation(const std::vector<cv::Point2i> &dst_pt); explicit MLSDAffine(); virtual~MLSDAffine(); private: double*a_affine_;///affine A参数 }; class MLSDSimilarity :public MLSDeformation { public: virtual bool InitMLSD(const cv::Mat& oriImg,const std::vector<cv::Point2i>&src_pt,int alpha=1, int gridsize=5); virtual cv::Mat Deformation(const std::vector<cv::Point2i> &dst_pt); explicit MLSDSimilarity(); virtual~MLSDSimilarity(); private: double*us_;//us参数 cv::Matx22d*a_similarity_;///similarity A参数 }; class MLSDRigid :public MLSDeformation { public: virtual bool InitMLSD(const cv::Mat& oriImg,const std::vector<cv::Point2i>&src_pt,int alpha=1, int gridsize=5); virtual cv::Mat Deformation(const std::vector<cv::Point2i> &dst_pt); explicit MLSDRigid(); virtual~MLSDRigid(); private: double*ur_;//us参数 cv::Point2d*pstart_rigid_;// cv::Matx22d*a_rigid_;///similarity A参数 }; #endif // MLS_DEFORMATION_H
从上面的实现可以看出,实现了一个MLS变形的方法,里面有两个函数,分别是init和deformation,然后三个子类开始继承这个父类,然后分别实现了MLS的仿射变换,相似变换,刚性变化。
这里顺便扩展下几个变换的意义。
仿射变换:主要包括平移变换、旋转变换、缩放变换(也叫尺度变换)、倾斜变换(也叫错切变换、剪切变换、偏移变换)、翻转变换,有六个自由度。
仿射变换保持二维图形的“平直性”和“平行性”,但是角度会改变。
“平直性”:变换后直线还是直线、圆弧还是圆弧。
“平行性”:平行线还是平行线,直线上点的位置顺序不变
相似变换:相当于是等距变换和均匀缩放的一个复合,用S表示变换矩阵,即为
左上角2×2矩阵为旋转部分,tx和ty为平移因子,它有4个自由度,即旋转,x方向平移,y方向平移和缩放因子s。相似变换前后长度比,夹角,虚圆点I,J保持不变。相似变换其实与相似三角形之间是有类似的。
在调用这些方法的时候,主要可以有以下几种方式。
刚性变换:只有物体的位置(平移变换)和朝向(旋转变换)发生改变,而形状不变。
调用上述类的方法:
第一,直接调用子类:
MLSDRigid mlsr; mlsr.InitMLSD(<#const cv::Mat &oriImg#>, <#const std::vector<cv::Point2i> &src_pt#>);
第二,调用父类,然后指针操作
MLSDeformation *mls; mls = new MLSDAffine; mls->InitMLSD(src,src_pt,alpha, gridsize);
甚至可以写成switch case语句,不同的条件下,mls new不同的子类,然后调用他的method。