自适应提升(Adaptive Boosting,Adaboost)算法是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器集合起来,构成一个更强的最终分类器(强分类器)。
主要步骤:
- 先通过对N个训练样本的学习得到第一个弱分类器
- 将分错的样本和其他的新数据一起构成一个新的N个的训练样本,通过对这个样本的学习得到第二个弱分类器
- 将1和2都分错了的样本加上其他的新样本构成另一个新的N个的训练样本,通过对这个样本的学习得到第三个弱分类器
- 最终经过提升的强分类器;即某个数据被分为哪一类要由各分类器权值决定。
由Adaboost算法的描述过程可知,该算法在实现过程中根据训练集的大小初始化样本权值,使其满足均匀分布,在后续操作中通过公式来改变和规范化算法迭代后样本的权值。样本被错误分类导致权值增大,反之权值相应减小,这表示被错分的训练样本集包括一个更高的权重。这就会使在下轮时训练样本集更注重于难以识别的样本,针对被错分样本的进一步学习来得到下一个弱分类器,直到样本被正确分类。在达到规定的迭代次数或者预期的误差率时,则强分类器构建完成。
OpenCV中使用决策树来得到弱分类器的。
测试用例:使用AdaBoost算法判断新的坐标(55,25)是属于红点还是绿点;
#include<iostream>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/ml/ml.hpp>
using namespace std;
using namespace cv;
using namespace cv::ml;
struct TrainData_s
{
int x;
int y;
int label;
};
cv::Scalar color[4] = { {0,0,255}, {0, 255, 0}, {255,0,0}, {255,0,255} };
static bool readTestData(const char *path, Mat &trainDataMat, Mat &labelsMat, Mat &showImage) {
// read maplist for warping
FILE *fp_list_sec = fopen(path, "r+");
if (!fp_list_sec) {
printf("Error in open fp_list_sec from %s\n", path);
return false;
}
int traindata_num = 0;
int n = fscanf(fp_list_sec, "%d\n", &traindata_num);
if (1 != n) {
fclose(fp_list_sec);
return false;
}
n = 3;
trainDataMat = cv::Mat(traindata_num, n-1, CV_32FC1);
labelsMat = cv::Mat(traindata_num,1, CV_32SC1);
int index = 0;
int x = 0;
int y = 0;
int label = 0;
while (3 == n) {
n = fscanf(fp_list_sec, "%d %d %d\n",&x, &y, &label);
if (3 == n) {
trainDataMat.ptr<float>(index)[0] = x;
trainDataMat.ptr<float>(index)[1] = y;
labelsMat.ptr<signed int>(index)[0] = label;
index++;
cv::circle(showImage, cv::Point(x, y), 0, color[label], 1, 8, 0);
}
}
fclose(fp_list_sec);
if (index != traindata_num) {
printf("Attention: point number not equal to predefined num in file [%s]\n", path);
}
return true;
}
int main(int argc, char *argv[])
{
//训练样本
std::string data_path = "D:\\work\\vs2017project\\data\\test_data_adaboost.txt";
cv::Mat trainDataMat, labelsMat;
int rows = 80;
int cols = 120;
cv::Mat showImage(rows, cols, CV_8UC3, cv::Scalar(255, 255, 255));
readTestData(data_path.data(), trainDataMat, labelsMat, showImage);
//建立模型
Ptr<Boost> boost = Boost::create();
boost->setBoostType(Boost::GENTLE);
boost->setWeakCount(100);
boost->setWeightTrimRate(0.95);
boost->setMaxDepth(2);
boost->setUseSurrogates(false);
boost->setPriors(Mat());
//创建TrainData并进行训练
Ptr<TrainData> tData = TrainData::create(trainDataMat, ROW_SAMPLE, labelsMat);
boost->train(tData);
float myData[2] = {55, 25};//测试样本
Mat myDataMat(1, 2, CV_32FC1, myData);
//利用训练好的分类器进行测试样本预测
cv::Mat rMat;
int r = (int)boost->predict(myDataMat, rMat, false);
std::cout << "result: " << r << endl;
cv::circle(showImage, cv::Point(myData[0], myData[1]), 1, color[r], -1);
return 0;
}
预测结果:红色点