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