如果要读取随机林的xml文件,则标签类型必须为float(opencv3.0)

时间:2015-08-01 21:11:26

标签: c++ opencv

#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类型是函数预测也可以工作INT

但是如果我将标签从int更改为float,当我调用train来训练机器时,rtree会弹出另一条错误消息(虚拟数据&#34; 0&#34;代码片段(#2)不会导致程序崩溃,但真正的数据会)。

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

将标签更改为浮动并呼叫列车以训练机器时的错误消息

&#34; .... \ opencv-3.0.0 \ sources \ modules \ ml \ src \ tree.cpp:1190:错误:(-215)(int)_sleft.size()&lt; n&amp;&amp; (int)_sright.size()&lt; n在函数cv :: ml :: DTreesImpl :: calcDir&#34;

1 个答案:

答案 0 :(得分: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;            
    }
}

但在编写文件时,字段&#34;格式&#34;不在这里。因此,您实际上是以错误的格式读取文件,因为您输入了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中重现您的其他问题,请告诉我这是否有效。