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