美文网首页OpenCV Numpy skimage
【转载】用opencv中svm分割图像

【转载】用opencv中svm分割图像

作者: dopami | 来源:发表于2019-02-09 16:41 被阅读0次

    https://blog.csdn.net/shi923281339/article/details/77094757

    1.理解SVM

    请移步支持向量机通俗导论,通俗易懂,这里不在赘述。

    2.opencv中的SVM

    opencv中对svm的介绍:Support Vector Machines for Non-Linearly Separable Data

    官方测试代码:我做了详细的标注:

    #include <opencv2/core.hpp>

    #include <opencv2/imgproc.hpp>

    #include "opencv2/imgcodecs.hpp"

    #include <opencv2/highgui.hpp>

    #include <opencv2/ml.hpp>

    #include <iostream>

    using namespace std;

    using namespace cv;

    using namespace cv::ml;

    int main(int, char**)

    {

        // Data for visual representation

        int width = 512, height = 512;

        // zeros就是搞成全0矩阵

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

        // Set up training data

        //! [setup1]

        //设置训练数据

        int labels[4] = { 1, -1, -1, -1 };  // 每个样本点对应的类

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

        //! [setup1]

        //! [setup2]

        // 将训练数据存入浮点型Mat中

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

        // 使用OpenCV里面的机器学习算法时,要保证给的labelData的数据格式为”有符号的整型数”,

        // ”CV_32FC1”就是错误的一种形式,应该使用”CV_32SC1”

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

        //! [setup2]

        // Train the SVM

        //! [init]

        // 这里的svm是一个指针

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

        svm->setType(SVM::C_SVC);  // 文本选择

        svm->setKernel(SVM::LINEAR);

        // TermCriteria是一个结构体,包括终止的类型,迭代次数或者元素数量,精度。

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

        //! [init]

        //! [train],ROW_SAMPLE指每次训练样本的一行

        // 因此总的意思是每次训练样本的一行,而这一行是哪一类是由labelsMat决定的

        svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);

        //! [train]

        // Show the decision regions given by the SVM

        //! [show]

        Vec3b green(0, 255, 0), blue(255, 0, 0);

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

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

            {

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

                float response = svm->predict(sampleMat);

                if (response == 1)

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

                else if (response == -1)

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

            }

        //! [show]

        // Show the training data

        //! [show_data]

        int thickness = -1;    // 实心圆

        int lineType = 8;

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

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

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

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

        //! [show_data]

        // Show support vectors

        //! [show_vectors]

        thickness = 2;    // 线宽为2的圆

        lineType = 8;

        // 输出所有的支持向量

        //int c = svm->getVarCount();    // 获得支持向量的维数

        //cout << c << endl;

        Mat sv = svm->getSupportVectors();

        //cout << sv.cols << "-" << sv.rows << endl;

        // 训练出来的SVM classifier的support vector是以Mat类型进行存储,

        //其rows是根据svm的参数而变化的,如果是二分类分类器,应该是1*n的大小。

        // 这里一行存的坐标。

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

        {

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

            // 6是圆的半径,(128,128,128)是灰色

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

        }

        //! [show_vectors]

        imwrite("result.png", image);        // save the image

        imshow("SVM Simple Example", image); // show it to the user

        waitKey(0);

    }

    3.用SVM做简单的图像分割

    直接看代码,同样做了注释:

    #include <opencv2/core.hpp>

    #include <opencv2/imgproc.hpp>

    #include "opencv2/imgcodecs.hpp"

    #include <opencv2/highgui.hpp>

    #include <opencv2/ml.hpp>

    #include <iostream>

    using namespace std;

    using namespace cv;

    using namespace cv::ml;

    int main()

    {

        Mat srcImg = imread("test.jpg");

        Mat desImg = srcImg.clone();

        imshow("原图", srcImg);

        // 选取目标区域和背景区域

        Mat BackImg = srcImg(Rect(199, 0, 30, 30));

        Mat ForeImg = srcImg(Rect(38, 95, 30, 30));

        // 初始化训练数据

        Mat trainingDataMat = ForeImg.clone().reshape(1, ForeImg.cols*ForeImg.rows);

        //在这里直接存入背景像素点,或者像下边一个一个点存入也可以

        trainingDataMat.push_back(BackImg.clone().reshape(1,BackImg.cols*BackImg.rows));

        trainingDataMat.convertTo(trainingDataMat, CV_32FC1);

        // 初始化标签,分别给两种标签辅助,虽然这里memset已经全部初始化为1了,可是这里的1是浮点数

        int *labels = new int[ForeImg.cols*ForeImg.rows + BackImg.cols*BackImg.rows];

        memset(labels, 1, sizeof(int)*(ForeImg.cols*ForeImg.rows + BackImg.cols*BackImg.rows));

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

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

                labels[i*ForeImg.cols + j] = 1;

            }

        for (int h = 0; h<BackImg.rows; h++)

        {

            for (int w = 0; w<BackImg.cols; w++)

            {

                labels[ForeImg.cols*ForeImg.rows + h*BackImg.cols + w] = -1;

            }

        }

        Mat labelsMat = Mat(ForeImg.cols*ForeImg.rows + BackImg.cols*BackImg.rows, 1, CV_32SC1, labels);

        // 可以将数据写入文件来检查是否正确

        //FileStorage fs("data.xml", FileStorage::WRITE);

        //fs << "traindata" << trainingDataMat << "labels" << labelsMat;

        // Train the SVM

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

        svm->setType(SVM::C_SVC);

        svm->setKernel(SVM::RBF);

        svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, (int)1e5, 1e-6));

        svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);

        // 开始分类

        Vec3b black(0, 0, 0), white(255, 255, 255);

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

        {

            uchar* p_sample = desImg.ptr<uchar>(i);

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

            {

                Mat sampleMat(1, 3, CV_32FC1);

                sampleMat.at<float>(0, 0) = p_sample[3 * j + 0];

                sampleMat.at<float>(0, 1) = p_sample[3 * j + 1];

                sampleMat.at<float>(0, 2) = p_sample[3 * j + 2];

                float response = svm->predict(sampleMat);

                if (response == 1)

                    desImg.at<Vec3b>(i, j) = white;

                else if (response == -1)

                    desImg.at<Vec3b>(i, j) = black;

            }

        }

        imwrite("result.jpg", desImg);

        imshow("resImg", desImg);

        waitKey(0);

        return 0;

    }

    这里的白块就是我们选得目标区域。不知道是不是我参数选择不好,这里的分割效果步理想。

    参考博客:利用SVM支持向量机对彩色图像进行分割并使用OpenCV进行实现

    支持向量机通俗导论(理解SVM的三层境界)

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

    作者:影子要造反

    来源:CSDN

    原文:https://blog.csdn.net/shi923281339/article/details/77094757

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

    相关文章

      网友评论

        本文标题:【转载】用opencv中svm分割图像

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