opencv中有两个函数可以训练分类器opencv_haartraining.exe和opencv_traincascade.exe,前者只能训练haar特征,后者可以用HAAR、LBP和HOG特征训练分类器。这两个函数都可以在opencv\build\x86\vc10\bin文件夹下找到。opencv_traincascade.exe训练的是adaboost的级联分类器,这里不讲adaboost的级联分类器的原理,具体讲解用opencv_traincascade.exe来训练一个分类器的步骤。
步骤:
一、获取样本
首先要采集正样本和负样本。以行人检测为例,正样本就是各种各样的行人,负样本就是非人照片。样本个数最好在上千个,个数太少训练出来的分类器不能准确的检测行人,网上对正负样本的个数比例不尽相同,有的说3:1有的说7:3,具体的还是要自己去实验,把正负样本分别放在不同的文件夹下,可以命名为pos、neg。正负样本的图片都需要建立描述文件,文件是txt文件,里面存放的是正负样本的相对路径,正样本除存放相对路径外,还需要标出目标所在图像中的位置,如下图所示。
下面代码是获取正负样本及txt描述文件的鼠标回调代码:
void on_mouse(int event, int x, int y, int flags, void *ustc)
{
static Point pre_pt(-1, -1);
static Point cur_pt(-1, -1);
if (event == CV_EVENT_LBUTTONDOWN)
{
gray.copyTo(img);
pre_pt = Point(x, y);
}
else if (event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON))//摁下左键,flags为1
{
img.copyTo(tmp);
cur_pt = Point(x, y);
rectangle(tmp, pre_pt, cur_pt, Scalar(0, 255, 0, 0), 2, 8, 0);
imshow("img", tmp);
}
else if (event == CV_EVENT_LBUTTONUP)
{
gray.copyTo(img);
img.copyTo(tmp);
cur_pt = Point(x, y);
rectangle(tmp, pre_pt, cur_pt, Scalar(0, 255, 0, 0), 2, 8, 0);
imshow("img", tmp);
int width = abs(pre_pt.x - cur_pt.x);
int height = abs(pre_pt.y - cur_pt.y);
int pix_x = min(cur_pt.x, pre_pt.x);
int pix_y = min(cur_pt.y, pre_pt.y);
if (width == 0 || height == 0)//负样本
{
cout<<"选择作为负样本"<<endl;
destroyWindow("img");
string str ="../train/neg/" + to_string(cnt_neg)+".jpg";
string str_write =to_string(cnt_neg)+".jpg" + '\n';
outfile_neg.open("../train/neg/neg.txt", ios::app);
outfile_neg<<str_write;
imwrite(str, img);
cnt_neg++;
outfile_neg.close();
return;
}
//选择作为正样本
while(1)
{
if(waitKey(0) == 'y'