/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2013, OpenCV Foundation, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of the copyright holders may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ #include "tldEnsembleClassifier.hpp" namespace cv { namespace tld { // Constructor TLDEnsembleClassifier::TLDEnsembleClassifier(const std::vector<Vec4b>& meas, int beg, int end) :lastStep_(-1) { int posSize = 1, mpc = end - beg; for (int i = 0; i < mpc; i++) posSize *= 2; posAndNeg.assign(posSize, Point2i(0, 0)); measurements.assign(meas.begin() + beg, meas.begin() + end); offset.assign(mpc, Point2i(0, 0)); } // Calculate measure locations from 15x15 grid on minSize patches void TLDEnsembleClassifier::stepPrefSuff(std::vector<Vec4b>& arr, int pos, int len, int gridSize) { #if 0 int step = len / (gridSize - 1), pref = (len - step * (gridSize - 1)) / 2; for (int i = 0; i < (int)(sizeof(x1) / sizeof(x1[0])); i++) arr[i] = pref + arr[i] * step; #else int total = len - gridSize; int quo = total / (gridSize - 1), rem = total % (gridSize - 1); int smallStep = quo, bigStep = quo + 1; int bigOnes = rem, smallOnes = gridSize - bigOnes - 1; int bigOnes_front = bigOnes / 2, bigOnes_back = bigOnes - bigOnes_front; for (int i = 0; i < (int)arr.size(); i++) { if (arr[i].val[pos] < bigOnes_back) { arr[i].val[pos] = (uchar)(arr[i].val[pos] * bigStep + arr[i].val[pos]); continue; } if (arr[i].val[pos] < (bigOnes_front + smallOnes)) { arr[i].val[pos] = (uchar)(bigOnes_front * bigStep + (arr[i].val[pos] - bigOnes_front) * smallStep + arr[i].val[pos]); continue; } if (arr[i].val[pos] < (bigOnes_front + smallOnes + bigOnes_back)) { arr[i].val[pos] = (uchar)(bigOnes_front * bigStep + smallOnes * smallStep + (arr[i].val[pos] - (bigOnes_front + smallOnes)) * bigStep + arr[i].val[pos]); continue; } arr[i].val[pos] = (uchar)(len - 1); } #endif } // Calculate offsets for classifier void TLDEnsembleClassifier::prepareClassifier(int rowstep) { if (lastStep_ != rowstep) { lastStep_ = rowstep; for (int i = 0; i < (int)offset.size(); i++) { offset[i].x = rowstep * measurements[i].val[2] + measurements[i].val[0]; offset[i].y = rowstep * measurements[i].val[3] + measurements[i].val[1]; } } } // Integrate patch into the Ensemble Classifier model void TLDEnsembleClassifier::integrate(const Mat_<uchar>& patch, bool isPositive) { int position = code(patch.data, (int)patch.step[0]); if (isPositive) posAndNeg[position].x++; else posAndNeg[position].y++; } // Calculate posterior probability on the patch double TLDEnsembleClassifier::posteriorProbability(const uchar* data, int rowstep) const { int position = code(data, rowstep); double posNum = (double)posAndNeg[position].x, negNum = (double)posAndNeg[position].y; if (posNum == 0.0 && negNum == 0.0) return 0.0; else return posNum / (posNum + negNum); } double TLDEnsembleClassifier::posteriorProbabilityFast(const uchar* data) const { int position = codeFast(data); double posNum = (double)posAndNeg[position].x, negNum = (double)posAndNeg[position].y; if (posNum == 0.0 && negNum == 0.0) return 0.0; else return posNum / (posNum + negNum); } // Calculate the 13-bit fern index int TLDEnsembleClassifier::codeFast(const uchar* data) const { int position = 0; for (int i = 0; i < (int)measurements.size(); i++) { position = position << 1; if (data[offset[i].x] < data[offset[i].y]) position++; } return position; } int TLDEnsembleClassifier::code(const uchar* data, int rowstep) const { int position = 0; for (int i = 0; i < (int)measurements.size(); i++) { position = position << 1; if (*(data + rowstep * measurements[i].val[2] + measurements[i].val[0]) < *(data + rowstep * measurements[i].val[3] + measurements[i].val[1])) { position++; } } return position; } // Create fern classifiers int TLDEnsembleClassifier::makeClassifiers(Size size, int measurePerClassifier, int gridSize, std::vector<TLDEnsembleClassifier>& classifiers) { std::vector<Vec4b> measurements; //Generate random measures for 10 ferns x 13 measures for (int i = 0; i < 10*measurePerClassifier; i++) { Vec4b m; m.val[0] = rand() % 15; m.val[1] = rand() % 15; m.val[2] = rand() % 15; m.val[3] = rand() % 15; measurements.push_back(m); } //Warp measures to minSize patch coordinates stepPrefSuff(measurements, 0, size.width, gridSize); stepPrefSuff(measurements, 1, size.width, gridSize); stepPrefSuff(measurements, 2, size.height, gridSize); stepPrefSuff(measurements, 3, size.height, gridSize); //Compile fern classifiers for (int i = 0, howMany = (int)measurements.size() / measurePerClassifier; i < howMany; i++) classifiers.push_back(TLDEnsembleClassifier(measurements, i * measurePerClassifier, (i + 1) * measurePerClassifier)); return (int)classifiers.size(); } } }