我正在尝试在C++中实现P. Viola和M. Jones的检测框架(起初是简单的序列分类器 – 不是级联版本)。我认为我已经设计了所有必需的类和模块(例如积分图像,Haar特征),但有一个最重要的部分我还没有完成:AdaBoost核心算法。
我已经阅读了P. Viola和M. Jones的原始论文和许多其他出版物。不幸的是,我仍然不明白如何为一个弱分类器找到最佳阈值?我只找到了关于“加权中位数”和“高斯分布”算法的少量参考资料,以及许多数学公式…
我尝试使用OpenCV Train Cascade模块源代码作为模板,但它非常复杂,进行代码逆向工程非常耗时。我还编写了自己的简单代码来理解自适应提升的概念。
问题是:你能解释一下为一个弱分类器计算最佳阈值的最佳方法吗?
下面我展示了AdaBoost的伪代码,这是从Google找到的样本中重写的,但我并不确信这是正确的做法。计算一个弱分类器非常慢(几个小时),我特别对计算最佳阈值的方法有疑问。
(1) AdaBoost::FindNewWeakClassifier(2) AdaBoost::CalculateFeatures(3) AdaBoost::FindBestThreshold(4) AdaBoost::FindFeatureError(5) AdaBoost::NormalizeWeights(6) AdaBoost::FindLowestError(7) AdaBoost::ClassifyExamples(8) AdaBoost::UpdateWeightsDESCRIPTION (1)-生成检测窗口中所有可能的特征排列并放入向量中DO IN LOOP -运行主要计算函数 (2)ENDDESCRIPTION(2)-归一化权重 (5)DO FOR EACH HAAR FEATURE -从列表中依次将下一个特征放置在所有积分图像上 -为每个特征找到最佳阈值 (3) -在当前迭代中为每个最佳特征找到错误 (4) -在数组中保存当前迭代中每个最佳特征的错误 -在数组中保存当前迭代中每个最佳特征的阈值 -在数组中保存当前迭代中每个最佳特征的阈值符号END LOOP-查找上述循环中选择的具有最低错误的分类器索引 (6)-从最佳特征中获取错误值-计算所有积分图像中最佳特征的值 (7)-更新权重 (8)-将新的弱分类器添加到向量中DESCRIPTION (3)-计算每个特征阈值在正样本积分图像上的错误 - 分别计算“+”和“-”符号 (4)-返回具有最低错误的特征的阈值和符号DESCRIPTION(4)- 通过计算不等式 f(x) * sign < sign * threshold 为所有样本返回特征错误DESCRIPTION (5)-确保样本权重是概率分布DESCRIPTION (6)-查找具有最低错误的分类器DESCRIPTION (7)-计算所有积分图像中最佳特征的值-计算假阳性数量和假阴性数量DESCRIPTION (8)-根据分类结果修正权重
感谢任何帮助
回答:
在原始的Viola-Jones论文这里,第3.1节学习讨论(确切地说是第4段),你会找到寻找最佳阈值的程序。
我将在下面快速总结一下方法。
每个特征的最佳阈值取决于样本权重,因此在每次AdaBoost迭代中计算。最佳弱分类器的阈值如伪代码中所述被保存下来。
在每一轮中,对于每个弱分类器,你必须根据特征值排列N个训练样本。设置一个阈值将这个序列分成两部分。两部分中的大多数样本将是正样本或负样本,同时还有一些其他类型的样本。
T+
: 正样本权重的总和T-
: 负样本权重的总和S+
: 阈值以下正样本权重的总和S-
: 阈值以下负样本权重的总和
这个特定阈值的错误是 –
e = MIN((S+) + (T-) - (S-), (S-) + (T+) - (S+))
为什么是最小值?这里有一个例子:
如果样本和阈值像这样 –
+ + + + + - - | + + - - - - -
在第一轮中,如果所有权重相等(=w),取最小值将给你4*w
的错误,而不是10*w
。
你要为所有N种可能的样本分隔方式计算这个错误。
最小错误将给你阈值值的范围。实际的阈值可能是相邻特征值的平均值(不过我不确定,需对此进行一些研究)。
这是你在DO FOR EACH HAAR FEATURE
循环中的第二步。
与OpenCV一起提供的级联是由Rainer Lienhart创建的,我不知道他使用了什么方法。你可以仔细跟随OpenCV源代码,以获得对这个程序的进一步改进。