在OpenCV上使用SVM训练图像

Ana*_*mov 4 opencv classification image-processing svm

我正在尝试对图像进行分类(下一步我将基于功能进行分类,但现在只想尝试我是否做得对)

这是我的代码.

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/ml/ml.hpp>

using namespace cv;
using namespace std;



int main(){


    Mat image[2];
    image[0]= imread("image.jpg",0);

    image[1]= imread("wrongimage.jpg",0);

    Mat rotated = imread("image.jpg",0);


    image[0] = image[0].reshape(0, 1); //SINGLE LINE
    image[1] = image[1].reshape(0, 1); //SINGLE LINE


    //  image[0].convertTo(image[0], CV_32FC1); //CONVERT TO 32FC1
    //  image[1].convertTo(image[1], CV_32FC1); //CONVERT TO 32FC1


    Mat new_image(2,1,CV_32FC1,image); //CONVERT TO 32FC1



    float labels[2] = {1.0, -1.0};
    Mat labelsmat(2,1,CV_32FC1,labels); //correct labels 1

    labelsmat.convertTo(labelsmat, CV_32FC1);



    CvSVMParams params;
    params.svm_type = CvSVM::C_SVC;
    params.kernel_type = CvSVM::LINEAR;
    params.gamma = 3;
    params.degree = 3;
    CvSVM svm;
    svm.train(new_image, labelsmat, Mat(),Mat(),params);

    //    svm.train(training_mat2, labelsmat, Mat(),Mat(),params);

    // svm.train(training_mat2, labelsmat, Mat(), Mat(), params);
    svm.save("svm.xml"); // saving


    svm.load("svm.xml"); // loading


    rotated = rotated.reshape(0,1);
    rotated.convertTo(rotated, CV_32FC1);


     svm.predict(rotated);
}
Run Code Online (Sandbox Code Playgroud)

由于使用opencv svm训练图像缺乏记录,我试图通过使用OpenCV和带有图像的SVMhttp://docs.opencv.org/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html来阅读.

不知怎的,我设法训练我的图像,但我强调我这列火车xml文件是不正确的,因为我没有指出哪个图像是正确的(1)或假(-1)

而且当我试图用图像预测我已经训练到svm时给了我错误

OpenCV错误:输入参数的大小不匹配(样本大小与训练时使用的大小不同)在cvPreparePredictData,文件/tmp/opencv-DXLLi8/opencv-2.4.9/modules/ml/src/inner_functions.cpp ,第1114行libc ++ abi.dylib:以cv类型的未捕获异常终止::异常:/tmp/opencv-DXLLi8/opencv-2.4.9/modules/ml/src/inner_functions.cpp:1114:错误:( - 209)样本大小不同于函数cvPreparePredictData中用于训练的样本大小

这里也是由SVM生成的xml.

<?xml version="1.0"?>
<opencv_storage>
<my_svm type_id="opencv-ml-svm">
  <svm_type>C_SVC</svm_type>
  <kernel><type>LINEAR</type></kernel>
  <C>1.</C>
  <term_criteria><epsilon>1.1920928955078125e-07</epsilon>
    <iterations>1000</iterations></term_criteria>
  <var_all>1</var_all>
  <var_count>1</var_count>
  <class_count>2</class_count>
  <class_labels type_id="opencv-matrix">
    <rows>1</rows>
    <cols>2</cols>
    <dt>i</dt>
    <data>
      -1 1</data></class_labels>
  <sv_total>1</sv_total>
  <support_vectors>
    <_>
      -1.56709105e-02</_></support_vectors>
  <decision_functions>
    <_>
      <sv_count>1</sv_count>
      <rho>-1.</rho>
      <alpha>
        1.</alpha>
      <index>
        0</index></_></decision_functions></my_svm>
</opencv_storage>
Run Code Online (Sandbox Code Playgroud)

UPDATE

我已经使用guneykayim的建议更改了我的代码,但现在我收到了EXC_BAD_ACCESS(code = 1 address = ...)错误.我的更新代码如下.

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/ml/ml.hpp>

using namespace cv;
using namespace std;



