本序列文章的目的是总结一下这段时间所学到的,主要分为以下几部分,本章是第五部分。
1 算法概述
2 runtld.cpp源码解析
3 tld.cpp源码解析
4 LKTracker(重点)
5 FerNNClassifier.cpp源码解析(重点)
6 tld_utils.cpp源码解析
方差分类器
代码中是通过积分图来计算一个图的灰度值的方差的。
fern分类器
a先讲解一下一个图的fern特征。
这个fern分类器分为10个小的分类器(10棵树),
每棵树有13个节点,一个图被这13个节点处理后会变为13位的二进制码(比如0011001100010)。
10棵树处理后,就会产生10个13位的二进制码。就是该图的fern特征。
b上面提高一个图会被一棵树的13个节点处理,那么这个特征抽取过程是怎么样的呢?下面讲解。
A分类器的初始化
一棵树的初始化工作,根据一个patch的大小,随机均匀产生点对的集合,就是13个点对。所谓点对,就是两个点,比如(1,1)和(1,5),表示两个像素在图像的位置,这些点以后用来定位像素。
10棵树的初始化就是重复上面的操作了。
B计算一个patch(指定大小的图)的fern特征
先看看一个patch如何被一棵树处理。
一棵树其实就是13个点对的集合,每个点对处理一次,比如这个点对(2,4)和(5,6),把这两个点在patch的像素找出来比较大小,返回1或者0。13个点对就得到13个1或者0了。这样一个patch就被一棵树处理为一个13位的二进制码了。
一个patch的fern特征就是被10棵树处理后的10个13位二进制码了。
c训练过程
A先验概率:每个fern特征在每棵树下都对应有一个先验概率。
比如计算fern特征在第i棵树的先验概率:
令idx=fern[i],则
posteriors[i][idx]= ((float)(pCounter[i][idx]))/(pCounter[i][idx]+nCounter[i][idx]);
其中,
pCounter[i][idx]对于第i棵树,含有idx特征的正样本的数量
nCounter[i][idx]对于第i棵树,含有idx特征的负样本的数量
B训练的过程,就是根据新的正负样本,不断更新pCounter和nCounter,posteriors的值。
如果每一个新进来的样本,要通过之前的先验概率的和对它进行权重的判断,要跟某个阈值比较,符合条件才用新来的样本来更新posteriors。
d分类
其实就是对fern特征进行权值衡量,判断大于还是小于某个阈值。
Nnc分类器
所有的patch要处理为15*15的大小。
训练:每进来一个新的样本patch,先将这个patch将之前保存的所有正的负的patch做比较,算出一个相似度的值,如果这个相似度跟某个阈值比较符合条件,就将这个新样本添加到库中。
那么这个相似度是怎么算的呢?
先说说一个patch和另一个patch的相似度怎么算。
代码中用的是库函数,算法是CV_TM_CCORR_NORMED(网上翻译为归一化相关匹配法)。
http://www.cnblogs.com/xrwang/archive/2010/02/05/MatchTemplate.html
我看论文提到的是
Similaritybetween two patches pi , pj is defined as
S(pi, pj ) = 0.5(NCC(pi , pj ) + 1),
whereNCC is a Normalized Correlation Coefficient.
NormalizedCorrelation Coefficient网上翻译为归一化相关系数
这里先不管究竟哪种算法好。
总之,一个pacth跟库中所有正样本比较,算出最大相似度,也跟所有负样本算出最大相似度。
两者结合算出相对相似度和保守相似读。(具体细节看代码)
-
-
-
-
-
-
-
- #include <FerNNClassifier.h>
-
- using namespace cv;
- using namespace std;
-
- void FerNNClassifier::read(const FileNode& file){
-
- valid = (float)file["valid"];
- ncc_thesame = (float)file["ncc_thesame"];
- nstructs = (int)file["num_trees"];
- structSize = (int)file["num_features"];
- thr_fern = (float)file["thr_fern"];
- thr_nn = (float)file["thr_nn"];
- thr_nn_valid = (float)file["thr_nn_valid"];
- }
-
-
-
-
-
- void FerNNClassifier::prepare(const vector<Size>& scales){
- acum = 0;
-
- int totalFeatures = nstructs*structSize;
- features = vector<vector<Feature> >(scales.size(),vector<Feature> (totalFeatures));
- RNG& rng = theRNG();
- float x1f,x2f,y1f,y2f;
- int x1, x2, y1, y2;
- for (int i=0;i<totalFeatures;i++){
- x1f = (float)rng;
- y1f = (float)rng;
- x2f = (float)rng;
- y2f = (float)rng;
- for (int s=0;s<scales.size();s++){
- x1 = x1f * scales[s].width;
- y1 = y1f * scales[s].height;
- x2 = x2f * scales[s].width;
- y2 = y2f * scales[s].height;
- features[s][i] = Feature(x1, y1, x2, y2);
- }
-
- }
-
- thrN = 0.5*nstructs;
-
-
- for (int i = 0; i<nstructs; i++) {
- posteriors.push_back(vector<float>(pow(2.0,structSize), 0));
- pCounter.push_back(vector<int>(pow(2.0,structSize), 0));
- nCounter.push_back(vector<int>(pow(2.0,structSize), 0));
- }
- }
-
-
-
-
-
-
- void FerNNClassifier::getFeatures(const cv::Mat& image,const int& scale_idx, vector<int>& fern){
- int leaf;
- for (int t=0;t<nstructs;t++){
- leaf=0;
- for (int f=0; f<structSize; f++){
- leaf = (leaf << 1) + features[scale_idx][t*nstructs+f](image);
-
-
- }
- fern[t]=leaf;
- }
- }
-
-
-
- float FerNNClassifier::measure_forest(vector<int> fern) {
- float votes = 0;
- for (int i = 0; i < nstructs; i++) {
- votes += posteriors[i][fern[i]];
- }
- return votes;
- }
-
-
-
-
-
- void FerNNClassifier::update(const vector<int>& fern, int C, int N) {
- int idx;
- for (int i = 0; i < nstructs; i++) {
- idx = fern[i];
- (C==1) ? pCounter[i][idx] += N : nCounter[i][idx] += N;
-
- if (pCounter[i][idx]==0) {
- posteriors[i][idx] = 0;
- } else {
- posteriors[i][idx] = ((float)(pCounter[i][idx]))/(pCounter[i][idx] + nCounter[i][idx]);
- }
- }
- }
-
-
-
- void FerNNClassifier::trainF(const vector<std::pair<vector<int>,int> >& ferns,int resample){
-
-
-
-
-
-
-
- thrP = thr_fern*nstructs;
-
- for (int i = 0; i < ferns.size(); i++){
-
-
-
- if(ferns[i].second==1){
- if(measure_forest(ferns[i].first)<=thrP)
- update(ferns[i].first,1,1);
- }else{
- if (measure_forest(ferns[i].first) >= thrN)
- update(ferns[i].first,0,1);
- }
- }
-
- }
-
- void FerNNClassifier::trainNN(const vector<cv::Mat>& nn_examples){
- float conf,dummy;
- vector<int> y(nn_examples.size(),0);
- y[0]=1;
- vector<int> isin;
- for (int i=0;i<nn_examples.size();i++){
- NNConf(nn_examples[i],isin,conf,dummy);
- if (y[i]==1 && conf<=thr_nn){
- if (isin[1]<0){
- pEx = vector<Mat>(1,nn_examples[i]);
- continue;
- }
-
- pEx.push_back(nn_examples[i]);
- }
- if(y[i]==0 && conf>0.5)
- nEx.push_back(nn_examples[i]);
-
- }
- acum++;
- printf("%d. Trained NN examples: %d positive %d negative\n",acum,(int)pEx.size(),(int)nEx.size());
- }
-
-
-
-
-
-
- void FerNNClassifier::NNConf(const Mat& example, vector<int>& isin,float& rsconf,float& csconf){
-
-
-
-
-
- isin=vector<int>(3,-1);
- if (pEx.empty()){
- rsconf = 0;
- csconf=0;
- return;
- }
- if (nEx.empty()){
- rsconf = 1;
- csconf=1;
- return;
- }
- Mat ncc(1,1,CV_32F);
- float nccP,csmaxP,maxP=0;
- bool anyP=false;
- int maxPidx,validatedPart = ceil(pEx.size()*valid);
- float nccN, maxN=0;
- bool anyN=false;
- for (int i=0;i<pEx.size();i++){
- matchTemplate(pEx[i],example,ncc,CV_TM_CCORR_NORMED);
- nccP=(((float*)ncc.data)[0]+1)*0.5;
- if (nccP>ncc_thesame)
- anyP=true;
- if(nccP > maxP){
- maxP=nccP;
- maxPidx = i;
- if(i<validatedPart)
- csmaxP=maxP;
- }
- }
- for (int i=0;i<nEx.size();i++){
- matchTemplate(nEx[i],example,ncc,CV_TM_CCORR_NORMED);
- nccN=(((float*)ncc.data)[0]+1)*0.5;
- if (nccN>ncc_thesame)
- anyN=true;
- if(nccN > maxN)
- maxN=nccN;
- }
-
- if (anyP) isin[0]=1;
- isin[1]=maxPidx;
- if (anyN) isin[2]=1;
-
- float dN=1-maxN;
- float dP=1-maxP;
- rsconf = (float)dN/(dN+dP);
-
- dP = 1 - csmaxP;
- csconf =(float)dN / (dN + dP);
- }
-
-
-
-
- void FerNNClassifier::evaluateTh(const vector<pair<vector<int>,int> >& nXT,const vector<cv::Mat>& nExT){
- float fconf;
- for (int i=0;i<nXT.size();i++){
- fconf = (float) measure_forest(nXT[i].first)/nstructs;
- if (fconf>thr_fern)
- thr_fern=fconf;
- }
- vector <int> isin;
- float conf,dummy;
- for (int i=0;i<nExT.size();i++){
- NNConf(nExT[i],isin,conf,dummy);
- if (conf>thr_nn)
- thr_nn=conf;
- }
- if (thr_nn>thr_nn_valid)
- thr_nn_valid = thr_nn;
- }
-
- void FerNNClassifier::show(){
- Mat examples((int)pEx.size()*pEx[0].rows,pEx[0].cols,CV_8U);
- double minval;
- Mat ex(pEx[0].rows,pEx[0].cols,pEx[0].type());
- for (int i=0;i<pEx.size();i++){
- minMaxLoc(pEx[i],&minval);
- pEx[i].copyTo(ex);
- ex = ex-minval;
- Mat tmp = examples.rowRange(Range(i*pEx[i].rows,(i+1)*pEx[i].rows));
- ex.convertTo(tmp,CV_8U);
- }
- imshow("Examples",examples);
- }
注:
原作者是用matlab实现的,我分析的源码是其他大神用c++和OpenCV实现的,源码可以从
https://github.com/arthurv/OpenTLD或者https://github.com/alantrrs/OpenTLD下载
本序列参考了zouxy09同学的序列文章,在此表示感谢
http://blog.csdn.NET/zouxy09/article/details/7893011
0 0