【问题标题】:The label type must be float if you want to read the xml files of random forest(opencv3.0)如果要读取随机森林的xml文件,标签类型必须是float(opencv3.0)
【发布时间】:2015-10-24 07:38:44
【问题描述】:
#include <opencv2/core.hpp>
#include <opencv2/ml.hpp>

#include <iostream>
#include <vector>

int main()
{
    size_t const FeatureSize = 24;
    {
        auto rtrees = cv::ml::RTrees::create();
        rtrees->setMaxDepth(10);
        rtrees->setMinSampleCount(2);
        rtrees->setRegressionAccuracy(0);
        rtrees->setUseSurrogates(false);
        rtrees->setMaxCategories(16);
        rtrees->setPriors(cv::Mat());
        rtrees->setCalculateVarImportance(false);
        rtrees->setActiveVarCount(0);
        rtrees->setTermCriteria({ cv::TermCriteria::MAX_ITER, 100, 0 });

        std::vector<float> labels; //#1
        cv::Mat_<float> features;        
        for(size_t i = 0; i != 500; ++i){
            std::vector<float> data;
            for(size_t j = 0; j != FeatureSize; ++j){
                data.emplace_back(0); //#2
            }
            labels.emplace_back(i % 2);
            features.push_back(cv::Mat(data, true));
        }                

        rtrees->train(features.reshape(1, labels.size()),
                      cv::ml::ROW_SAMPLE, labels);
        rtrees->write(cv::FileStorage("smoke_classifier.xml",
                                  cv::FileStorage::WRITE));
    }

    {
        auto rtrees2 = cv::ml::RTrees::create();

        cv::FileStorage read("smoke_classifier.xml",
                             cv::FileStorage::READ);
        rtrees2->read(read.root());

        int a = rtrees2->getMinSampleCount();
        std::cout<<"a == "<<a<<"\n";
        cv::Mat1f feat2(1, FeatureSize, 0.f);
        std::cout<<"predict == "<<rtrees2->predict(feat2)<<"\n";
    }  
} 

如果将#1从float改为int并读取xml然后调用predict,程序会崩溃,但是如果我不从xml读取信息,即使#1类型是,函数predict也可以工作诠释

但是如果我将标签从int更改为float,当我调用train训练机器时,rtree会弹出另一个错误消息(代码sn-p(#2)的虚拟数据“0”不会导致程序会崩溃,但真实数据会)。

另一个问题是,将标签从 int 更改为 float 会使其从分类问题变为回归问题,但我真正需要的是分类而不是回归(虽然很容易通过回归来模拟分类,因为只有两个标签)

将标签更改为浮动并调用 train 训练机器时的错误消息

"....\opencv-3.0.0\sources\modules\ml\src\tree.cpp:1190: 错误:(-215) (int)_sleft.size()

【问题讨论】:

    标签: c++ opencv


    【解决方案1】:

    相关代码在tree.cpp中。

    当使用int标签时,这行会导致崩溃:

    float DTreesImpl::predictTrees( const Range& range, const Mat& sample, int flags ) const
    {
        ...
        if( predictType == PREDICT_MAX_VOTE ) {
        ...
            sum = (flags & RAW_OUTPUT) ? (float)best_idx : classLabels[best_idx]; // Line 1487
        ...
        }
    }
    

    因为classLabels 是空的(即使它存在于 xml 文件中)。

    使用float 标签时,不会执行此行,因为predictType 将是PREDICT_SUM 而不是PREDICT_MAX_VOTE。 (相关代码在同一个函数中)。

    造成这种情况的原因是文件没有正确加载(这可能是一个错误)。其实读取文件的时候就有这个检查

    void DTreesImpl::readParams( const FileNode& fn )
    {
        ...
        int format = 0; // line 1720
        fn["format"] >> format;
        bool isLegacy = format < 3;
        ...
        if (isLegacy) { ... }
        else 
        {
            ...
            fn["class_labels"] >> classLabels;            
        }
    }
    

    但是在写入文件时,“格式”字段不存在。因此,您实际上是在以错误的格式读取文件,因为您输入了isLegacy 部分。


    解决方法是将文件另存为:

    ...
    std::vector<int> labels;
    ...
    rtrees->write(cv::FileStorage("smoke_classifier.xml", cv::FileStorage::WRITE));
    // Add this
    {
        cv::FileStorage fs("smoke_classifier.xml", cv::FileStorage::APPEND);
        fs << "format" << 3; // So "isLegacy" return false;
    }
    
    cv::FileStorage read("smoke_classifier.xml",
                         cv::FileStorage::READ);
    auto rtrees2 = cv::ml::RTrees::create();
    rtrees2->read(read.root());
    

    这样做,文件将被正确加载,程序不会崩溃。

    由于我无法在 calcDir 中重现您的其他问题,请告诉我这是否可行。

    【讨论】:

    • 你太棒了,这对我有用,非常感谢。我想这可能是一个错误,没有理由要求用户附加格式标签以避免崩溃。
    猜你喜欢
    • 2015-10-23
    • 2020-01-31
    • 2016-08-05
    • 2015-09-22
    • 2020-08-28
    • 2016-05-25
    • 2018-06-05
    • 2017-03-15
    • 2018-07-10
    相关资源
    最近更新 更多