准备知识
在文件”opencv\sources\modules\ml\src\precomp.hpp“中
有cvPrepareTrainData的函数原型。
int
cvPrepareTrainData( const char* /*funcname*/,
const CvMat* train_data, int tflag,
const CvMat* responses, int response_type,
const CvMat* var_idx,
const CvMat* sample_idx,
bool always_copy_data,
const float*** out_train_samples,
int* _sample_count,
int* _var_count,
int* _var_all,
CvMat** out_responses,
CvMat** out_response_map,
CvMat** out_var_idx,
CvMat** out_sample_idx=0 )
从函数原型的参数可以看出主要为:
const char* /funcname/: 函数的名称
const CvMat* train_data, int tflag,: 训练集、训练集样本的布局
const CvMat* responses, int response_type,:训练集标签、对应数据类型
const CvMat* var_idx,: 用了哪些特征
const CvMat* sample_idx,: 用了哪些样本
bool always_copy_data,: 是否复制数据集
const float*** out_train_samples,: 输出处理过的的训练集
int* _sample_count, : 样本的总数
int* _var_count,: 特征的总数
int* _var_all,
CvMat** out_responses,: 输出训练集标签
CvMat** out_response_map,
CvMat** out_var_idx, : 输出用了哪些特征
CvMat** out_sample_idx=0 : 默认输出为使用了所有的样本
在文件”opencv\sources\modules\ml\src\inner_functions.cpp“中有cvPrepareTrainData的函数实现:
int
cvPrepareTrainData( const char* /*funcname*/,
const CvMat* train_data, int tflag,
const CvMat* responses, int response_type,
const CvMat* var_idx,
const CvMat* sample_idx,
bool always_copy_data,
const float*** out_train_samples,
int* _sample_count,
int* _var_count,
int* _var_all,
CvMat** out_responses,
CvMat** out_response_map,
CvMat** out_var_idx,
CvMat** out_sample_idx )
{
int ok = 0;//用于标记该函数是否成功执行
CvMat* _var_idx = 0;//默认使用所有的特征
CvMat* _sample_idx = 0;//默认使用所有的样本
CvMat* _responses = 0;
int sample_all = 0, sample_count = 0, var_all = 0, var_count = 0;
CV_FUNCNAME( "cvPrepareTrainData" );
// step 0. clear all the output pointers to ensure we do not try
// to call free() with uninitialized pointers
//第0步,先释放所有输出的指针以确保不会有未初始化的指针。
if( out_responses )
*out_responses = 0;
if( out_response_map )
*out_response_map = 0;
if( out_var_idx )
*out_var_idx = 0;
if( out_sample_idx )
*out_sample_idx = 0;
if( out_train_samples )
*out_train_samples = 0;
if( _sample_count )
*_sample_count = 0;
if( _var_count )
*_var_count = 0;
if( _var_all )
*_var_all = 0;
//重置完成
__BEGIN__;
if( !out_train_samples )
CV_ERROR( CV_StsBadArg, "output pointer to train samples is NULL" );
CV_CALL( cvCheckTrainData( train_data, tflag, 0, &var_all, &sample_all ));
if( sample_idx )
CV_CALL( _sample_idx = cvPreprocessIndexArray( sample_idx, sample_all ));
if( var_idx )
CV_CALL( _var_idx = cvPreprocessIndexArray( var_idx, var_all ));
if( responses )
{
if( !out_responses )
CV_ERROR( CV_StsNullPtr, "output response pointer is NULL" );
if( response_type == CV_VAR_NUMERICAL )
{
CV_CALL( _responses = cvPreprocessOrderedResponses( responses,
_sample_idx, sample_all ));
}
else
{
CV_CALL( _responses = cvPreprocessCategoricalResponses( responses,
_sample_idx, sample_all, out_response_map, 0 ));
}
}
CV_CALL( *out_train_samples =
cvGetTrainSamples( train_data, tflag, _var_idx, _sample_idx,
&var_count, &sample_count, always_copy_data ));
ok = 1;
__END__;
//如果上面的操作都结束了,那么检测对应的输出需要的指针,是否已经初始化,然后接着对各自的输出指针指向的对象进行置0初始化
if( ok )
{
if( out_responses )
*out_responses = _responses, _responses = 0;
if( out_var_idx )
*out_var_idx = _var_idx, _var_idx = 0;
if( out_sample_idx )
*out_sample_idx = _sample_idx, _sample_idx = 0;
if( _sample_count )
*_sample_count = sample_count;
if( _var_count )
*_var_count = var_count;
if( _var_all )
*_var_all = var_all;
}
else
{
if( out_response_map )
cvReleaseMat( out_response_map );
cvFree( out_train_samples );
}
if( _responses != responses )
cvReleaseMat( &_responses );
cvReleaseMat( &_var_idx );
cvReleaseMat( &_sample_idx );
return ok;//返回该函数是否成功执行
}
首先在文件“opencv\sources\modules\ml\include\opencv2\ml\ml.hpp”中有:
#define CV_TYPE_NAME_ML_KNN "opencv-ml-knn"
struct CvVectors
{
int type;
int dims, count;
CvVectors* next;
union
{
uchar** ptr;
float** fl;
double** db;
} data;
};
/*********K-Nearest Neighbour Classifier **********/
class CV_EXPORTS_W CvKNearest : public CvStatModel
{
public:
CV_WRAP CvKNearest();//默认构造函数
virtual ~CvKNearest();//虚析构函数
//2个重载的构造函数,参数中一个是CvMat,一个是Mat
//trainData:训练集
//responses:训练集的目标值
//sampleIdx:用来指定使用哪些训练样本,0表示使用所有的训练样本
//isRegression:trueb表示knn作为回归,否则为分类器
//max_k:K的上限
CvKNearest( const CvMat* trainData, const CvMat* responses,
const CvMat* sampleIdx=0, bool isRegression=false, int max_k=32 );
CV_WRAP CvKNearest( const cv::Mat& trainData, const cv::Mat& responses,
const cv::Mat& sampleIdx=cv::Mat(), bool isRegression=false, int max_k=32 );
//训练模型,两个重载函数,一个使用的是CvMat;一个使用的是Mat;Mat的会调用CvMat的train实现训练功能。
//updateBase:用于指定该模型是从头开始训练?(update_base=false),还是使用新的训练数据来进行更新
//(update_base=true).在后者中,参数maxK不能大于原始的值
virtual bool train( const CvMat* trainData, const CvMat* responses,
const CvMat* sampleIdx=0, bool is_regression=false,
int maxK=32, bool updateBase=false );
CV_WRAP virtual bool train( const cv::Mat& trainData, const cv::Mat& responses,
const cv::Mat& sampleIdx=cv::Mat(), bool isRegression=false,
int maxK=32, bool updateBase=false