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) 2013, OpenCV Foundation, 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 the copyright holders 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 #include "tldDetector.hpp"
45 #include "tracking_utils.hpp"
46 
47 namespace cv {
48 inline namespace tracking {
49 namespace impl {
50 namespace tld {
51 		// Calculate offsets for classifiers
prepareClassifiers(int rowstep)52 		void TLDDetector::prepareClassifiers(int rowstep)
53 		{
54 			for (int i = 0; i < (int)classifiers.size(); i++)
55 				classifiers[i].prepareClassifier(rowstep);
56 		}
57 
58 		// Calculate posterior probability, that the patch belongs to the current EC model
ensembleClassifierNum(const uchar * data)59 		double TLDDetector::ensembleClassifierNum(const uchar* data)
60 		{
61 			double p = 0;
62 			for (int k = 0; k < (int)classifiers.size(); k++)
63 				p += classifiers[k].posteriorProbabilityFast(data);
64 			p /= classifiers.size();
65 			return p;
66 		}
67 
computeSminus(const Mat_<uchar> & patch) const68         double TLDDetector::computeSminus(const Mat_<uchar>& patch) const
69         {
70             double sminus = 0.0;
71             Mat_<uchar> modelSample(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
72             for (int i = 0; i < *negNum; i++)
73             {
74                 modelSample.data = &(negExp->data[i * 225]);
75                 sminus = std::max(sminus, 0.5 * (tracking_internal::computeNCC(modelSample, patch) + 1.0));
76             }
77             return sminus;
78         }
79 
80 		// Calculate Relative similarity of the patch (NN-Model)
Sr(const Mat_<uchar> & patch) const81 		double TLDDetector::Sr(const Mat_<uchar>& patch) const
82 		{
83 			double splus = 0.0, sminus = 0.0;
84             Mat_<uchar> modelSample(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
85 			for (int i = 0; i < *posNum; i++)
86 			{
87 				modelSample.data = &(posExp->data[i * 225]);
88                 splus = std::max(splus, 0.5 * (tracking_internal::computeNCC(modelSample, patch) + 1.0));
89 			}
90             sminus = computeSminus(patch);
91 
92 			if (splus + sminus == 0.0)
93 				return 0.0;
94 			return splus / (sminus + splus);
95 		}
96 
SrAndSc(const Mat_<uchar> & patch) const97         std::pair<double, double> TLDDetector::SrAndSc(const Mat_<uchar>& patch) const
98         {
99             double splusC = 0.0, sminus = 0.0, splus = 0.0;
100             Mat_<uchar> modelSample(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
101             int med = tracking_internal::getMedian((*timeStampsPositive));
102             for (int i = 0; i < *posNum; i++)
103             {
104                 modelSample.data = &(posExp->data[i * 225]);
105                 double s = 0.5 * (tracking_internal::computeNCC(modelSample, patch) + 1.0);
106 
107                 if ((int)(*timeStampsPositive)[i] <= med)
108                     splusC = std::max(splusC, s);
109 
110                 splus = std::max(splus, s);
111             }
112             sminus = computeSminus(patch);
113 
114             double sr = (splus + sminus == 0.0) ? 0. : splus / (sminus + splus);
115             double sc = (splusC + sminus == 0.0) ? 0. : splusC / (sminus + splusC);
116 
117             return std::pair<double, double>(sr, sc);
118         }
119 
120 #ifdef HAVE_OPENCL
ocl_Sr(const Mat_<uchar> & patch)121 		double TLDDetector::ocl_Sr(const Mat_<uchar>& patch)
122 		{
123 			double splus = 0.0, sminus = 0.0;
124 
125 
126 			UMat devPatch = patch.getUMat(ACCESS_READ, USAGE_ALLOCATE_DEVICE_MEMORY);
127 			UMat devPositiveSamples = posExp->getUMat(ACCESS_READ, USAGE_ALLOCATE_DEVICE_MEMORY);
128 			UMat devNegativeSamples = negExp->getUMat(ACCESS_READ, USAGE_ALLOCATE_DEVICE_MEMORY);
129 			UMat devNCC(1, 2*MAX_EXAMPLES_IN_MODEL, CV_32FC1, ACCESS_RW, USAGE_ALLOCATE_DEVICE_MEMORY);
130 
131 
132 			ocl::Kernel k;
133 			ocl::ProgramSource src = ocl::tracking::tldDetector_oclsrc;
134 			String error;
135 			ocl::Program prog(src, String(), error);
136 			k.create("NCC", prog);
137 			if (k.empty())
138 				printf("Kernel create failed!!!\n");
139 			k.args(
140 				ocl::KernelArg::PtrReadOnly(devPatch),
141 				ocl::KernelArg::PtrReadOnly(devPositiveSamples),
142 				ocl::KernelArg::PtrReadOnly(devNegativeSamples),
143 				ocl::KernelArg::PtrWriteOnly(devNCC),
144 				*posNum,
145 				*negNum);
146 
147 			size_t globSize = 1000;
148 
149 			if (!k.run(1, &globSize, NULL, false))
150 				printf("Kernel Run Error!!!");
151 
152 			Mat resNCC = devNCC.getMat(ACCESS_READ);
153 
154 			for (int i = 0; i < *posNum; i++)
155 				splus = std::max(splus, 0.5 * (resNCC.at<float>(i) + 1.0));
156 
157 			for (int i = 0; i < *negNum; i++)
158 				sminus = std::max(sminus, 0.5 * (resNCC.at<float>(i+500) +1.0));
159 
160 			if (splus + sminus == 0.0)
161 				return 0.0;
162 			return splus / (sminus + splus);
163 		}
164 
ocl_batchSrSc(const Mat_<uchar> & patches,double * resultSr,double * resultSc,int numOfPatches)165 		void TLDDetector::ocl_batchSrSc(const Mat_<uchar>& patches, double *resultSr, double *resultSc, int numOfPatches)
166 		{
167 			UMat devPatches = patches.getUMat(ACCESS_READ, USAGE_ALLOCATE_DEVICE_MEMORY);
168 			UMat devPositiveSamples = posExp->getUMat(ACCESS_READ, USAGE_ALLOCATE_DEVICE_MEMORY);
169 			UMat devNegativeSamples = negExp->getUMat(ACCESS_READ, USAGE_ALLOCATE_DEVICE_MEMORY);
170 			UMat devPosNCC(MAX_EXAMPLES_IN_MODEL, numOfPatches, CV_32FC1, ACCESS_RW, USAGE_ALLOCATE_DEVICE_MEMORY);
171 			UMat devNegNCC(MAX_EXAMPLES_IN_MODEL, numOfPatches, CV_32FC1, ACCESS_RW, USAGE_ALLOCATE_DEVICE_MEMORY);
172 
173 			ocl::Kernel k;
174 			ocl::ProgramSource src = ocl::tracking::tldDetector_oclsrc;
175 			String error;
176 			ocl::Program prog(src, String(), error);
177 			k.create("batchNCC", prog);
178 			if (k.empty())
179 				printf("Kernel create failed!!!\n");
180 			k.args(
181 				ocl::KernelArg::PtrReadOnly(devPatches),
182 				ocl::KernelArg::PtrReadOnly(devPositiveSamples),
183 				ocl::KernelArg::PtrReadOnly(devNegativeSamples),
184 				ocl::KernelArg::PtrWriteOnly(devPosNCC),
185 				ocl::KernelArg::PtrWriteOnly(devNegNCC),
186 				*posNum,
187 				*negNum,
188 				numOfPatches);
189 
190 			size_t globSize = 2 * numOfPatches*MAX_EXAMPLES_IN_MODEL;
191 
192 			if (!k.run(1, &globSize, NULL, true))
193 				printf("Kernel Run Error!!!");
194 
195 			Mat posNCC = devPosNCC.getMat(ACCESS_READ);
196 			Mat negNCC = devNegNCC.getMat(ACCESS_READ);
197 
198 			//Calculate Srs
199 			for (int id = 0; id < numOfPatches; id++)
200 			{
201 				double spr = 0.0, smr = 0.0, spc = 0.0, smc = 0;
202                 int med = tracking_internal::getMedian((*timeStampsPositive));
203 				for (int i = 0; i < *posNum; i++)
204 				{
205 					spr = std::max(spr, 0.5 * (posNCC.at<float>(id * 500 + i) + 1.0));
206 					if ((int)(*timeStampsPositive)[i] <= med)
207 						spc = std::max(spr, 0.5 * (posNCC.at<float>(id * 500 + i) + 1.0));
208 				}
209 				for (int i = 0; i < *negNum; i++)
210 					smc = smr = std::max(smr, 0.5 * (negNCC.at<float>(id * 500 + i) + 1.0));
211 
212 				if (spr + smr == 0.0)
213 					resultSr[id] = 0.0;
214 				else
215 					resultSr[id] = spr / (smr + spr);
216 
217 				if (spc + smc == 0.0)
218 					resultSc[id] = 0.0;
219 				else
220 					resultSc[id] = spc / (smc + spc);
221 			}
222 		}
223 #endif
224 
225 		// Calculate Conservative similarity of the patch (NN-Model)
Sc(const Mat_<uchar> & patch) const226 		double TLDDetector::Sc(const Mat_<uchar>& patch) const
227 		{
228 			double splus = 0.0, sminus = 0.0;
229 			Mat_<uchar> modelSample(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
230             int med = tracking_internal::getMedian((*timeStampsPositive));
231 			for (int i = 0; i < *posNum; i++)
232 			{
233 				if ((int)(*timeStampsPositive)[i] <= med)
234 				{
235 					modelSample.data = &(posExp->data[i * 225]);
236                     splus = std::max(splus, 0.5 * (tracking_internal::computeNCC(modelSample, patch) + 1.0));
237 				}
238 			}
239             sminus = computeSminus(patch);
240 
241 			if (splus + sminus == 0.0)
242 				return 0.0;
243 
244 			return splus / (sminus + splus);
245 		}
246 
247 #ifdef HAVE_OPENCL
ocl_Sc(const Mat_<uchar> & patch)248 		double TLDDetector::ocl_Sc(const Mat_<uchar>& patch)
249 		{
250 			double splus = 0.0, sminus = 0.0;
251 
252 			UMat devPatch = patch.getUMat(ACCESS_READ, USAGE_ALLOCATE_DEVICE_MEMORY);
253 			UMat devPositiveSamples = posExp->getUMat(ACCESS_READ, USAGE_ALLOCATE_DEVICE_MEMORY);
254 			UMat devNegativeSamples = negExp->getUMat(ACCESS_READ, USAGE_ALLOCATE_DEVICE_MEMORY);
255 			UMat devNCC(1, 2 * MAX_EXAMPLES_IN_MODEL, CV_32FC1, ACCESS_RW, USAGE_ALLOCATE_DEVICE_MEMORY);
256 
257 
258 			ocl::Kernel k;
259 			ocl::ProgramSource src = ocl::tracking::tldDetector_oclsrc;
260 			String error;
261 			ocl::Program prog(src, String(), error);
262 			k.create("NCC", prog);
263 			if (k.empty())
264 				printf("Kernel create failed!!!\n");
265 			k.args(
266 				ocl::KernelArg::PtrReadOnly(devPatch),
267 				ocl::KernelArg::PtrReadOnly(devPositiveSamples),
268 				ocl::KernelArg::PtrReadOnly(devNegativeSamples),
269 				ocl::KernelArg::PtrWriteOnly(devNCC),
270 				*posNum,
271 				*negNum);
272 
273 			size_t globSize = 1000;
274 
275 			if (!k.run(1, &globSize, NULL, false))
276 				printf("Kernel Run Error!!!");
277 
278 			Mat resNCC = devNCC.getMat(ACCESS_READ);
279 
280             int med = tracking_internal::getMedian((*timeStampsPositive));
281 			for (int i = 0; i < *posNum; i++)
282 				if ((int)(*timeStampsPositive)[i] <= med)
283 					splus = std::max(splus, 0.5 * (resNCC.at<float>(i) +1.0));
284 
285 			for (int i = 0; i < *negNum; i++)
286 				sminus = std::max(sminus, 0.5 * (resNCC.at<float>(i + 500) + 1.0));
287 
288 			if (splus + sminus == 0.0)
289 				return 0.0;
290 			return splus / (sminus + splus);
291 		}
292 #endif // HAVE_OPENCL
293 
294 		// Generate Search Windows for detector from aspect ratio of initial BBs
generateScanGrid(int rows,int cols,Size initBox,std::vector<Rect2d> & res,bool withScaling)295 		void TLDDetector::generateScanGrid(int rows, int cols, Size initBox, std::vector<Rect2d>& res, bool withScaling)
296 		{
297 			res.clear();
298 			//Scales step: SCALE_STEP; Translation steps: 10% of width & 10% of height; minSize: 20pix
299 			for (double h = initBox.height, w = initBox.width; h < cols && w < rows;)
300 			{
301 				for (double x = 0; (x + w + 1.0) <= cols; x += (0.1 * w))
302 				{
303 					for (double y = 0; (y + h + 1.0) <= rows; y += (0.1 * h))
304 						res.push_back(Rect2d(x, y, w, h));
305 				}
306 				if (withScaling)
307 				{
308 					if (h <= initBox.height)
309 					{
310 						h /= SCALE_STEP; w /= SCALE_STEP;
311 						if (h < 20 || w < 20)
312 						{
313 							h = initBox.height * SCALE_STEP; w = initBox.width * SCALE_STEP;
314 							CV_Assert(h > initBox.height || w > initBox.width);
315 						}
316 					}
317 					else
318 					{
319 						h *= SCALE_STEP; w *= SCALE_STEP;
320 					}
321 				}
322 				else
323 				{
324 					break;
325 				}
326 			}
327 		}
328 
329 		//Detection - returns most probable new target location (Max Sc)
330 
331 		class CalcScSrParallelLoopBody: public cv::ParallelLoopBody
332 		{
333 		public:
CalcScSrParallelLoopBody(TLDDetector * detector,Size initSize)334 			explicit CalcScSrParallelLoopBody (TLDDetector * detector, Size initSize):
335 				detectorF (detector),
336 				initSizeF (initSize)
337 			{
338 			}
339 
operator ()(const cv::Range & r) const340 			virtual void operator () (const cv::Range & r) const CV_OVERRIDE
341 			{
342 				for (int ind = r.start; ind < r.end; ++ind)
343 				{
344 					resample(detectorF->resized_imgs[detectorF->ensScaleIDs[ind]],
345 						Rect2d(detectorF->ensBuffer[ind], initSizeF),
346 						detectorF->standardPatches[ind]);
347                     std::pair<double, double> values = detectorF->SrAndSc(detectorF->standardPatches[ind]);
348                     detectorF->scValues[ind] = values.second;
349                     detectorF->srValues[ind] = values.first;
350 				}
351 			}
352 
353 			TLDDetector * detectorF;
354 			const Size initSizeF;
355 		private:
356 			CalcScSrParallelLoopBody (const CalcScSrParallelLoopBody&);
357 			CalcScSrParallelLoopBody& operator= (const CalcScSrParallelLoopBody&);
358 		};
359 
detect(const Mat & img,const Mat & imgBlurred,Rect2d & res,std::vector<LabeledPatch> & patches,Size initSize)360 		bool TLDDetector::detect(const Mat& img, const Mat& imgBlurred, Rect2d& res, std::vector<LabeledPatch>& patches, Size initSize)
361 		{
362 			patches.clear();
363 			Mat tmp;
364 			int dx = initSize.width / 10, dy = initSize.height / 10;
365 			Size2d size = img.size();
366 			double scale = 1.0;
367 			int npos = 0, nneg = 0;
368 			double maxSc = -5.0;
369 			Rect2d maxScRect;
370 			int scaleID;
371 
372 			resized_imgs.clear ();
373 			blurred_imgs.clear ();
374 			varBuffer.clear ();
375 			ensBuffer.clear ();
376 			varScaleIDs.clear ();
377 			ensScaleIDs.clear ();
378 
379 			//Detection part
380 			//Generate windows and filter by variance
381 			scaleID = 0;
382 			resized_imgs.push_back(img);
383 			blurred_imgs.push_back(imgBlurred);
384 			do
385 			{
386 				Mat_<double> intImgP, intImgP2;
387 				computeIntegralImages(resized_imgs[scaleID], intImgP, intImgP2);
388 				for (int i = 0, imax = cvFloor((0.0 + resized_imgs[scaleID].cols - initSize.width) / dx); i < imax; i++)
389 				{
390 					for (int j = 0, jmax = cvFloor((0.0 + resized_imgs[scaleID].rows - initSize.height) / dy); j < jmax; j++)
391 					{
392 						if (!patchVariance(intImgP, intImgP2, originalVariancePtr, Point(dx * i, dy * j), initSize))
393 							continue;
394 						varBuffer.push_back(Point(dx * i, dy * j));
395 						varScaleIDs.push_back(scaleID);
396 					}
397 				}
398 				scaleID++;
399 				size.width /= SCALE_STEP;
400 				size.height /= SCALE_STEP;
401 				scale *= SCALE_STEP;
402 				resize(img, tmp, size, 0, 0, DOWNSCALE_MODE);
403 				resized_imgs.push_back(tmp);
404 				GaussianBlur(resized_imgs[scaleID], tmp, GaussBlurKernelSize, 0.0f);
405 				blurred_imgs.push_back(tmp);
406 			} while (size.width >= initSize.width && size.height >= initSize.height);
407 
408 			//Encsemble classification
409 			for (int i = 0; i < (int)varBuffer.size(); i++)
410 			{
411 				prepareClassifiers(static_cast<int> (blurred_imgs[varScaleIDs[i]].step[0]));
412 				if (ensembleClassifierNum(&blurred_imgs[varScaleIDs[i]].at<uchar>(varBuffer[i].y, varBuffer[i].x)) <= ENSEMBLE_THRESHOLD)
413 					continue;
414 				ensBuffer.push_back(varBuffer[i]);
415 				ensScaleIDs.push_back(varScaleIDs[i]);
416 			}
417 
418 			//Batch preparation
419 			srValues.resize (ensBuffer.size());
420 			scValues.resize (ensBuffer.size());
421 
422 			//Carefully resize standard patches with reference-counted Mat members
423 			const int oldPatchesSize = (int)standardPatches.size();
424 			standardPatches.resize (ensBuffer.size());
425 			if ((int)ensBuffer.size() > oldPatchesSize)
426 			{
427 				Mat_<uchar> standardPatch(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
428 				for (int i = oldPatchesSize; i < (int)ensBuffer.size(); ++i)
429 				{
430 					standardPatches[i] = standardPatch.clone();
431 				}
432 			}
433 
434 			//Batch calculation
435 			cv::parallel_for_ (cv::Range (0, (int)ensBuffer.size ()), CalcScSrParallelLoopBody (this, initSize));
436 
437 			//NN classification
438 			for (int i = 0; i < (int)ensBuffer.size(); i++)
439 			{
440 				LabeledPatch labPatch;
441 				double curScale = pow(SCALE_STEP, ensScaleIDs[i]);
442 				labPatch.rect = Rect2d(ensBuffer[i].x*curScale, ensBuffer[i].y*curScale, initSize.width * curScale, initSize.height * curScale);
443 
444 				const double srValue = srValues[i];
445 				const double scValue = scValues[i];
446 
447 				////To fix: Check the paper, probably this cause wrong learning
448 				//
449                 labPatch.isObject = srValue > THETA_NN;
450                 labPatch.shouldBeIntegrated = abs(srValue - THETA_NN) < CLASSIFIER_MARGIN;
451                 patches.push_back(labPatch);
452 				//
453 
454 				if (!labPatch.isObject)
455 				{
456 					nneg++;
457 					continue;
458 				}
459 				else
460 				{
461 					npos++;
462 				}
463 
464 				if (scValue > maxSc)
465 				{
466 					maxSc = scValue;
467 					maxScRect = labPatch.rect;
468 				}
469 			}
470 
471             if (maxSc < 0)
472 				return false;
473 			else
474 			{
475 				res = maxScRect;
476 				return true;
477 			}
478 		}
479 
480 #ifdef HAVE_OPENCL
ocl_detect(const Mat & img,const Mat & imgBlurred,Rect2d & res,std::vector<LabeledPatch> & patches,Size initSize)481 		bool TLDDetector::ocl_detect(const Mat& img, const Mat& imgBlurred, Rect2d& res, std::vector<LabeledPatch>& patches, Size initSize)
482 		{
483 			patches.clear();
484 			Mat_<uchar> standardPatch(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
485 			Mat tmp;
486 			int dx = initSize.width / 10, dy = initSize.height / 10;
487 			Size2d size = img.size();
488 			double scale = 1.0;
489 			int npos = 0, nneg = 0;
490 			double maxSc = -5.0;
491 			Rect2d maxScRect;
492 			int scaleID;
493 			std::vector <Mat> resized_imgs, blurred_imgs;
494 			std::vector <Point> varBuffer, ensBuffer;
495 			std::vector <int> varScaleIDs, ensScaleIDs;
496 
497 			//Detection part
498 			//Generate windows and filter by variance
499 			scaleID = 0;
500 			resized_imgs.push_back(img);
501 			blurred_imgs.push_back(imgBlurred);
502 			do
503 			{
504 				Mat_<double> intImgP, intImgP2;
505 				computeIntegralImages(resized_imgs[scaleID], intImgP, intImgP2);
506 				for (int i = 0, imax = cvFloor((0.0 + resized_imgs[scaleID].cols - initSize.width) / dx); i < imax; i++)
507 				{
508 					for (int j = 0, jmax = cvFloor((0.0 + resized_imgs[scaleID].rows - initSize.height) / dy); j < jmax; j++)
509 					{
510 						if (!patchVariance(intImgP, intImgP2, originalVariancePtr, Point(dx * i, dy * j), initSize))
511 							continue;
512 						varBuffer.push_back(Point(dx * i, dy * j));
513 						varScaleIDs.push_back(scaleID);
514 					}
515 				}
516 				scaleID++;
517 				size.width /= SCALE_STEP;
518 				size.height /= SCALE_STEP;
519 				scale *= SCALE_STEP;
520 				resize(img, tmp, size, 0, 0, DOWNSCALE_MODE);
521 				resized_imgs.push_back(tmp);
522 				GaussianBlur(resized_imgs[scaleID], tmp, GaussBlurKernelSize, 0.0f);
523 				blurred_imgs.push_back(tmp);
524 			} while (size.width >= initSize.width && size.height >= initSize.height);
525 
526 			//Encsemble classification
527 			for (int i = 0; i < (int)varBuffer.size(); i++)
528 			{
529 				prepareClassifiers((int)blurred_imgs[varScaleIDs[i]].step[0]);
530 				if (ensembleClassifierNum(&blurred_imgs[varScaleIDs[i]].at<uchar>(varBuffer[i].y, varBuffer[i].x)) <= ENSEMBLE_THRESHOLD)
531 					continue;
532 				ensBuffer.push_back(varBuffer[i]);
533 				ensScaleIDs.push_back(varScaleIDs[i]);
534 			}
535 
536 			//NN classification
537 			//Prepare batch of patches
538 			int numOfPatches = (int)ensBuffer.size();
539 			Mat_<uchar> stdPatches(numOfPatches, 225);
540 			double *resultSr = new double[numOfPatches];
541 			double *resultSc = new double[numOfPatches];
542 
543 			uchar *patchesData = stdPatches.data;
544 			for (int i = 0; i < (int)ensBuffer.size(); i++)
545 			{
546 				resample(resized_imgs[ensScaleIDs[i]], Rect2d(ensBuffer[i], initSize), standardPatch);
547 				uchar *stdPatchData = standardPatch.data;
548 				for (int j = 0; j < 225; j++)
549 					patchesData[225*i+j] = stdPatchData[j];
550 			}
551 			//Calculate Sr and Sc batches
552 			ocl_batchSrSc(stdPatches, resultSr, resultSc, numOfPatches);
553 
554 
555 			for (int i = 0; i < (int)ensBuffer.size(); i++)
556 			{
557 				LabeledPatch labPatch;
558 				standardPatch.data = &stdPatches.data[225 * i];
559 				double curScale = pow(SCALE_STEP, ensScaleIDs[i]);
560 				labPatch.rect = Rect2d(ensBuffer[i].x*curScale, ensBuffer[i].y*curScale, initSize.width * curScale, initSize.height * curScale);
561 
562 				double srValue, scValue;
563 
564 				srValue = resultSr[i];
565 
566 				////To fix: Check the paper, probably this cause wrong learning
567 				//
568 				labPatch.isObject = srValue > THETA_NN;
569                 labPatch.shouldBeIntegrated = abs(srValue - THETA_NN) < CLASSIFIER_MARGIN;
570 				patches.push_back(labPatch);
571 				//
572 
573 				if (!labPatch.isObject)
574 				{
575 					nneg++;
576 					continue;
577 				}
578 				else
579 				{
580 					npos++;
581 				}
582 				scValue = resultSc[i];
583 				if (scValue > maxSc)
584 				{
585 					maxSc = scValue;
586 					maxScRect = labPatch.rect;
587 				}
588 			}
589 
590 			if (maxSc < 0)
591 				return false;
592 			res = maxScRect;
593 			return true;
594 		}
595 #endif // HAVE_OPENCL
596 
597 		// Computes the variance of subimage given by box, with the help of two integral
598 		// images intImgP and intImgP2 (sum of squares), which should be also provided.
patchVariance(Mat_<double> & intImgP,Mat_<double> & intImgP2,double * originalVariance,Point pt,Size size)599 		bool TLDDetector::patchVariance(Mat_<double>& intImgP, Mat_<double>& intImgP2, double *originalVariance, Point pt, Size size)
600 		{
601 			int x = (pt.x), y = (pt.y), width = (size.width), height = (size.height);
602 			CV_Assert(0 <= x && (x + width) < intImgP.cols && (x + width) < intImgP2.cols);
603 			CV_Assert(0 <= y && (y + height) < intImgP.rows && (y + height) < intImgP2.rows);
604 			double p = 0, p2 = 0;
605 			double A, B, C, D;
606 
607 			A = intImgP(y, x);
608 			B = intImgP(y, x + width);
609 			C = intImgP(y + height, x);
610 			D = intImgP(y + height, x + width);
611 			p = (A + D - B - C) / (width * height);
612 
613 			A = intImgP2(y, x);
614 			B = intImgP2(y, x + width);
615 			C = intImgP2(y + height, x);
616 			D = intImgP2(y + height, x + width);
617 			p2 = (A + D - B - C) / (width * height);
618 
619 			return ((p2 - p * p) > VARIANCE_THRESHOLD * *originalVariance);
620 		}
621 
622 }}}}  // namespace
623