opencv KNN 模型不能保存的问题

由Opencv 机器学习部分在线文档

 http://docs.opencv.org/modules/ml/doc/ml.html

得知,这些机器学习方法K-Nearest Neighbors等都继承于基类CvStatModel,此基类中有save,load等方法,http://wiki.opencv.org.cn/index.php/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E4%B8%AD%E6%96%87%E5%8F%82%E8%80%83%E6%89%8B%E5%86%8C#CvStatModel 中文解释说save,load方法会调用write和read方法。

在早期opencv中,基类的load和save都是纯虚函数,即子类要加以实现。

class CvStatModel
{
public:
    /* CvStatModel(); */
    /* CvStatModel( const CvMat* train_data ... ); */

    virtual ~CvStatModel();

    virtual void clear()=0;

    /* virtual bool train( const CvMat* train_data, [int tflag,] ..., const CvMat* responses, ...,
    [const CvMat* var_idx,] ..., [const CvMat* sample_idx,] ...
    [const CvMat* var_type,] ..., [const CvMat* missing_mask,] <misc_training_alg_params> ... )=0;
     */

    /* virtual float predict( const CvMat* sample ... ) const=0; */

    virtual void save( const char* filename, const char* name=0 )=0;
    virtual void load( const char* filename, const char* name=0 )=0;

    virtual void write( CvFileStorage* storage, const char* name )=0;
    virtual void read( CvFileStorage* storage, CvFileNode* node )=0;
};

而后来opencv对此做了修改,修改成为了虚函数。如下:

class CV_EXPORTS_W CvStatModel
{
public:
    CvStatModel();
    virtual ~CvStatModel();

    virtual void clear();

    CV_WRAP virtual void save( const char* filename, const char* name=0 ) const;
    CV_WRAP virtual void load( const char* filename, const char* name=0 );

    virtual void write( CvFileStorage* storage, const char* name ) const;
    virtual void read( CvFileStorage* storage, CvFileNode* node );

protected:
    const char* default_model_name;
};

这个虚函数声明说明,任何继承自CvStatModel的类都可以调用save,load等。

但是在使用KNN时调用save会出错,我们查看ml.hpp 文件发现opencv中K-Nearest Neighbors没有实现load,save,write,read这些函数。如下:

// k Nearest Neighbors
class CV_EXPORTS_W CvKNearest : public CvStatModel
{
public:

    CV_WRAP CvKNearest();
    virtual ~CvKNearest();

    CvKNearest( const CvMat* trainData, const CvMat* responses,
                const CvMat* sampleIdx=0, bool isRegression=false, int max_k=32 );

    virtual bool train( const CvMat* trainData, const CvMat* responses,
                        const CvMat* sampleIdx=0, bool is_regression=false,
                        int maxK=32, bool updateBase=false );

    virtual float find_nearest( const CvMat* samples, int k, CV_OUT CvMat* results=0,
        const float** neighbors=0, CV_OUT CvMat* neighborResponses=0, CV_OUT CvMat* dist=0 ) const;

    CV_WRAP CvKNearest( const cv::Mat& trainData, const cv::Mat& responses,
               const cv::Mat& sampleIdx=cv::Mat(), bool isRegression=false, int max_k=32 );

    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 );

    virtual float find_nearest( const cv::Mat& samples, int k, cv::Mat* results=0,
                                const float** neighbors=0, cv::Mat* neighborResponses=0,
                                cv::Mat* dist=0 ) const;
    CV_WRAP virtual float find_nearest( const cv::Mat& samples, int k, CV_OUT cv::Mat& results,
                                        CV_OUT cv::Mat& neighborResponses, CV_OUT cv::Mat& dists) const;

    virtual void clear();
    int get_max_k() const;
    int get_var_count() const;
    int get_sample_count() const;
    bool is_regression() const;

    virtual float write_results( int k, int k1, int start, int end,
        const float* neighbor_responses, const float* dist, CvMat* _results,
        CvMat* _neighbor_responses, CvMat* _dist, Cv32suf* sort_buf ) const;

    virtual void find_neighbors_direct( const CvMat* _samples, int k, int start, int end,
        float* neighbor_responses, const float** neighbors, float* dist ) const;

protected:

    int max_k, var_count;
    int total;
    bool regression;
    CvVectors* samples;
};

此时如果用KNN.save时会调用基类的虚函数,而我们无法知道基类的save是如何实现的。

而在可以保存的svm等方法中发现了,read和write的声明

// SVM model
class CV_EXPORTS_W CvSVM : public CvStatModel
{
public:
    // SVM type
    virtual void write( CvFileStorage* storage, const char* name ) const;
    virtual void read( CvFileStorage* storage, CvFileNode* node );

我们这里省略了大部分,可猜测不同的方法保存是有差别的。

我们没有在KNN代码中找到任何实现write和read的函数,通过运行出错,我们理解为opencv并没有实现对knn的write,这是源于knn的特点的,knn所谓的train也是只是保存样本数据,没有生成分类的模型,这个train函数也不是严格意义的训练。

如果我们想保存这些样本数据,可以通过保存样本特征在文件中,一次读入,可以参考http://www.aishack.in/2010/10/k-nearest-neighbors-in-opencv/

 

你可能感兴趣的:(opencv,learning,machine,CvKNearest)