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 */
AffineTransformerImpl()52     AffineTransformerImpl()
53     {
54         fullAffine = true;
55         name_ = "ShapeTransformer.AFF";
56     }
57 
AffineTransformerImpl(bool _fullAffine)58     AffineTransformerImpl(bool _fullAffine)
59     {
60         fullAffine = _fullAffine;
61         name_ = "ShapeTransformer.AFF";
62     }
63 
64     /* Destructor */
~AffineTransformerImpl()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
setFullAffine(bool _fullAffine)76     virtual void setFullAffine(bool _fullAffine) {fullAffine=_fullAffine;}
getFullAffine() const77     virtual bool getFullAffine() const {return fullAffine;}
78 
79     //! write/read
write(FileStorage & fs) const80     virtual void write(FileStorage& fs) const
81     {
82         fs << "name" << name_
83            << "affine_type" << int(fullAffine);
84     }
85 
read(const FileNode & fn)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 
warpImage(InputArray transformingImage,OutputArray output,int flags,int borderMode,const Scalar & borderValue) const101 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 
_localAffineEstimate(const std::vector<Point2f> & shape1,const std::vector<Point2f> & shape2,bool fullAfine)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 
estimateTransformation(InputArray _pts1,InputArray _pts2,std::vector<DMatch> & _matches)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 
applyTransformation(InputArray inPts,OutputArray outPts)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 
createAffineTransformer(bool fullAffine)259 Ptr <AffineTransformer> createAffineTransformer(bool fullAffine)
260 {
261     return Ptr<AffineTransformer>( new AffineTransformerImpl(fullAffine) );
262 }
263 
264 } // cv
265