int main(){


    Mat image[2];
    image[0]= imread("image.jpg",0);

    image[1]= imread("wrongimage.jpg",0);

    Mat rotated = imread("image.jpg",0);


   image[0] = image[0].reshape(0, 1); //SINGLE LINE
   image[1] = image[1].reshape(0, 1); //SINGLE LINE

 //   int size = sizeof(image)/sizeof(Mat);
    //  image[0].convertTo(image[0], CV_32FC1); //CONVERT TO 32FC1
    //  image[1].convertTo(image[1], CV_32FC1); //CONVERT TO 32FC1

    Mat new_image(2,341318,CV_32FC1,image); //CONVERT TO 32FC1

    float labels[2] = {1.0, -1.0};
    Mat labelsmat(2,1,CV_32FC1,labels); //correct labels 1

    labelsmat.convertTo(labelsmat, CV_32FC1);


    cout<<image[0].size()<<endl;
    cout<<new_image.size()<<endl;



    CvSVMParams params;
    params.svm_type = CvSVM::C_SVC;
    params.kernel_type = CvSVM::LINEAR;
    params.gamma = 3;
    params.degree = 3;
    CvSVM svm;
    svm.train_auto(new_image, labelsmat,Mat(),Mat(),params);

    //  svm.train_(new_image, labelsmat, Mat(),Mat(),params);
    //    svm.train(training_mat2, labelsmat, Mat(),Mat(),params);

    // svm.train(training_mat2, labelsmat, Mat(), Mat(), params);
    svm.save("svm.xml"); // saving


    svm.load("svm.xml"); // loading


    rotated = rotated.reshape(0,1);
    rotated.convertTo(rotated, CV_32FC1);

    cout<<svm.predict(rotated)<<endl;

}
Run Code Online (Sandbox Code Playgroud)

我的图像大小是:[170569 x 1]和new_image大小是[341318 x 2]

gun*_*yim 8

有些事情你做错了或者你不知道你在做什么.

  1. 你说你没有指出哪个图像是正确的(1)还是假的(-1),但你做了以下几行: float labels[2] = {1.0, -1.0};
  2. 您正在创建错误的训练集.假设您的图像640x480大小合适.然后当你重塑它们时,它们将是307200大小的向量,这很好.因此,您调用的训练集new_image应该调整2x307200大小,每行应代表一个图像,而是创建2x1大小的训练集.这就是为什么当你试图预测你会得到一个错误Sizes of input arguments do not match.您训练了具有2x1大小训练集的SVM 并尝试使用1x307200向量进行预测.

除此之外,您不应该使用幻数设置SVM参数,您需要使用交叉验证来优化它们.在这个玩具示例当然你不能做参数优化,我想说的是你应该知道设置SVM参数是一个非常关键的任务.

我已经回答了几个关于SVM的问题,你可以从我的个人资料中查看它们.

希望这可以帮助.

UPDATE

您可以new_image通过以下代码检查您的创作是否正确:

Mat image[2];
image[0]= imread("image.jpg",0);
image[1]= imread("wrongimage.jpg",0);

// dont reshape them for debugging purposes...
//image[0] = image[0].reshape(0, 1); //SINGLE LINE
//image[1] = image[1].reshape(0, 1); //SINGLE LINE

// I assume that images are 640x480, change the value accordig to the image sizes, or directly use values in the size parameter
Mat new_image(1280, 480, CV_32FC1, image); //CONVERT TO 32FC1

// visualize the image see if the previous line of code does its job correctly.
imshow("new_image", new_image);
Run Code Online (Sandbox Code Playgroud)

更新2

您需要cv::Matcv::Mat数组中创建单个对象.显然,以下行无法正常完成.

Mat new_image(2,341318,CV_32FC1,image); 
Run Code Online (Sandbox Code Playgroud)

找到一个正确的方法,目前我没有安装OpenCV环境,你可以基本上问一个关于它的另一个问题.

请记住,您的new_image变量应该调整[image_count * (image_width * image_height)]大小,每行应该表示1 * (image_width * image_height)大小合适的图像矢量.

  • @Rodrane你不是在读我写的:)请在我更新的答案中看到输出的可视化,看看是否正确生成了`new_image`.正确的大小并不意味着它是正确创建的. (2认同)