赞
踩
数据分为正样本和负样本:正样本是要识别的部分,负样本是不包含要识别的部分。
正样本要求尽量转成灰度图,统一大小尺寸,数据量在1000张图像以上;负样本之间的尺寸大小随意,数据量尽量是正样本的3倍。
以车辆检测为例,下图为正样本的示例:
下图为负样本的示例:
为正样本创建描述文件posdata.txt,负样本创建描述文件negdata.txt文件:
#include <io.h>
#include <vector>
#include "opencv2/opencv.hpp"
#include <fstream>
using namespace cv;
using namespace std;
void getFiles(string path, vector<string>& files, vector<string>& ownname)
{
intptr_t hFile = 0;
struct _finddata_t fileinfo;
string p;
if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
{
do
{
if ((fileinfo.attrib & _A_SUBDIR))
{
if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
getFiles(p.assign(path).append("\\").append(fileinfo.name), files, ownname);
}
else
{
files.push_back(p.assign(path).append("\\").append(fileinfo.name));
ownname.push_back(fileinfo.name);
}
} while (_findnext(hFile, &fileinfo) == 0);
_findclose(hFile);
}
}
void get_txt()
{
vector<string> files_pos, names_pos;
getFiles("E://vs_program//Haar_test//train_car//posdata", files_pos, names_pos); //正样本的路径
vector<string> files_neg, names_neg;
getFiles("E://vs_program//Haar_test//train_car//negdata", files_neg, names_neg); //负样本的路径
ofstream pxData;
pxData.open("..//train_car//posdata.txt", std::ios::out | std::ios::trunc); //在train_car文件夹下生成正样本的txt文件
for (int i = 0; i < files_pos.size(); i++)
{
pxData << files_pos[i] << " 1 0 0 32 24" << std::endl; //32*24是resize正样本的尺寸
}
pxData.close();
pxData.open("..//train_car//negdata.txt", std::ios::out | std::ios::trunc); //在train_car文件夹下生成负样本的txt文件
for (int i = 0; i < files_neg.size(); i++)
{
pxData << files_neg[i] << std::endl;
}
pxData.close();
}
int main()
{
get_txt();
return 0;
}
编译的主要步骤可见QT配置opencv并打包发布
通过上述的编译,在bin文件夹中便得到opencv_createsamples.exe,但还需要opencv_traincascade.exe,因此,在Search里面输入MOD,添加OPENCV_EXTRA_MODULES_PATH值,即在Value处填入opencv_contrib路径下modules文件夹的路径,如下图
注意:路径是反斜杠,否则会报错【CMake Error at cmake/OpenCVModule.cmake:288 (message): No modules has been found:】。
改好之后再次点击Configure,出现configure done之后点击Generate,最后应该是下图这样的:
至此,便得到opencv_traincascade.exe。
在cmd里cd到编译后的文件夹下,再将两个txt拷贝至此,运行如下语句:
opencv_createsamples.exe -info posdata.txt -vec detect_number.vec -bg negdata.txt -num 850 -w 32 -h 24
参数解释:
-info:posdata.txt的位置,可以直接使用绝对地址避免出错
-vec 生成vec文件的位置和名称
-bg negdata.txt的位置,可以直接使用绝对地址
-num 正样本的数量
-w -h 正样本的宽高
在程序所在的上一个文件夹中,新建一个文件夹xml_file。不能在当前文件夹下新建,否则会报错【terminate called after throwing an instance of ‘cv::Exception‘,已放弃 (核心已转储)】。
再运行如下语句:
opencv_traincascade.exe -data ../xml_file -vec detect_number.vec -bg negdata.txt -numPos 850 -numNeg 4666 -numStages 20 -featureType HAAR -w 32 -h 24
参数解释:
-data 存放训练好的xml文件的文件夹,这个一定要事先创建好
-vec 之前生成vec文件
-bg negdata.txt的位置
-numPos 正样本的数量
-numNeg 负样本的数量
-numStages 训练步数
-featureType 特征类型,有三种,HAAR最常用
-w -h 正样本的宽高
开始训练后如图:
训练完成后在xml_file文件夹里会生成一系列xml文件,最后能用的文件是cascade.xml
#include <io.h>
#include <vector>
#include "opencv2/opencv.hpp"
#include <fstream>
using namespace cv;
using namespace std;
void getFiles(string path, vector<string>& files, vector<string>& ownname)
{
intptr_t hFile = 0;
struct _finddata_t fileinfo;
string p;
if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
{
do
{
if ((fileinfo.attrib & _A_SUBDIR))
{
if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
getFiles(p.assign(path).append("\\").append(fileinfo.name), files, ownname);
}
else
{
files.push_back(p.assign(path).append("\\").append(fileinfo.name));
ownname.push_back(fileinfo.name);
}
} while (_findnext(hFile, &fileinfo) == 0);
_findclose(hFile);
}
}
int main()
{
vector<string> files, names;
getFiles("..//train_car//test", files, names);
CascadeClassifier face_cascade;
String file1 = "..//carTrain3//traincascade//cascade05022.xml";
if (!face_cascade.load(file1))
{
printf("can not load the file... xml\n");
return -1;
}
for (int j = 0; j < files.size(); j++)
{
Mat image = imread(files[j]);
resize(image, image, Size(400, 200));
vector<Rect> objects;
Mat gray_image;
cvtColor(image, gray_image, COLOR_BGR2GRAY);
face_cascade.detectMultiScale(gray_image, objects, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(1, 1));
vector<Rect> pick = NMS(objects, 0.1);
//框选出脸部区域
for (int i = 0; i < pick.size(); i++)
{
RNG rng(i);
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), 20);
rectangle(image, pick[static_cast<int>(i)], color, 2, 8, 0);
}
imshow("cars", image);
imwrite("..//result//" + names[j], image);
waitKey(1);
}
return 0;
}
效果如下:
如果训练无误,但测试时没有结果。说明数据集不够,训练样本太少。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。