【问题标题】:svm predict function always return a large numbersvm predict 函数总是返回一个大数字
【发布时间】:2016-02-28 13:24:59
【问题描述】:

我试图实现一个简单的样本,目的是传输和检测一个数字。来源如下:

第 1 步:用于转换的初始数据: 我使用了一组图像编号来训练数据,

    Mat vectorMatToMat(vector<Mat> list) {
        if (list.empty()) {
            return Mat();
        }
        int row = list.size();
        int col = list.at(0).rows * list.at(0).cols;
        Mat data(row, col, CV_32FC1);
        int i = 0;
        for (i = 0; i < row; i++) {
            Mat rowMat = list.at(i).reshape(1, 1);
            rowMat.copyTo(data.row(i));
        }
        return data;
    }
    Mat vectorIntToMat(vector<int> list) {
        int row = list.size();
        Mat data(row, 1, CV_32SC1, &list[0]);
        return data;
    }

    Mat dataMat = vectorMatToMat(listImageForTraining);
    Mat dataLabel = vectorIntToMat(listLabel);

第 2 步:初始化 SVM:

Ptr<TrainData> trainData = TrainData::create(dataMat, ROW_SAMPLE, dataLabel);

Ptr<SVM> model = SVM::create();
model->setType(SVM::C_SVC);
model->setKernel(SVM::LINEAR);
model->setC(7);
model->setNu(SVM::NU_SVC);
model->setP(0);
model->setDegree(0);
model->setGamma(20);
model->setCoef0(0);
TermCriteria term(CV_TERMCRIT_ITER +CV_TERMCRIT_EPS, 1000, 1e-6);
model->setTermCriteria(term);
model->train(trainData);

第 3 步:尝试使用 SVM 进行预测:

    int i = 0;
    for (i = 0; i < 15; i++) {
        Mat check = dataMat.row(i);
        ostringstream oss;
        oss << i;
        imshow(oss.str(), check.reshape(1, 128));

        check = check.reshape(1, 1);
        int lable = svm.predict(check);

        cout << "Result: " << lable << endl;
    }

第 4 步:结果:

Result: -1237234688
Result: 159407376
Result: 159407376
Result: 167908848
Result: 1065353216
Result: 1065353216
Result: 1065353216
Result: 1065353216
Result: 1065353216
Result: 1065353216
Result: 1065353216
Result: 1065353216
Result: 1065353216
Result: 1065353216
Result: 1065353216

正如我们所见,我的结果是非常大的数字,尽管我的标签是 0 到 10 之间的数字。 我不明白为什么,我认为我在初始化 SVM 模型时出错了。

但我不知道如何解决这个问题, 如果有任何想法,请帮助我。

感谢和最好的问候,

小偷

【问题讨论】:

    标签: opencv svm predict


    【解决方案1】:

    看起来您在以下方法的第一步中有错误:

    Mat vectorIntToMat(vector<int> list) {
        int row = list.size();
        Mat data(row, 1, CV_32SC1, &list[0]);
        return data;
    }
    

    您按值传递标签向量。它实际上制作了标签向量的副本,该向量将在返回后被破坏。 比您使用cv::Mat 的以下构造函数:

    Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
    

    根据OpenCV documentation,此构造函数不分配矩阵数据。它只使用您提供的内存。但是在您的情况下,此内存将在方法返回后被释放,并且标签的矩阵对象将不正确。

    显然,如果您在训练中使用不正确的标签矩阵,您会得到不正确的预测结果。

    我认为,最简单的问题解决方法如下:

    Mat vectorIntToMat(vector<int> list) {
        int row = list.size();
        Mat data = Mat(row, 1, CV_32SC1, &list[0]).clone();
        return data;
    }
    

    希望它会有所帮助。

    【讨论】:

    • 感谢您的建议。我尝试创建一个数组并将其传递给构造函数。但结果与我上面的结果相同。 :(
    【解决方案2】:

    我尝试如下修改,但效果仍然不好。

    Mat vectorIntToMat(vector<int> list) {
        int row = list.size();
        Mat data = Mat(row, 1, CV_32SC1, &list[0]).clone();
        return data;
    }
    

    之后我尝试修改如下,我的问题解决了:

    Mat vectorIntToMat(vector<int> list) {
        return Mat(list, true);
    }
    

    但我仍然不明白根本原因。 谁能给我解释一下?

    【讨论】:

    • 能否请您检查带有.clone() 的示例不起作用?我制作了一个简单的代码shippet,两种变体的工作方式相同。你可能是在其他地方更改了代码吗?
    猜你喜欢
    • 2018-06-02
    • 2022-01-05
    • 2015-04-20
    • 2013-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多