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 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41 
42 #include "precomp.hpp"
43 
44 
45 /****************************************************************************************\
46 *                                       Image Alignment (ECC algorithm)                  *
47 \****************************************************************************************/
48 
49 using namespace cv;
50 
image_jacobian_homo_ECC(const Mat & src1,const Mat & src2,const Mat & src3,const Mat & src4,const Mat & src5,Mat & dst)51 static void image_jacobian_homo_ECC(const Mat& src1, const Mat& src2,
52                                     const Mat& src3, const Mat& src4,
53                                     const Mat& src5, Mat& dst)
54 {
55 
56 
57     CV_Assert(src1.size() == src2.size());
58     CV_Assert(src1.size() == src3.size());
59     CV_Assert(src1.size() == src4.size());
60 
61     CV_Assert( src1.rows == dst.rows);
62     CV_Assert(dst.cols == (src1.cols*8));
63     CV_Assert(dst.type() == CV_32FC1);
64 
65     CV_Assert(src5.isContinuous());
66 
67 
68     const float* hptr = src5.ptr<float>(0);
69 
70     const float h0_ = hptr[0];
71     const float h1_ = hptr[3];
72     const float h2_ = hptr[6];
73     const float h3_ = hptr[1];
74     const float h4_ = hptr[4];
75     const float h5_ = hptr[7];
76     const float h6_ = hptr[2];
77     const float h7_ = hptr[5];
78 
79     const int w = src1.cols;
80 
81 
82     //create denominator for all points as a block
83     Mat den_ = src3*h2_ + src4*h5_ + 1.0;//check the time of this! otherwise use addWeighted
84 
85     //create projected points
86     Mat hatX_ = -src3*h0_ - src4*h3_ - h6_;
87     divide(hatX_, den_, hatX_);
88     Mat hatY_ = -src3*h1_ - src4*h4_ - h7_;
89     divide(hatY_, den_, hatY_);
90 
91 
92     //instead of dividing each block with den,
93     //just pre-divide the block of gradients (it's more efficient)
94 
95     Mat src1Divided_;
96     Mat src2Divided_;
97 
98     divide(src1, den_, src1Divided_);
99     divide(src2, den_, src2Divided_);
100 
101 
102     //compute Jacobian blocks (8 blocks)
103 
104     dst.colRange(0, w) = src1Divided_.mul(src3);//1
105 
106     dst.colRange(w,2*w) = src2Divided_.mul(src3);//2
107 
108     Mat temp_ = (hatX_.mul(src1Divided_)+hatY_.mul(src2Divided_));
109     dst.colRange(2*w,3*w) = temp_.mul(src3);//3
110 
111     hatX_.release();
112     hatY_.release();
113 
114     dst.colRange(3*w, 4*w) = src1Divided_.mul(src4);//4
115 
116     dst.colRange(4*w, 5*w) = src2Divided_.mul(src4);//5
117 
118     dst.colRange(5*w, 6*w) = temp_.mul(src4);//6
119 
120     src1Divided_.copyTo(dst.colRange(6*w, 7*w));//7
121 
122     src2Divided_.copyTo(dst.colRange(7*w, 8*w));//8
123 }
124 
image_jacobian_euclidean_ECC(const Mat & src1,const Mat & src2,const Mat & src3,const Mat & src4,const Mat & src5,Mat & dst)125 static void image_jacobian_euclidean_ECC(const Mat& src1, const Mat& src2,
126                                          const Mat& src3, const Mat& src4,
127                                          const Mat& src5, Mat& dst)
128 {
129 
130     CV_Assert( src1.size()==src2.size());
131     CV_Assert( src1.size()==src3.size());
132     CV_Assert( src1.size()==src4.size());
133 
134     CV_Assert( src1.rows == dst.rows);
135     CV_Assert(dst.cols == (src1.cols*3));
136     CV_Assert(dst.type() == CV_32FC1);
137 
138     CV_Assert(src5.isContinuous());
139 
140     const float* hptr = src5.ptr<float>(0);
141 
142     const float h0 = hptr[0];//cos(theta)
143     const float h1 = hptr[3];//sin(theta)
144 
145     const int w = src1.cols;
146 
147     //create -sin(theta)*X -cos(theta)*Y for all points as a block -> hatX
148     Mat hatX = -(src3*h1) - (src4*h0);
149 
150     //create cos(theta)*X -sin(theta)*Y for all points as a block -> hatY
151     Mat hatY = (src3*h0) - (src4*h1);
152 
153 
154     //compute Jacobian blocks (3 blocks)
155     dst.colRange(0, w) = (src1.mul(hatX))+(src2.mul(hatY));//1
156 
157     src1.copyTo(dst.colRange(w, 2*w));//2
158     src2.copyTo(dst.colRange(2*w, 3*w));//3
159 }
160 
161 
image_jacobian_affine_ECC(const Mat & src1,const Mat & src2,const Mat & src3,const Mat & src4,Mat & dst)162 static void image_jacobian_affine_ECC(const Mat& src1, const Mat& src2,
163                                       const Mat& src3, const Mat& src4,
164                                       Mat& dst)
165 {
166 
167     CV_Assert(src1.size() == src2.size());
168     CV_Assert(src1.size() == src3.size());
169     CV_Assert(src1.size() == src4.size());
170 
171     CV_Assert(src1.rows == dst.rows);
172     CV_Assert(dst.cols == (6*src1.cols));
173 
174     CV_Assert(dst.type() == CV_32FC1);
175 
176 
177     const int w = src1.cols;
178 
179     //compute Jacobian blocks (6 blocks)
180 
181     dst.colRange(0,w) = src1.mul(src3);//1
182     dst.colRange(w,2*w) = src2.mul(src3);//2
183     dst.colRange(2*w,3*w) = src1.mul(src4);//3
184     dst.colRange(3*w,4*w) = src2.mul(src4);//4
185     src1.copyTo(dst.colRange(4*w,5*w));//5
186     src2.copyTo(dst.colRange(5*w,6*w));//6
187 }
188 
189 
image_jacobian_translation_ECC(const Mat & src1,const Mat & src2,Mat & dst)190 static void image_jacobian_translation_ECC(const Mat& src1, const Mat& src2, Mat& dst)
191 {
192 
193     CV_Assert( src1.size()==src2.size());
194 
195     CV_Assert( src1.rows == dst.rows);
196     CV_Assert(dst.cols == (src1.cols*2));
197     CV_Assert(dst.type() == CV_32FC1);
198 
199     const int w = src1.cols;
200 
201     //compute Jacobian blocks (2 blocks)
202     src1.copyTo(dst.colRange(0, w));
203     src2.copyTo(dst.colRange(w, 2*w));
204 }
205 
206 
project_onto_jacobian_ECC(const Mat & src1,const Mat & src2,Mat & dst)207 static void project_onto_jacobian_ECC(const Mat& src1, const Mat& src2, Mat& dst)
208 {
209     /* this functions is used for two types of projections. If src1.cols ==src.cols
210     it does a blockwise multiplication (like in the outer product of vectors)
211     of the blocks in matrices src1 and src2 and dst
212     has size (number_of_blcks x number_of_blocks), otherwise dst is a vector of size
213     (number_of_blocks x 1) since src2 is "multiplied"(dot) with each block of src1.
214 
215     The number_of_blocks is equal to the number of parameters we are lloking for
216     (i.e. rtanslation:2, euclidean: 3, affine: 6, homography: 8)
217 
218     */
219     CV_Assert(src1.rows == src2.rows);
220     CV_Assert((src1.cols % src2.cols) == 0);
221     int w;
222 
223     float* dstPtr = dst.ptr<float>(0);
224 
225     if (src1.cols !=src2.cols){//dst.cols==1
226         w  = src2.cols;
227         for (int i=0; i<dst.rows; i++){
228             dstPtr[i] = (float) src2.dot(src1.colRange(i*w,(i+1)*w));
229         }
230     }
231 
232     else {
233         CV_Assert(dst.cols == dst.rows); //dst is square (and symmetric)
234         w = src2.cols/dst.cols;
235         Mat mat;
236         for (int i=0; i<dst.rows; i++){
237 
238             mat = Mat(src1.colRange(i*w, (i+1)*w));
239             dstPtr[i*(dst.rows+1)] = (float) pow(norm(mat),2); //diagonal elements
240 
241             for (int j=i+1; j<dst.cols; j++){ //j starts from i+1
242                 dstPtr[i*dst.cols+j] = (float) mat.dot(src2.colRange(j*w, (j+1)*w));
243                 dstPtr[j*dst.cols+i] = dstPtr[i*dst.cols+j]; //due to symmetry
244             }
245         }
246     }
247 }
248 
249 
update_warping_matrix_ECC(Mat & map_matrix,const Mat & update,const int motionType)250 static void update_warping_matrix_ECC (Mat& map_matrix, const Mat& update, const int motionType)
251 {
252     CV_Assert (map_matrix.type() == CV_32FC1);
253     CV_Assert (update.type() == CV_32FC1);
254 
255     CV_Assert (motionType == MOTION_TRANSLATION || motionType == MOTION_EUCLIDEAN ||
256         motionType == MOTION_AFFINE || motionType == MOTION_HOMOGRAPHY);
257 
258     if (motionType == MOTION_HOMOGRAPHY)
259         CV_Assert (map_matrix.rows == 3 && update.rows == 8);
260     else if (motionType == MOTION_AFFINE)
261         CV_Assert(map_matrix.rows == 2 && update.rows == 6);
262     else if (motionType == MOTION_EUCLIDEAN)
263         CV_Assert (map_matrix.rows == 2 && update.rows == 3);
264     else
265         CV_Assert (map_matrix.rows == 2 && update.rows == 2);
266 
267     CV_Assert (update.cols == 1);
268 
269     CV_Assert( map_matrix.isContinuous());
270     CV_Assert( update.isContinuous() );
271 
272 
273     float* mapPtr = map_matrix.ptr<float>(0);
274     const float* updatePtr = update.ptr<float>(0);
275 
276 
277     if (motionType == MOTION_TRANSLATION){
278         mapPtr[2] += updatePtr[0];
279         mapPtr[5] += updatePtr[1];
280     }
281     if (motionType == MOTION_AFFINE) {
282         mapPtr[0] += updatePtr[0];
283         mapPtr[3] += updatePtr[1];
284         mapPtr[1] += updatePtr[2];
285         mapPtr[4] += updatePtr[3];
286         mapPtr[2] += updatePtr[4];
287         mapPtr[5] += updatePtr[5];
288     }
289     if (motionType == MOTION_HOMOGRAPHY) {
290         mapPtr[0] += updatePtr[0];
291         mapPtr[3] += updatePtr[1];
292         mapPtr[6] += updatePtr[2];
293         mapPtr[1] += updatePtr[3];
294         mapPtr[4] += updatePtr[4];
295         mapPtr[7] += updatePtr[5];
296         mapPtr[2] += updatePtr[6];
297         mapPtr[5] += updatePtr[7];
298     }
299     if (motionType == MOTION_EUCLIDEAN) {
300         double new_theta = updatePtr[0];
301         new_theta += asin(mapPtr[3]);
302 
303         mapPtr[2] += updatePtr[1];
304         mapPtr[5] += updatePtr[2];
305         mapPtr[0] = mapPtr[4] = (float) cos(new_theta);
306         mapPtr[3] = (float) sin(new_theta);
307         mapPtr[1] = -mapPtr[3];
308     }
309 }
310 
311 
312 /** Function that computes enhanced corelation coefficient from Georgios et.al. 2008
313 *   See https://github.com/opencv/opencv/issues/12432
314 */
computeECC(InputArray templateImage,InputArray inputImage,InputArray inputMask)315 double cv::computeECC(InputArray templateImage, InputArray inputImage, InputArray inputMask)
316 {
317     CV_Assert(!templateImage.empty());
318     CV_Assert(!inputImage.empty());
319 
320     if( ! (templateImage.type()==inputImage.type()))
321         CV_Error( Error::StsUnmatchedFormats, "Both input images must have the same data type" );
322 
323     Scalar meanTemplate, sdTemplate;
324 
325     int active_pixels = inputMask.empty() ? templateImage.size().area() : countNonZero(inputMask);
326     int type = templateImage.type();
327     meanStdDev(templateImage, meanTemplate, sdTemplate, inputMask);
328     Mat templateImage_zeromean = Mat::zeros(templateImage.size(), templateImage.type());
329     Mat templateMat = templateImage.getMat();
330     Mat inputMat = inputImage.getMat();
331 
332     /*
333      * For unsigned ints, when the mean is computed and subtracted, any values less than the mean
334      * will be set to 0 (since there are no negatives values). This impacts the norm and dot product, which
335      * ultimately results in an incorrect ECC. To circumvent this problem, if unsigned ints are provided,
336      * we convert them to a signed ints with larger resolution for the subtraction step.
337      */
338     if(type == CV_8U || type == CV_16U) {
339         int newType = type == CV_8U ? CV_16S : CV_32S;
340         Mat templateMatConverted, inputMatConverted;
341         templateMat.convertTo(templateMatConverted, newType);
342         cv::swap(templateMat, templateMatConverted);
343         inputMat.convertTo(inputMatConverted, newType);
344         cv::swap(inputMat, inputMatConverted);
345     }
346     subtract(templateMat, meanTemplate, templateImage_zeromean, inputMask);
347     double templateImagenorm = std::sqrt(active_pixels*sdTemplate.val[0]*sdTemplate.val[0]);
348 
349     Scalar meanInput, sdInput;
350 
351     Mat inputImage_zeromean = Mat::zeros(inputImage.size(), inputImage.type());
352     meanStdDev(inputImage, meanInput, sdInput, inputMask);
353     subtract(inputMat, meanInput, inputImage_zeromean, inputMask);
354     double inputImagenorm = std::sqrt(active_pixels*sdInput.val[0]*sdInput.val[0]);
355 
356     return templateImage_zeromean.dot(inputImage_zeromean)/(templateImagenorm*inputImagenorm);
357 }
358 
359 
findTransformECC(InputArray templateImage,InputArray inputImage,InputOutputArray warpMatrix,int motionType,TermCriteria criteria,InputArray inputMask,int gaussFiltSize)360 double cv::findTransformECC(InputArray templateImage,
361                             InputArray inputImage,
362                             InputOutputArray warpMatrix,
363                             int motionType,
364                             TermCriteria criteria,
365                             InputArray inputMask,
366                             int gaussFiltSize)
367 {
368 
369 
370     Mat src = templateImage.getMat();//template image
371     Mat dst = inputImage.getMat(); //input image (to be warped)
372     Mat map = warpMatrix.getMat(); //warp (transformation)
373 
374     CV_Assert(!src.empty());
375     CV_Assert(!dst.empty());
376 
377     // If the user passed an un-initialized warpMatrix, initialize to identity
378     if(map.empty()) {
379         int rowCount = 2;
380         if(motionType == MOTION_HOMOGRAPHY)
381             rowCount = 3;
382 
383         warpMatrix.create(rowCount, 3, CV_32FC1);
384         map = warpMatrix.getMat();
385         map = Mat::eye(rowCount, 3, CV_32F);
386     }
387 
388     if( ! (src.type()==dst.type()))
389         CV_Error( Error::StsUnmatchedFormats, "Both input images must have the same data type" );
390 
391     //accept only 1-channel images
392     if( src.type() != CV_8UC1 && src.type()!= CV_32FC1)
393         CV_Error( Error::StsUnsupportedFormat, "Images must have 8uC1 or 32fC1 type");
394 
395     if( map.type() != CV_32FC1)
396         CV_Error( Error::StsUnsupportedFormat, "warpMatrix must be single-channel floating-point matrix");
397 
398     CV_Assert (map.cols == 3);
399     CV_Assert (map.rows == 2 || map.rows ==3);
400 
401     CV_Assert (motionType == MOTION_AFFINE || motionType == MOTION_HOMOGRAPHY ||
402         motionType == MOTION_EUCLIDEAN || motionType == MOTION_TRANSLATION);
403 
404     if (motionType == MOTION_HOMOGRAPHY){
405         CV_Assert (map.rows ==3);
406     }
407 
408     CV_Assert (criteria.type & TermCriteria::COUNT || criteria.type & TermCriteria::EPS);
409     const int    numberOfIterations = (criteria.type & TermCriteria::COUNT) ? criteria.maxCount : 200;
410     const double termination_eps    = (criteria.type & TermCriteria::EPS)   ? criteria.epsilon  :  -1;
411 
412     int paramTemp = 6;//default: affine
413     switch (motionType){
414       case MOTION_TRANSLATION:
415           paramTemp = 2;
416           break;
417       case MOTION_EUCLIDEAN:
418           paramTemp = 3;
419           break;
420       case MOTION_HOMOGRAPHY:
421           paramTemp = 8;
422           break;
423     }
424 
425 
426     const int numberOfParameters = paramTemp;
427 
428     const int ws = src.cols;
429     const int hs = src.rows;
430     const int wd = dst.cols;
431     const int hd = dst.rows;
432 
433     Mat Xcoord = Mat(1, ws, CV_32F);
434     Mat Ycoord = Mat(hs, 1, CV_32F);
435     Mat Xgrid = Mat(hs, ws, CV_32F);
436     Mat Ygrid = Mat(hs, ws, CV_32F);
437 
438     float* XcoPtr = Xcoord.ptr<float>(0);
439     float* YcoPtr = Ycoord.ptr<float>(0);
440     int j;
441     for (j=0; j<ws; j++)
442         XcoPtr[j] = (float) j;
443     for (j=0; j<hs; j++)
444         YcoPtr[j] = (float) j;
445 
446     repeat(Xcoord, hs, 1, Xgrid);
447     repeat(Ycoord, 1, ws, Ygrid);
448 
449     Xcoord.release();
450     Ycoord.release();
451 
452     Mat templateZM    = Mat(hs, ws, CV_32F);// to store the (smoothed)zero-mean version of template
453     Mat templateFloat = Mat(hs, ws, CV_32F);// to store the (smoothed) template
454     Mat imageFloat    = Mat(hd, wd, CV_32F);// to store the (smoothed) input image
455     Mat imageWarped   = Mat(hs, ws, CV_32F);// to store the warped zero-mean input image
456     Mat imageMask     = Mat(hs, ws, CV_8U); // to store the final mask
457 
458     Mat inputMaskMat = inputMask.getMat();
459     //to use it for mask warping
460     Mat preMask;
461     if(inputMask.empty())
462         preMask = Mat::ones(hd, wd, CV_8U);
463     else
464         threshold(inputMask, preMask, 0, 1, THRESH_BINARY);
465 
466     //gaussian filtering is optional
467     src.convertTo(templateFloat, templateFloat.type());
468     GaussianBlur(templateFloat, templateFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
469 
470     Mat preMaskFloat;
471     preMask.convertTo(preMaskFloat, CV_32F);
472     GaussianBlur(preMaskFloat, preMaskFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
473     // Change threshold.
474     preMaskFloat *= (0.5/0.95);
475     // Rounding conversion.
476     preMaskFloat.convertTo(preMask, preMask.type());
477     preMask.convertTo(preMaskFloat, preMaskFloat.type());
478 
479     dst.convertTo(imageFloat, imageFloat.type());
480     GaussianBlur(imageFloat, imageFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
481 
482     // needed matrices for gradients and warped gradients
483     Mat gradientX = Mat::zeros(hd, wd, CV_32FC1);
484     Mat gradientY = Mat::zeros(hd, wd, CV_32FC1);
485     Mat gradientXWarped = Mat(hs, ws, CV_32FC1);
486     Mat gradientYWarped = Mat(hs, ws, CV_32FC1);
487 
488 
489     // calculate first order image derivatives
490     Matx13f dx(-0.5f, 0.0f, 0.5f);
491 
492     filter2D(imageFloat, gradientX, -1, dx);
493     filter2D(imageFloat, gradientY, -1, dx.t());
494 
495     gradientX = gradientX.mul(preMaskFloat);
496     gradientY = gradientY.mul(preMaskFloat);
497 
498     // matrices needed for solving linear equation system for maximizing ECC
499     Mat jacobian                = Mat(hs, ws*numberOfParameters, CV_32F);
500     Mat hessian                 = Mat(numberOfParameters, numberOfParameters, CV_32F);
501     Mat hessianInv              = Mat(numberOfParameters, numberOfParameters, CV_32F);
502     Mat imageProjection         = Mat(numberOfParameters, 1, CV_32F);
503     Mat templateProjection      = Mat(numberOfParameters, 1, CV_32F);
504     Mat imageProjectionHessian  = Mat(numberOfParameters, 1, CV_32F);
505     Mat errorProjection         = Mat(numberOfParameters, 1, CV_32F);
506 
507     Mat deltaP = Mat(numberOfParameters, 1, CV_32F);//transformation parameter correction
508     Mat error = Mat(hs, ws, CV_32F);//error as 2D matrix
509 
510     const int imageFlags = INTER_LINEAR  + WARP_INVERSE_MAP;
511     const int maskFlags  = INTER_NEAREST + WARP_INVERSE_MAP;
512 
513 
514     // iteratively update map_matrix
515     double rho      = -1;
516     double last_rho = - termination_eps;
517     for (int i = 1; (i <= numberOfIterations) && (fabs(rho-last_rho)>= termination_eps); i++)
518     {
519 
520         // warp-back portion of the inputImage and gradients to the coordinate space of the templateImage
521         if (motionType != MOTION_HOMOGRAPHY)
522         {
523             warpAffine(imageFloat, imageWarped,     map, imageWarped.size(),     imageFlags);
524             warpAffine(gradientX,  gradientXWarped, map, gradientXWarped.size(), imageFlags);
525             warpAffine(gradientY,  gradientYWarped, map, gradientYWarped.size(), imageFlags);
526             warpAffine(preMask,    imageMask,       map, imageMask.size(),       maskFlags);
527         }
528         else
529         {
530             warpPerspective(imageFloat, imageWarped,     map, imageWarped.size(),     imageFlags);
531             warpPerspective(gradientX,  gradientXWarped, map, gradientXWarped.size(), imageFlags);
532             warpPerspective(gradientY,  gradientYWarped, map, gradientYWarped.size(), imageFlags);
533             warpPerspective(preMask,    imageMask,       map, imageMask.size(),       maskFlags);
534         }
535 
536         Scalar imgMean, imgStd, tmpMean, tmpStd;
537         meanStdDev(imageWarped,   imgMean, imgStd, imageMask);
538         meanStdDev(templateFloat, tmpMean, tmpStd, imageMask);
539 
540         subtract(imageWarped,   imgMean, imageWarped, imageMask);//zero-mean input
541         templateZM = Mat::zeros(templateZM.rows, templateZM.cols, templateZM.type());
542         subtract(templateFloat, tmpMean, templateZM,  imageMask);//zero-mean template
543 
544         const double tmpNorm = std::sqrt(countNonZero(imageMask)*(tmpStd.val[0])*(tmpStd.val[0]));
545         const double imgNorm = std::sqrt(countNonZero(imageMask)*(imgStd.val[0])*(imgStd.val[0]));
546 
547         // calculate jacobian of image wrt parameters
548         switch (motionType){
549             case MOTION_AFFINE:
550                 image_jacobian_affine_ECC(gradientXWarped, gradientYWarped, Xgrid, Ygrid, jacobian);
551                 break;
552             case MOTION_HOMOGRAPHY:
553                 image_jacobian_homo_ECC(gradientXWarped, gradientYWarped, Xgrid, Ygrid, map, jacobian);
554                 break;
555             case MOTION_TRANSLATION:
556                 image_jacobian_translation_ECC(gradientXWarped, gradientYWarped, jacobian);
557                 break;
558             case MOTION_EUCLIDEAN:
559                 image_jacobian_euclidean_ECC(gradientXWarped, gradientYWarped, Xgrid, Ygrid, map, jacobian);
560                 break;
561         }
562 
563         // calculate Hessian and its inverse
564         project_onto_jacobian_ECC(jacobian, jacobian, hessian);
565 
566         hessianInv = hessian.inv();
567 
568         const double correlation = templateZM.dot(imageWarped);
569 
570         // calculate enhanced correlation coefficient (ECC)->rho
571         last_rho = rho;
572         rho = correlation/(imgNorm*tmpNorm);
573         if (cvIsNaN(rho)) {
574           CV_Error(Error::StsNoConv, "NaN encountered.");
575         }
576 
577         // project images into jacobian
578         project_onto_jacobian_ECC( jacobian, imageWarped, imageProjection);
579         project_onto_jacobian_ECC(jacobian, templateZM, templateProjection);
580 
581 
582         // calculate the parameter lambda to account for illumination variation
583         imageProjectionHessian = hessianInv*imageProjection;
584         const double lambda_n = (imgNorm*imgNorm) - imageProjection.dot(imageProjectionHessian);
585         const double lambda_d = correlation - templateProjection.dot(imageProjectionHessian);
586         if (lambda_d <= 0.0)
587         {
588             rho = -1;
589             CV_Error(Error::StsNoConv, "The algorithm stopped before its convergence. The correlation is going to be minimized. Images may be uncorrelated or non-overlapped");
590 
591         }
592         const double lambda = (lambda_n/lambda_d);
593 
594         // estimate the update step delta_p
595         error = lambda*templateZM - imageWarped;
596         project_onto_jacobian_ECC(jacobian, error, errorProjection);
597         deltaP = hessianInv * errorProjection;
598 
599         // update warping matrix
600         update_warping_matrix_ECC( map, deltaP, motionType);
601 
602 
603     }
604 
605     // return final correlation coefficient
606     return rho;
607 }
608 
findTransformECC(InputArray templateImage,InputArray inputImage,InputOutputArray warpMatrix,int motionType,TermCriteria criteria,InputArray inputMask)609 double cv::findTransformECC(InputArray templateImage, InputArray inputImage,
610     InputOutputArray warpMatrix, int motionType,
611     TermCriteria criteria,
612     InputArray inputMask)
613 {
614     // Use default value of 5 for gaussFiltSize to maintain backward compatibility.
615     return findTransformECC(templateImage, inputImage, warpMatrix, motionType, criteria, inputMask, 5);
616 }
617 
618 /* End of file. */
619