Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                           License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
     14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
     15 // Third party copyrights are property of their respective owners.
     16 //
     17 // Redistribution and use in source and binary forms, with or without modification,
     18 // are permitted provided that the following conditions are met:
     19 //
     20 //   * Redistribution's of source code must retain the above copyright notice,
     21 //     this list of conditions and the following disclaimer.
     22 //
     23 //   * Redistribution's in binary form must reproduce the above copyright notice,
     24 //     this list of conditions and the following disclaimer in the documentation
     25 //     and/or other materials provided with the distribution.
     26 //
     27 //   * The name of the copyright holders may not be used to endorse or promote products
     28 //     derived from this software without specific prior written permission.
     29 //
     30 // This software is provided by the copyright holders and contributors "as is" and
     31 // any express or implied warranties, including, but not limited to, the implied
     32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     33 // In no event shall the Intel Corporation or contributors be liable for any direct,
     34 // indirect, incidental, special, exemplary, or consequential damages
     35 // (including, but not limited to, procurement of substitute goods or services;
     36 // loss of use, data, or profits; or business interruption) however caused
     37 // and on any theory of liability, whether in contract, strict liability,
     38 // or tort (including negligence or otherwise) arising in any way out of
     39 // the use of this software, even if advised of the possibility of such damage.
     40 //
     41 //M*/
     42 
     43 #include "precomp.hpp"
     44 
     45 namespace cv
     46 {
     47 
     48 class AffineTransformerImpl : public AffineTransformer
     49 {
     50 public:
     51     /* Constructors */
     52     AffineTransformerImpl()
     53     {
     54         fullAffine = true;
     55         name_ = "ShapeTransformer.AFF";
     56     }
     57 
     58     AffineTransformerImpl(bool _fullAffine)
     59     {
     60         fullAffine = _fullAffine;
     61         name_ = "ShapeTransformer.AFF";
     62     }
     63 
     64     /* Destructor */
     65     ~AffineTransformerImpl()
     66     {
     67     }
     68 
     69     //! the main operator
     70     virtual void estimateTransformation(InputArray transformingShape, InputArray targetShape, std::vector<DMatch> &matches);
     71     virtual float applyTransformation(InputArray input, OutputArray output=noArray());
     72     virtual void warpImage(InputArray transformingImage, OutputArray output,
     73                            int flags, int borderMode, const Scalar& borderValue) const;
     74 
     75     //! Setters/Getters
     76     virtual void setFullAffine(bool _fullAffine) {fullAffine=_fullAffine;}
     77     virtual bool getFullAffine() const {return fullAffine;}
     78 
     79     //! write/read
     80     virtual void write(FileStorage& fs) const
     81     {
     82         fs << "name" << name_
     83            << "affine_type" << int(fullAffine);
     84     }
     85 
     86     virtual void read(const FileNode& fn)
     87     {
     88         CV_Assert( (String)fn["name"] == name_ );
     89         fullAffine = int(fn["affine_type"])?true:false;
     90     }
     91 
     92 private:
     93     bool fullAffine;
     94     Mat affineMat;
     95     float transformCost;
     96 
     97 protected:
     98     String name_;
     99 };
    100 
    101 void AffineTransformerImpl::warpImage(InputArray transformingImage, OutputArray output,
    102                                       int flags, int borderMode, const Scalar& borderValue) const
    103 {
    104     CV_Assert(!affineMat.empty());
    105     warpAffine(transformingImage, output, affineMat, transformingImage.getMat().size(), flags, borderMode, borderValue);
    106 }
    107 
    108 
    109 static Mat _localAffineEstimate(const std::vector<Point2f>& shape1, const std::vector<Point2f>& shape2,
    110                                 bool fullAfine)
    111 {
    112     Mat out(2,3,CV_32F);
    113     int siz=2*(int)shape1.size();
    114 
    115     if (fullAfine)
    116     {
    117         Mat matM(siz, 6, CV_32F);
    118         Mat matP(siz,1,CV_32F);
    119         int contPt=0;
    120         for (int ii=0; ii<siz; ii++)
    121         {
    122             Mat therow = Mat::zeros(1,6,CV_32F);
    123             if (ii%2==0)
    124             {
    125                 therow.at<float>(0,0)=shape1[contPt].x;
    126                 therow.at<float>(0,1)=shape1[contPt].y;
    127                 therow.at<float>(0,2)=1;
    128                 therow.row(0).copyTo(matM.row(ii));
    129                 matP.at<float>(ii,0) = shape2[contPt].x;
    130             }
    131             else
    132             {
    133                 therow.at<float>(0,3)=shape1[contPt].x;
    134                 therow.at<float>(0,4)=shape1[contPt].y;
    135                 therow.at<float>(0,5)=1;
    136                 therow.row(0).copyTo(matM.row(ii));
    137                 matP.at<float>(ii,0) = shape2[contPt].y;
    138                 contPt++;
    139             }
    140         }
    141         Mat sol;
    142         solve(matM, matP, sol, DECOMP_SVD);
    143         out = sol.reshape(0,2);
    144     }
    145     else
    146     {
    147         Mat matM(siz, 4, CV_32F);
    148         Mat matP(siz,1,CV_32F);
    149         int contPt=0;
    150         for (int ii=0; ii<siz; ii++)
    151         {
    152             Mat therow = Mat::zeros(1,4,CV_32F);
    153             if (ii%2==0)
    154             {
    155                 therow.at<float>(0,0)=shape1[contPt].x;
    156                 therow.at<float>(0,1)=shape1[contPt].y;
    157                 therow.at<float>(0,2)=1;
    158                 therow.row(0).copyTo(matM.row(ii));
    159                 matP.at<float>(ii,0) = shape2[contPt].x;
    160             }
    161             else
    162             {
    163                 therow.at<float>(0,0)=-shape1[contPt].y;
    164                 therow.at<float>(0,1)=shape1[contPt].x;
    165                 therow.at<float>(0,3)=1;
    166                 therow.row(0).copyTo(matM.row(ii));
    167                 matP.at<float>(ii,0) = shape2[contPt].y;
    168                 contPt++;
    169             }
    170         }
    171         Mat sol;
    172         solve(matM, matP, sol, DECOMP_SVD);
    173         out.at<float>(0,0)=sol.at<float>(0,0);
    174         out.at<float>(0,1)=sol.at<float>(1,0);
    175         out.at<float>(0,2)=sol.at<float>(2,0);
    176         out.at<float>(1,0)=-sol.at<float>(1,0);
    177         out.at<float>(1,1)=sol.at<float>(0,0);
    178         out.at<float>(1,2)=sol.at<float>(3,0);
    179     }
    180     return out;
    181 }
    182 
    183 void AffineTransformerImpl::estimateTransformation(InputArray _pts1, InputArray _pts2, std::vector<DMatch>& _matches)
    184 {
    185     Mat pts1 = _pts1.getMat();
    186     Mat pts2 = _pts2.getMat();
    187     CV_Assert((pts1.channels()==2) && (pts1.cols>0) && (pts2.channels()==2) && (pts2.cols>0));
    188     CV_Assert(_matches.size()>1);
    189 
    190     if (pts1.type() != CV_32F)
    191         pts1.convertTo(pts1, CV_32F);
    192     if (pts2.type() != CV_32F)
    193         pts2.convertTo(pts2, CV_32F);
    194 
    195     // Use only valid matchings //
    196     std::vector<DMatch> matches;
    197     for (size_t i=0; i<_matches.size(); i++)
    198     {
    199         if (_matches[i].queryIdx<pts1.cols &&
    200             _matches[i].trainIdx<pts2.cols)
    201         {
    202             matches.push_back(_matches[i]);
    203         }
    204     }
    205 
    206     // Organizing the correspondent points in vector style //
    207     std::vector<Point2f> shape1; // transforming shape
    208     std::vector<Point2f> shape2; // target shape
    209     for (size_t i=0; i<matches.size(); i++)
    210     {
    211         Point2f pt1=pts1.at<Point2f>(0,matches[i].queryIdx);
    212         shape1.push_back(pt1);
    213 
    214         Point2f pt2=pts2.at<Point2f>(0,matches[i].trainIdx);
    215         shape2.push_back(pt2);
    216     }
    217 
    218     // estimateRigidTransform //
    219     Mat affine;
    220     estimateRigidTransform(shape1, shape2, fullAffine).convertTo(affine, CV_32F);
    221 
    222     if (affine.empty())
    223         affine=_localAffineEstimate(shape1, shape2, fullAffine); //In case there is not good solution, just give a LLS based one
    224 
    225     affineMat = affine;
    226 }
    227 
    228 float AffineTransformerImpl::applyTransformation(InputArray inPts, OutputArray outPts)
    229 {
    230     Mat pts1 = inPts.getMat();
    231     CV_Assert((pts1.channels()==2) && (pts1.cols>0));
    232 
    233     //Apply transformation in the complete set of points
    234     Mat fAffine;
    235     transform(pts1, fAffine, affineMat);
    236 
    237     // Ensambling output //
    238     if (outPts.needed())
    239     {
    240         outPts.create(1,fAffine.cols, CV_32FC2);
    241         Mat outMat = outPts.getMat();
    242         for (int i=0; i<fAffine.cols; i++)
    243             outMat.at<Point2f>(0,i)=fAffine.at<Point2f>(0,i);
    244     }
    245 
    246     // Updating Transform Cost //
    247     Mat Af(2, 2, CV_32F);
    248     Af.at<float>(0,0)=affineMat.at<float>(0,0);
    249     Af.at<float>(0,1)=affineMat.at<float>(1,0);
    250     Af.at<float>(1,0)=affineMat.at<float>(0,1);
    251     Af.at<float>(1,1)=affineMat.at<float>(1,1);
    252     SVD mysvd(Af, SVD::NO_UV);
    253     Mat singVals=mysvd.w;
    254     transformCost=std::log((singVals.at<float>(0,0)+FLT_MIN)/(singVals.at<float>(1,0)+FLT_MIN));
    255 
    256     return transformCost;
    257 }
    258 
    259 Ptr <AffineTransformer> createAffineTransformer(bool fullAffine)
    260 {
    261     return Ptr<AffineTransformer>( new AffineTransformerImpl(fullAffine) );
    262 }
    263 
    264 } // cv
    265