File indexing completed on 2025-01-05 03:58:06
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam 0004 * 0005 * Date : 2013-06-14 0006 * Description : Alignment by Image Congealing. 0007 * Funneling for complex, realistic images 0008 * using sequence of distribution fields learned from congealReal 0009 * Gary B. Huang, Vidit Jain, and Erik Learned-Miller. 0010 * Unsupervised joint alignment of complex images. 0011 * International Conference on Computer Vision (ICCV), 2007. 0012 * Based on Gary B. Huang, UMass-Amherst implementation. 0013 * 0014 * SPDX-FileCopyrightText: 2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0015 * 0016 * SPDX-License-Identifier: GPL-2.0-or-later 0017 * 0018 * ============================================================ */ 0019 0020 #include "funnelreal.h" 0021 0022 // C++ includes 0023 0024 #include <cmath> 0025 #include <iostream> 0026 #include <fstream> 0027 #include <vector> 0028 #include <string> 0029 0030 // Qt includes 0031 0032 #include <QTest> 0033 #include <QFileInfo> 0034 #include <QStandardPaths> 0035 #include <QRandomGenerator> 0036 0037 // Local includes 0038 0039 #include "digikam_debug.h" 0040 #include "dtestdatadir.h" 0041 0042 namespace Digikam 0043 { 0044 0045 class Q_DECL_HIDDEN FunnelReal::Private 0046 { 0047 public: 0048 0049 explicit Private() 0050 : isLoaded (false), 0051 numParams (4), // similarity transforms - x translation, y translation, rotation, uniform scaling 0052 windowSize (4), 0053 maxProcessAtOnce (600), // set based on memory limitations, 0054 outerDimW (150), 0055 outerDimH (150), 0056 innerDimW (100), 0057 innerDimH (100), 0058 siftHistDim (4), 0059 siftBucketsDim (8), 0060 siftDescDim ((4*windowSize*windowSize*siftBucketsDim) / (siftHistDim*siftHistDim)), 0061 numRandPxls (0), 0062 numFeatureClusters(0), 0063 edgeDescDim (0) 0064 { 0065 /* 0066 if (outerDimW - innerDimW < 2*windowSize) 0067 { 0068 qCDebug(DIGIKAM_FACESENGINE_LOG) << "difference between outerDimW and innerDimW is not greater than window size for SIFT descriptor)"; 0069 return -1; 0070 } 0071 0072 if ((outerDimW - innerDimW) % 2 != 0) 0073 { 0074 qCDebug(DIGIKAM_FACESENGINE_LOG) << "shrinking innerDimW by 1 so outerDimW - innerDimW is divisible by 2"; 0075 --innerDimW; 0076 } 0077 0078 if (outerDimH - innerDimH < 2*windowSize) 0079 { 0080 qCDebug(DIGIKAM_FACESENGINE_LOG) << "difference between outerDimH and innerDimH is not greater than window size for SIFT descriptor)"; 0081 return -1; 0082 } 0083 0084 if ((outerDimH - innerDimH) % 2 != 0) 0085 { 0086 qCDebug(DIGIKAM_FACESENGINE_LOG) << "shrinking innerDimH by 1 so outerDimH - innerDimH is divisible by 2"; 0087 --innerDimH; 0088 } 0089 */ 0090 paddingW = ((outerDimW - innerDimW) - 2*windowSize) / 2; 0091 paddingH = ((outerDimH - innerDimH) - 2*windowSize) / 2; 0092 } 0093 0094 void loadTrainingData(const QString& path); 0095 void computeGaussian(std::vector<std::vector<float> >& gaussian, 0096 int windowSize) const; 0097 0098 /// Part 1: Fills originalFeatures from the image data 0099 void computeOriginalFeatures(std::vector<std::vector<std::vector<float> > >& originalFeatures, 0100 const cv::Mat& image, 0101 const int width, 0102 const int height) const; 0103 0104 /// Part 2: Returns a small vector contains transformation parameters 0105 std::vector<float> computeTransform(const std::vector<std::vector<std::vector<float> > >& originalFeatures, 0106 const int width, 0107 const int height) const; 0108 0109 /// Part 3: Applies the transformation (v, form computeTransform) to the given image, returns the result. 0110 cv::Mat applyTransform (const cv::Mat& image, 0111 const std::vector<float>& v, 0112 int h, 0113 int w) const; 0114 0115 // Utilities 0116 void getSIFTdescripter (std::vector<float>& descripter, 0117 const std::vector<std::vector<float> >& m, 0118 const std::vector<std::vector<float> >& theta, 0119 int x, int y, int windowSize, int histDim, int bucketsDim, 0120 const std::vector<std::vector<float> >& Gaussian) const; 0121 0122 float computeLogLikelihood (const std::vector<std::vector<float> >& logDistField, 0123 const std::vector<std::vector<float> >& fids, 0124 int numFeatureClusters) const; 0125 0126 void getNewFeatsInvT (std::vector<std::vector<float> >& newFIDs, 0127 const std::vector<std::vector<std::vector<float> > >& originalFeats, 0128 const std::vector<float>& vparams, 0129 float centerX, 0130 float centerY) const; 0131 0132 public: 0133 0134 bool isLoaded; 0135 0136 const int numParams; 0137 const int windowSize; 0138 const int maxProcessAtOnce; 0139 0140 int outerDimW; 0141 int outerDimH; 0142 int innerDimW; 0143 int innerDimH; 0144 int paddingW; 0145 int paddingH; 0146 0147 const int siftHistDim; 0148 const int siftBucketsDim; 0149 const int siftDescDim; 0150 0151 /// Training data 0152 int numRandPxls; 0153 int numFeatureClusters; 0154 int edgeDescDim; 0155 std::vector<std::vector<float> > centroids; 0156 std::vector<float> sigmaSq; 0157 std::vector<std::pair<int, int> > randPxls; 0158 std::vector<std::vector<std::vector<float> > > logDFSeq; 0159 std::vector<std::vector<float> > Gaussian; 0160 }; 0161 0162 // ----------------------------------------------------------------------------------------------------------------------------- 0163 0164 FunnelReal::FunnelReal() 0165 : d(new Private) 0166 { 0167 QString filesPath = DTestDataDir::TestData(QString::fromUtf8("core/tests/faceengine/alignment")) 0168 .root().path() + QLatin1Char('/'); 0169 qCDebug(DIGIKAM_TESTS_LOG) << "Test Data Dir:" << filesPath; 0170 0171 QString trainingFile = filesPath + QLatin1String("face-funnel.data"); ///< data model file 0172 0173 if (!QFileInfo::exists(trainingFile)) 0174 { 0175 qCritical(DIGIKAM_FACESENGINE_LOG) << "Training data for Congealing/Funnel not found. Should be at" << trainingFile; 0176 0177 return; 0178 } 0179 0180 d->loadTrainingData(trainingFile); 0181 } 0182 0183 FunnelReal::~FunnelReal() 0184 { 0185 delete d; 0186 } 0187 0188 cv::Mat FunnelReal::align(const cv::Mat& inputImage) 0189 { 0190 if (!d->isLoaded) 0191 { 0192 return inputImage; 0193 } 0194 0195 cv::Mat scaled, grey, image; 0196 0197 // resize to outer window size 0198 0199 cv::resize(inputImage, scaled, cv::Size(d->outerDimW, d->outerDimH), 0, 0, 0200 ((d->outerDimW < inputImage.cols) ? cv::INTER_AREA 0201 : cv::INTER_CUBIC)); 0202 0203 // ensure it's grayscale 0204 0205 if (scaled.channels() > 1) 0206 { 0207 cvtColor(scaled, grey, CV_RGB2GRAY); 0208 } 0209 else 0210 { 0211 grey = scaled; 0212 } 0213 0214 // convert to float 0215 0216 grey.convertTo(image, CV_32F); 0217 0218 const int height = image.rows - 2*d->windowSize; 0219 const int width = image.cols - 2*d->windowSize; 0220 0221 std::vector<std::vector<std::vector<float> > > originalFeatures; 0222 0223 d->computeOriginalFeatures(originalFeatures, image, width, height); 0224 0225 std::vector<float> v = d->computeTransform(originalFeatures, width, height); 0226 0227 return (d->applyTransform(inputImage, v, d->outerDimH, d->outerDimW)); 0228 } 0229 0230 void FunnelReal::Private::loadTrainingData(const QString& path) 0231 { 0232 try 0233 { 0234 std::ifstream trainingInfo(path.toLocal8Bit().data()); 0235 trainingInfo.exceptions(std::ifstream::badbit); 0236 0237 trainingInfo >> numFeatureClusters >> edgeDescDim; 0238 0239 std::vector<float> cRow(edgeDescDim, 0); 0240 centroids = std::vector<std::vector<float> >(numFeatureClusters, cRow); 0241 sigmaSq = std::vector<float>(numFeatureClusters); 0242 0243 for (int i = 0 ; i < numFeatureClusters ; ++i) 0244 { 0245 for (int j = 0 ; j < edgeDescDim ; ++j) 0246 { 0247 trainingInfo >> centroids[i][j]; 0248 } 0249 0250 trainingInfo >> sigmaSq[i]; 0251 } 0252 0253 trainingInfo >> numRandPxls; 0254 randPxls = std::vector<std::pair<int, int> >(numRandPxls); 0255 0256 for (int j = 0 ; j < numRandPxls ; ++j) 0257 { 0258 trainingInfo >> randPxls[j].first >> randPxls[j].second; 0259 } 0260 0261 std::vector<float> dfCol(numFeatureClusters, 0); 0262 std::vector<std::vector<float> > logDistField(numRandPxls, dfCol); 0263 0264 int iteration; 0265 0266 while (true) 0267 { 0268 trainingInfo >> iteration; 0269 0270 if (trainingInfo.eof()) 0271 { 0272 break; 0273 } 0274 0275 for (int j = 0 ; j < numRandPxls ; ++j) 0276 { 0277 for (int i = 0 ; i < numFeatureClusters ; ++i) 0278 { 0279 trainingInfo >> logDistField[j][i]; 0280 } 0281 } 0282 0283 logDFSeq.push_back(logDistField); 0284 } 0285 } 0286 catch (const std::ifstream::failure& e) 0287 { 0288 qCritical(DIGIKAM_FACESENGINE_LOG) << "Error loading Congealing/Funnel training data:" << e.what(); 0289 } 0290 catch (...) 0291 { 0292 qCritical(DIGIKAM_FACESENGINE_LOG) << "Default exception"; 0293 } 0294 0295 computeGaussian(Gaussian, windowSize); 0296 0297 isLoaded = true; 0298 } 0299 0300 void FunnelReal::Private::computeGaussian(std::vector<std::vector<float> >& gaussian, int windowSize) const 0301 { 0302 for (int i = 0 ; i < 2*windowSize ; ++i) 0303 { 0304 std::vector<float> grow(2*windowSize); 0305 0306 for (int j = 0 ; j < 2*windowSize ; ++j) 0307 { 0308 float ii = i-(windowSize-0.5f); 0309 float jj = j-(windowSize-0.5f); 0310 grow[j] = exp(-(ii*ii + jj*jj) / (2*windowSize*windowSize)); 0311 } 0312 0313 gaussian.push_back(grow); 0314 } 0315 } 0316 0317 static float dist(const std::vector<float>& a, const std::vector<float>& b) 0318 { 0319 float r = 0; 0320 0321 for (int i = 0 ; i < (signed)a.size() ; ++i) 0322 { 0323 r += (a[i]-b[i])*(a[i]-b[i]); 0324 } 0325 0326 return r; 0327 } 0328 0329 /** 0330 * Main function, part 1 0331 */ 0332 void FunnelReal::Private::computeOriginalFeatures(std::vector<std::vector<std::vector<float> > >& originalFeatures, 0333 const cv::Mat& image, 0334 const int width, 0335 const int height) const 0336 { 0337 std::vector<float> ofEntry(edgeDescDim, 0); 0338 std::vector<std::vector<float> > ofCol(width, ofEntry); 0339 0340 originalFeatures = std::vector<std::vector<std::vector<float> > >(height, ofCol); 0341 0342 std::vector<float> SiftDesc(edgeDescDim); 0343 0344 std::vector<float> mtRow(image.cols); 0345 std::vector<std::vector<float> > m(image.rows, mtRow); 0346 std::vector<std::vector<float> > theta(image.rows, mtRow); 0347 float dx, dy; 0348 0349 for (int j = 0 ; j < image.rows ; ++j) 0350 { 0351 const float* greaterRow; 0352 const float* lesserRow; 0353 const float* row; 0354 row = image.ptr<float>(j); 0355 0356 if (j == 0) 0357 { 0358 greaterRow = image.ptr<float>(j+1); 0359 lesserRow = row; 0360 } 0361 else if (j == image.rows-1) 0362 { 0363 greaterRow = row; 0364 lesserRow = image.ptr<float>(j-1); 0365 } 0366 else 0367 { 0368 greaterRow = image.ptr<float>(j+1); 0369 lesserRow = image.ptr<float>(j-1); 0370 } 0371 0372 for (int k = 0 ; k < image.cols ; ++k) 0373 { 0374 dy = greaterRow[k] - lesserRow[k]; 0375 0376 if (k == 0) 0377 { 0378 dx = row[k+1] - row[k]; 0379 } 0380 else if (k == image.cols-1) 0381 { 0382 dx = row[k] - row[k-1]; 0383 } 0384 else 0385 { 0386 dx = row[k+1] - row[k-1]; 0387 } 0388 0389 m[j][k] = (float)sqrt(dx*dx+dy*dy); 0390 theta[j][k] = (float)atan2(dy,dx) * 180.0f/M_PI; 0391 0392 if (theta[j][k] < 0) 0393 { 0394 theta[j][k] += 360.0f; 0395 } 0396 } 0397 } 0398 0399 for (int j = 0 ; j < height ; ++j) 0400 { 0401 for (int k = 0 ; k < width ; ++k) 0402 { 0403 getSIFTdescripter(SiftDesc, 0404 m, 0405 theta, 0406 j+windowSize, 0407 k+windowSize, 0408 windowSize, 0409 siftHistDim, 0410 siftBucketsDim, 0411 Gaussian); 0412 0413 originalFeatures[j][k] = SiftDesc; 0414 } 0415 } 0416 0417 for (int j = 0 ; j < height ; ++j) 0418 { 0419 for(int k = 0 ; k < width ; ++k) 0420 { 0421 std::vector<float> distances(numFeatureClusters); 0422 float sum = 0; 0423 0424 for (int ii = 0 ; ii < numFeatureClusters ; ++ii) 0425 { 0426 distances[ii] = exp(-dist(originalFeatures[j][k], centroids[ii]) / 0427 (2*sigmaSq[ii])) / sqrt(sigmaSq[ii]); 0428 0429 sum += distances[ii]; 0430 } 0431 0432 for (int ii = 0 ; ii < numFeatureClusters ; ++ii) 0433 { 0434 distances[ii] /= sum; 0435 } 0436 0437 originalFeatures[j][k] = distances; 0438 } 0439 } 0440 } 0441 0442 /** 0443 * Main function, part 2 0444 */ 0445 std::vector<float> FunnelReal::Private::computeTransform(const std::vector<std::vector<std::vector<float> > >& originalFeatures, 0446 const int width, 0447 const int height) const 0448 { 0449 std::vector<float> v(numParams); 0450 0451 std::vector<float> fidsEntry(numFeatureClusters, 0); 0452 std::vector<std::vector<float> > featureIDs(numRandPxls, fidsEntry); 0453 0454 std::vector<float> nfEntry(numFeatureClusters, 0); 0455 std::vector<std::vector<float> > newFIDs(numRandPxls, nfEntry); 0456 float centerX = width/2.0f; 0457 float centerY = height/2.0f; 0458 0459 float d[] = { 0460 1.0f, 0461 1.0f, 0462 (float)M_PI / 180.0f, 0463 0.02f 0464 }; 0465 0466 getNewFeatsInvT(featureIDs, originalFeatures, v, centerX, centerY); 0467 0468 for (uint iter = 0 ; iter < logDFSeq.size() ; ++iter) 0469 { 0470 float oldL = computeLogLikelihood(logDFSeq[iter], featureIDs, numFeatureClusters); 0471 0472 for (int k = 0 ; k < numParams ; ++k) 0473 { 0474 float dn = QRandomGenerator::global()->bounded(-80, 80)/100.0f; 0475 0476 if (k > 1) 0477 { 0478 dn /= 100.0f; 0479 } 0480 0481 v[k] += (d[k] + dn); 0482 0483 getNewFeatsInvT(newFIDs, originalFeatures, v, centerX, centerY); 0484 float newL = computeLogLikelihood(logDFSeq[iter], newFIDs, numFeatureClusters); 0485 0486 if (newL > oldL) 0487 { 0488 featureIDs = newFIDs; 0489 oldL = newL; 0490 } 0491 else 0492 { 0493 v[k] -= (2*(d[k] + dn)); 0494 getNewFeatsInvT(newFIDs, originalFeatures, v, centerX, centerY); 0495 newL = computeLogLikelihood(logDFSeq[iter], newFIDs, numFeatureClusters); 0496 0497 if (newL > oldL) 0498 { 0499 oldL = newL; 0500 featureIDs = newFIDs; 0501 } 0502 else 0503 { 0504 v[k] += (d[k]+dn); 0505 } 0506 } 0507 } 0508 } 0509 0510 return v; 0511 } 0512 0513 cv::Mat FunnelReal::Private::applyTransform(const cv::Mat& image, 0514 const std::vector<float>& v, 0515 int h, 0516 int w) const 0517 { 0518 float cropT1inv[2][3] = {{1 , 0, image.cols/2.0f}, {0, 1, image.rows/2.0f}}; 0519 float cropS1inv[3][3] = {{image.cols/(float)w, 0, 0}, {0, image.rows/(float)h, 0}, {0, 0, 1}}; 0520 float cropS2inv[3][3] = {{w/(float)image.cols, 0, 0}, {0, h/(float)image.rows, 0}, {0, 0, 1}}; 0521 float cropT2inv[3][3] = {{1, 0, -image.cols/2.0f}, {0, 1, -image.rows/2.0f}, {0, 0, 1}}; 0522 0523 float postM[3][3] = {{1, 0, w/2.0f}, {0, 1, h/2.0f}, {0, 0, 1}}; 0524 float preM[3][3] = {{1, 0, -w/2.0f}, {0, 1, -h/2.0f}, {0, 0, 1}}; 0525 0526 float tM[3][3] = {{1, 0, v[0]}, {0, 1, v[1]}, {0,0,1}}; 0527 float rM[3][3] = {{cosf(v[2]), -sinf(v[2]), 0}, {sinf(v[2]), cosf(v[2]), 0}, {0, 0, 1}}; 0528 float sM[3][3] = {{expf(v[3]), 0, 0}, {0, expf(v[3]), 0}, {0, 0, 1}}; 0529 0530 cv::Mat tCVM(3, 3, CV_32FC1, tM); 0531 cv::Mat rCVM(3, 3, CV_32FC1, rM); 0532 cv::Mat sCVM(3, 3, CV_32FC1, sM); 0533 0534 cv::Mat postCVM(3, 3, CV_32FC1, postM); 0535 cv::Mat preCVM(3, 3, CV_32FC1, preM); 0536 0537 cv::Mat cropT1invCVM(2,3, CV_32FC1, cropT1inv); 0538 cv::Mat cropS1invCVM(3,3, CV_32FC1, cropS1inv); 0539 cv::Mat cropS2invCVM(3,3, CV_32FC1, cropS2inv); 0540 cv::Mat cropT2invCVM(3,3, CV_32FC1, cropT2inv); 0541 0542 cv::Mat xform(2, 3, CV_32FC1); 0543 0544 xform = cropT1invCVM * cropS1invCVM; 0545 xform = xform * tCVM; 0546 xform = xform * rCVM; 0547 xform = xform * sCVM; 0548 xform = xform * cropS2invCVM; 0549 xform = xform * cropT2invCVM; 0550 0551 cv::Mat dst;//(image.rows, image.cols, image.type()) 0552 cv::warpAffine(image, dst, xform, image.size(), cv::WARP_INVERSE_MAP /*+ cv::WARP_FILL_OUTLIERS*/ + cv::INTER_CUBIC); 0553 0554 return dst; 0555 } 0556 0557 void FunnelReal::Private::getSIFTdescripter(std::vector<float>& descripter, 0558 const std::vector<std::vector<float> >& m, 0559 const std::vector<std::vector<float> >& theta, 0560 int x, 0561 int y, 0562 int windowSize, 0563 int histDim, 0564 int bucketsDim, 0565 const std::vector<std::vector<float> >& Gaussian) const 0566 { 0567 for (int i = 0 ; i < (signed)descripter.size() ; ++i) 0568 { 0569 descripter[i] = 0; 0570 } 0571 0572 int histDimWidth = 2 * windowSize / histDim; 0573 float degPerBin = 360.0f / bucketsDim; 0574 0575 // weight magnitudes by Gaussian with sigma equal to half window 0576 0577 std::vector<float> mtimesGRow(2*windowSize); 0578 std::vector<std::vector<float> > mtimesG(2*windowSize, mtimesGRow); 0579 0580 for (int i = 0 ; i < 2*windowSize ; ++i) 0581 { 0582 for (int j = 0 ; j < 2*windowSize ; ++j) 0583 { 0584 int xx = x+i-(windowSize-1); 0585 int yy = y+j-(windowSize-1); 0586 mtimesG[i][j] = m[xx][yy] * Gaussian[i][j]; 0587 } 0588 } 0589 0590 // calculate descripter 0591 // using trilinear interpolation 0592 0593 int histBin[2], histX[2], histY[2]; 0594 float dX[2], dY[2], dBin[2]; 0595 0596 for (int i = 0; i < 2*windowSize ; ++i) 0597 { 0598 for (int j = 0 ; j < 2*windowSize ; ++j) 0599 { 0600 histX[0] = i/histDim; 0601 histX[1] = i/histDim; 0602 histY[0] = j/histDim; 0603 histY[1] = j/histDim; 0604 dX[1] = 0; 0605 dY[1] = 0; 0606 0607 int iModHD = i % histDim; 0608 int jModHD = j % histDim; 0609 int histDimD2 = histDim/2; 0610 0611 if ( iModHD >= histDimD2 && i < 2*windowSize - histDimD2 ) 0612 { 0613 histX[1] = histX[0] + 1; 0614 dX[1] = (iModHD + 0.5f - histDimD2) / histDim; 0615 } 0616 0617 if ( iModHD < histDimD2 && i >= histDimD2 ) 0618 { 0619 histX[1] = histX[0] - 1; 0620 dX[1] = (histDimD2 + 0.5f - iModHD) / histDim; 0621 } 0622 0623 if ( jModHD >= histDimD2 && j < 2*windowSize - histDimD2 ) 0624 { 0625 histY[1] = histY[0] + 1; 0626 dY[1] = (jModHD + 0.5f - histDimD2) / histDim; 0627 } 0628 0629 if ( jModHD < histDimD2 && j >= histDimD2) 0630 { 0631 histY[1] = histY[0] - 1; 0632 dY[1] = (histDimD2 + 0.5f - jModHD) / histDim; 0633 } 0634 0635 dX[0] = 1.0f - dX[1]; 0636 dY[0] = 1.0f - dY[1]; 0637 0638 float histAngle = theta[x+i-(windowSize-1)][y+j-(windowSize-1)]; 0639 0640 histBin[0] = (int)(histAngle / degPerBin); 0641 histBin[1] = (histBin[0]+1) % bucketsDim; 0642 dBin[1] = (histAngle - histBin[0]*degPerBin) / degPerBin; 0643 dBin[0] = 1.0f-dBin[1]; 0644 0645 for (int histBinIndex = 0 ; histBinIndex < 2 ; ++histBinIndex) 0646 { 0647 for (int histXIndex = 0; histXIndex < 2 ; ++histXIndex) 0648 { 0649 for (int histYIndex = 0; histYIndex < 2 ; ++histYIndex) 0650 { 0651 int histNum = histX[histXIndex]*histDimWidth + histY[histYIndex]; 0652 int bin = histBin[histBinIndex]; 0653 descripter[histNum*bucketsDim + bin] += (mtimesG[i][j] * dX[histXIndex] * dY[histYIndex] * dBin[histBinIndex]); 0654 } 0655 } 0656 } 0657 } 0658 } 0659 0660 // normalize 0661 // threshold values at .2, renormalize 0662 0663 float sum = 0.0f; 0664 0665 for (int i = 0 ; i < (signed)descripter.size() ; ++i) 0666 { 0667 sum += descripter[i]; 0668 } 0669 0670 if (sum < .0000001f) 0671 { 0672 /* 0673 float dn = 1.0f / (signed)descripter.size(); // is unused, don't know 0674 */ 0675 for (int i = 0 ; i < (signed)descripter.size() ; ++i) 0676 { 0677 descripter[i] = 0; 0678 } 0679 0680 return; 0681 } 0682 0683 for (int i = 0 ; i < (signed)descripter.size() ; ++i) 0684 { 0685 descripter[i] /= sum; 0686 0687 if (descripter[i] > .2f) 0688 { 0689 descripter[i] = .2f; 0690 } 0691 } 0692 0693 sum = 0.0f; 0694 0695 for (int i = 0 ; i < (signed)descripter.size() ; ++i) 0696 { 0697 sum += descripter[i]; 0698 } 0699 0700 for (int i = 0 ; i < (signed)descripter.size() ; ++i) 0701 { 0702 descripter[i] /= sum; 0703 } 0704 } 0705 0706 void FunnelReal::Private::getNewFeatsInvT(std::vector<std::vector<float> >& newFIDs, 0707 const std::vector<std::vector<std::vector<float> > >& originalFeats, 0708 const std::vector<float>& vparams, 0709 float centerX, 0710 float centerY) const 0711 { 0712 int numFeats = (int)newFIDs[0].size(); 0713 std::vector<float> uniformDist(numFeats, 1.0f/numFeats); 0714 0715 float postM[2][3] = {{1, 0, centerX}, {0, 1, centerY}}; 0716 float preM[3][3] = {{1, 0, -centerX}, {0, 1, -centerY}, {0, 0, 1}}; 0717 0718 float tM[3][3] = {{1, 0, vparams[0]}, {0, 1, vparams[1]}, {0, 0, 1}}; 0719 float rM[3][3] = {{cosf(vparams[2]), -sinf(vparams[2]), 0}, {sinf(vparams[2]), cosf(vparams[2]), 0}, {0, 0, 1}}; 0720 float sM[3][3] = {{expf(vparams[3]), 0, 0}, {0, expf(vparams[3]), 0}, {0, 0, 1}}; 0721 0722 cv::Mat tCVM(3, 3, CV_32FC1, tM); 0723 cv::Mat rCVM(3, 3, CV_32FC1, rM); 0724 cv::Mat sCVM(3, 3, CV_32FC1, sM); 0725 0726 cv::Mat postCVM(2, 3, CV_32FC1, postM); 0727 cv::Mat preCVM(3, 3, CV_32FC1, preM); 0728 0729 cv::Mat xform(2, 3, CV_32FC1); 0730 xform = postCVM * tCVM; 0731 xform = xform * rCVM; 0732 xform = xform * sCVM; 0733 xform = xform * preCVM; 0734 0735 int height = (signed)originalFeats.size(); 0736 int width = (signed)originalFeats[0].size(); 0737 0738 for (int i = 0 ; i < (signed)newFIDs.size() ; ++i) 0739 { 0740 int j = randPxls[i].first; 0741 int k = randPxls[i].second; 0742 int nx = (int)(xform.at<float>(0)*k + xform.at<float>(1)*j + xform.at<float>(2) + 0.5f); 0743 int ny = (int)(xform.at<float>(3)*k + xform.at<float>(4)*j + xform.at<float>(5) + 0.5f); 0744 0745 if (!(ny >= 0 && ny < height && nx >= 0 && nx < width)) 0746 { 0747 newFIDs[i] = uniformDist; 0748 } 0749 else 0750 { 0751 newFIDs[i] = originalFeats[ny][nx]; 0752 } 0753 } 0754 } 0755 0756 float FunnelReal::Private::computeLogLikelihood(const std::vector<std::vector<float> >& logDistField, 0757 const std::vector<std::vector<float> >& fids, 0758 int numFeatureClusters) const 0759 { 0760 float l = 0.0f; 0761 0762 for (int j = 0 ; j < (signed)fids.size() ; ++j) 0763 { 0764 for (int i = 0 ; i < numFeatureClusters ; ++i) 0765 { 0766 l += fids[j][i] * logDistField[j][i]; 0767 } 0768 } 0769 0770 return l; 0771 } 0772 0773 } // namespace Digikam