美文网首页OpenCV Numpy skimage
【转载】OpenCV3.0或OpenCV3.1的SVM操作

【转载】OpenCV3.0或OpenCV3.1的SVM操作

作者: dopami | 来源:发表于2019-02-20 18:13 被阅读0次

    https://blog.csdn.net/wfh2015/article/details/51163890


    OpenCV3.0或OpenCV3.1的SVM操作

    #include "opencv2/opencv.hpp"

    #include "opencv2/imgproc.hpp"

    #include "opencv2/highgui.hpp"

    #include "opencv2/ml.hpp"

    //using namespace cv;

    //using namespace cv::ml;

    int main(int argc, char** argv)

    {

        // visual representation

        int width = 512;

        int height = 512;

        cv::Mat image = cv::Mat::zeros(height, width, CV_8UC3);

        // training data

        int labels[4] = { 1, -1, -1, -1 };

        float trainingData[4][2] = { { 501, 10 }, { 255, 10 }, { 501, 255 }, { 10, 501 } };

        cv::Mat trainingDataMat(4, 2, CV_32FC1, trainingData);

        cv::Mat labelsMat(4, 1, CV_32SC1, labels);

        // initial SVM

        cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::create();

        svm->setType(cv::ml::SVM::Types::C_SVC);

        svm->setKernel(cv::ml::SVM::KernelTypes::LINEAR);

        svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER, 100, 1e-6));

        // train operation

        svm->train(trainingDataMat, cv::ml::SampleTypes::ROW_SAMPLE, labelsMat);

        // prediction

        cv::Vec3b green(0, 255, 0);

        cv::Vec3b blue(255, 0, 0);

        for (int i = 0; i < image.rows; i++)

        {

            for (int j = 0; j < image.cols; j++)

            {

                cv::Mat sampleMat = (cv::Mat_<float>(1, 2) << j, i);

                float respose = svm->predict(sampleMat);

                if (respose == 1)

                    image.at<cv::Vec3b>(i, j) = green;

                else if (respose == -1)

                    image.at<cv::Vec3b>(i, j) = blue;

            }

        }

        int thickness = -1;

        int lineType = cv::LineTypes::LINE_8;

        cv::circle(image, cv::Point(501, 10), 5, cv::Scalar(0, 0, 0), thickness, lineType);

        cv::circle(image, cv::Point(255, 10), 5, cv::Scalar(255, 255, 255), thickness, lineType);

        cv::circle(image, cv::Point(501, 255), 5, cv::Scalar(255, 255, 255), thickness, lineType);

        cv::circle(image, cv::Point(10, 501), 5, cv::Scalar(255, 255, 255), thickness, lineType);

        thickness = 2;

        lineType = cv::LineTypes::LINE_8;

        cv::Mat sv = svm->getSupportVectors();

        for (int i = 0; i < sv.rows; i++)

        {

            const float* v = sv.ptr<float>(i);

            cv::circle(image, cv::Point((int)v[0], (int)v[1]), 6, cv::Scalar(128, 128, 128), thickness, lineType);

        }

        cv::imshow("SVM Simple Example", image);

        cv::waitKey(0);

        return 0;

    }

    运行的效果如下:

    为了保证代码可读性,代码没有用using namespace cv或using namespace cv::ml;之类的代码,全部都写完整的名称,命名空间+类名。比如设置SVM的核类型为线性,写成svm->setKernel(cv::ml::SVM::KernelTypes::LINEAR);。当然,这个只是一处地方,其他的请自己阅读。

    代码的注意事项

    虽然,大家的目标很明确:导入训练数据+label –> Mat, 训练,预测,显示这些目标。但是仍然避免不了代码错误。下面就是我遇到的代码的问题。

    标签以及变成Mat的数据类型

    其实,在本代码中出现了一种情况就是数据类型,下面均以标签为例:

    这个是OpenCV3.0、OpenCV3.1正确的代码:

    int labels[4] = { 1, -1, -1, -1 };

    cv::Mat labelsMat(4, 1, CV_32SC1, labels);

    下面是OpenCV 2.X 正确代码

    float labels[4] = {1.0, -1.0, -1.0, -1.0};

    Mat labelsMat(3, 1, CV_32FC1, labels);

    如果将OpenCV 2.X的代码换到OpenCV 3.1、OpenCV3.0代码会有什么样子的结果呢?

    这个很熟悉吧所以,如果傻乎乎的换,这个是行不通的。

    下面对于label和labelMat按照不同的情况进行分析。

    首先,这个labelMat和trainingMat到底能取哪几种类型?

    下面,请看OpenCV3.1 源码中的一个部分:

    void setData(InputArray _samples, int _layout, InputArray _responses,

                    InputArray _varIdx, InputArray _sampleIdx, InputArray _sampleWeights,

                    InputArray _varType, InputArray _missing)

        {

            samples = _samples.getMat();

            responses = _responses.getMat();

            CV_Assert( samples.type() == CV_32F || samples.type() == CV_32S );

            if( !responses.empty() )

            {

                CV_Assert( responses.type() == CV_32F || responses.type() == CV_32S );

            }

        }

    为了方便起见,将这个函数的代码的其他部分删除了。首先解释一下:samples就是训练的数据。response就是标签。通过上面,我们知道再来用Mat的时候,只能用CV_32F和CV_32S。所以说,如果这些矩阵不能写什么CV_8UC1之类的了,这个是错误的。

    假设我们写其他的情况,比如

    label为int,labelsMat为CV_32SC1

    这个是正确的。

    label为float,labelsMat为CV_32FC1

    这个会出现错误,这个我还没有分析出来是什么原因。错误的截图如下:。

    下面的错误均表示为截图所示的错误。

    label为int,labelsMat为CV_32FC1

    同样的,这个是错误。当我们用Imagewatch插件去观察labelsMat的值的时候发现这个labelsMat的值为。好吧,这个很明显了。

    label为float,labelsMat为CV_32SC1

    这个是可以运行的,但是结果肯定是错误的。同样的,值不对。

    ---------------------

    作者:wfh2015

    来源:CSDN

    原文:https://blog.csdn.net/wfh2015/article/details/51163890

    版权声明:本文为博主原创文章,转载请附上博文链接!

    相关文章

      网友评论

        本文标题:【转载】OpenCV3.0或OpenCV3.1的SVM操作

        本文链接:https://www.haomeiwen.com/subject/dqfkyqtx.html