如何使用OpenCV针对一组图像训练支持向量机(SVM)?

6

我有一个包含正面和负面图像的文件夹,格式为JPG,我想要根据这些图像训练出一个基于SVM的模型。我已经尝试了以下操作,但是遇到了错误:

Mat classes = new Mat();
Mat trainingData = new Mat();

Mat trainingImages = new Mat();
Mat trainingLabels = new Mat();

CvSVM clasificador;

for (File file : new File(path + "positives/").listFiles()) {
        Mat img = Highgui.imread(file.getAbsolutePath());
        img.reshape(1, 1);

        trainingImages.push_back(img);
        trainingLabels.push_back(Mat.ones(new Size(1, 1), CvType.CV_32FC1));
    }

    for (File file : new File(path + "negatives/").listFiles()) {
        Mat img = Highgui.imread(file.getAbsolutePath());
        img.reshape(1, 1);

        trainingImages.push_back(img);
        trainingLabels.push_back(Mat.zeros(new Size(1, 1), CvType.CV_32FC1));
    }

    trainingImages.copyTo(trainingData);
    trainingData.convertTo(trainingData, CvType.CV_32FC1);
    trainingLabels.copyTo(classes);

    CvSVMParams params = new CvSVMParams();
    params.set_kernel_type(CvSVM.LINEAR);

    clasificador = new CvSVM(trainingData, classes, new Mat(), new Mat(), params);

当我尝试运行时,会出现以下错误信息:
OpenCV Error: Bad argument (train data must be floating-point matrix) in cvCheckTrainData, file ..\..\..\src\opencv\modules\ml\src\inner_functions.cpp, line 857
Exception in thread "main" CvException [org.opencv.core.CvException: ..\..\..\src\opencv\modules\ml\src\inner_functions.cpp:857: error: (-5) train data must be floating-point matrix in function cvCheckTrainData
]
    at org.opencv.ml.CvSVM.CvSVM_1(Native Method)
    at org.opencv.ml.CvSVM.<init>(CvSVM.java:80)

我无法训练支持向量机(SVM),有什么建议吗?谢谢。


我正在尝试基于我已经获得的分割结果对车牌进行分类,我的代码是基于这个例子的:https://github.com/MasteringOpenCV/code/blob/master/Chapter5_NumberPlateRecognition/trainSVM.cpp - Joaquín L. Robles
你尝试使用CV_64F了吗?并且为了绝对确定,你是否检查了trainingData在传递到CvSVM之前的类型? - morynicz
感谢 @morynicz,'CvType.typeToString(trainingData.type())' 将返回 "CV_32FC3"。我也尝试将其转换为 CV_64F,但出现了相同的错误。 - Joaquín L. Robles
2个回答

11

假设您知道如何通过重新调整图像并使用它来训练SVM,那么最有可能的原因是您的

Mat img = Highgui.imread(file.getAbsolutePath());

未能真正读取图像,生成一个img矩阵,其中data属性为空,这最终将触发OpenCV代码中以下内容:

// check parameter types and sizes
if( !CV_IS_MAT(train_data) || CV_MAT_TYPE(train_data->type) != CV_32FC1 )
    CV_ERROR( CV_StsBadArg, "train data must be floating-point matrix" );

基本上,train_data 未能满足第一个条件(成为有效矩阵),而不是未能满足第二个条件(成为类型为 CV_32FC1 的矩阵)。

此外,即使 *this 对象上的 reshape 可以正常工作,它也像过滤器一样,其效果并不是永久的。如果它在单个语句中使用,而没有立即被使用或分配给另一个变量,那么它将是无用的。请更改您代码中的以下行:

img.reshape(1, 1);
trainingImages.push_back(img);

至:

trainingImages.push_back(img.reshape(1, 1));

0
正如错误所述,您需要更改矩阵的类型,从整数类型(可能是CV_8U)到浮点类型之一(CV_32F或CV_64F)。要做到这一点,您可以使用{{link1:cv :: Mat :: convertTo()}}。 这里有关矩阵深度和类型的一些信息。

实际上我执行了:'trainingData.convertTo(trainingData, CvType.CV_32FC1);' 然后我的 'classes' 填充了 [1] CV_32FC1 矩阵。 - Joaquín L. Robles
抱歉,疏忽了。 - morynicz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接