在opencv3中利用SVM進行圖像目標檢測和分類


采用鼠標事件,手動選擇樣本點,包括目標樣本和背景樣本。組成訓練數據進行訓練

1、主函數

#include "stdafx.h"
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace cv::ml;

Mat img,image;
Mat targetData, backData;
bool flag = true;
string wdname = "image";

void on_mouse(int event, int x, int y, int flags, void* ustc); //鼠標取樣本點
void getTrainData(Mat &train_data, Mat &train_label);  //生成訓練數據 
void svm(); //svm分類


int main(int argc, char** argv)
{
    string path = "d:/peppers.png";
    img = imread(path);
    img.copyTo(image);
    if (img.empty())
    {
        cout << "Image load error";
        return 0;
    }
    namedWindow(wdname);
    setMouseCallback(wdname, on_mouse, 0);

    for (;;)
    {
        imshow("image", img);

        int c = waitKey(0);
        if ((c & 255) == 27)
        {
            cout << "Exiting ...\n";
            break;
        }
        if ((char)c == 'c')
        {
            flag = false;
        }
        if ((char)c == 'q')
        {
            destroyAllWindows();
            break;
        }
    }
    svm();
    return 0;
}

首先輸入圖像,調用setMouseCallback函數進行鼠標取點

2、鼠標事件

//鼠標在圖像上取樣本點,按q鍵退出
void on_mouse(int event, int x, int y, int flags, void* ustc)
{
    if (event == CV_EVENT_LBUTTONDOWN)
    {
        Point pt = Point(x, y);
        Vec3b point = img.at<Vec3b>(y, x);  //取出該坐標處的像素值,注意x,y的順序
        Mat tmp = (Mat_<float>(1, 3) << point[0], point[1], point[2]);
        if (flag)
        {
            targetData.push_back(tmp); //加入正樣本矩陣
            circle(img, pt, 2, Scalar(0, 255, 255), -1, 8); //畫圓,在圖上顯示點擊的點 

        }

        else
        {
            backData.push_back(tmp); //加入負樣本矩陣
            circle(img, pt, 2, Scalar(255, 0, 0), -1, 8); 

        }
        imshow(wdname, img);
    }
}

用鼠標在圖像上點擊,取出當前點的紅綠藍像素值進行訓練。先選擇任意個目標樣本,然后按"c“鍵后選擇任意個背景樣本。樣本數可以自己隨意決定。樣本選擇完后,按”q"鍵完成樣本選擇。

3、svm分類

void getTrainData(Mat &train_data, Mat &train_label)
{
    int m = targetData.rows;
    int n = backData.rows;
    cout << "正樣本數::" << m << endl;
    cout << "負樣本數:" << n << endl;
    vconcat(targetData, backData, train_data); //合並所有的樣本點,作為訓練數據
    train_label = Mat(m + n, 1, CV_32S, Scalar::all(1)); //初始化標注
    for (int i = m; i < m + n; i++)
        train_label.at<int>(i, 0) = -1;
}

void svm()
{
    Mat train_data, train_label;
    getTrainData(train_data, train_label); //獲取鼠標選擇的樣本訓練數據

    // 設置參數
    Ptr<SVM> svm = SVM::create();
    svm->setType(SVM::C_SVC);
    svm->setKernel(SVM::LINEAR);

    // 訓練分類器
    Ptr<TrainData> tData = TrainData::create(train_data, ROW_SAMPLE, train_label);
    svm->train(tData);

    Vec3b color(0, 0, 0);
    // Show the decision regions given by the SVM
    for (int i = 0; i < image.rows; ++i)
    for (int j = 0; j < image.cols; ++j)
    {
        Vec3b point = img.at<Vec3b>(i, j);  //取出該坐標處的像素值
        Mat sampleMat = (Mat_<float>(1, 3) << point[0], point[1], point[2]);
        float response = svm->predict(sampleMat);  //進行預測,返回1或-1,返回類型為float
        if ((int)response != 1)
            image.at<Vec3b>(i, j) = color;  //將背景點設為黑色
    }

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

將正負樣本矩陣,用vconcat合並成一個矩陣,用作訓練分類器,並對相應的樣本進行標注。最后將識別出的目標保留,將背景部分調成黑色。

4、完整程序

// svm.cpp : 定義控制台應用程序的入口點。
//

#include "stdafx.h"
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace cv::ml;

Mat img,image;
Mat targetData, backData;
bool flag = true;
string wdname = "image";

void on_mouse(int event, int x, int y, int flags, void* ustc); //鼠標取樣本點
void getTrainData(Mat &train_data, Mat &train_label);  //生成訓練數據 
void svm(); //svm分類


int main(int argc, char** argv)
{
    string path = "d:/peppers.png";
    img = imread(path);
    img.copyTo(image);
    if (img.empty())
    {
        cout << "Image load error";
        return 0;
    }
    namedWindow(wdname);
    setMouseCallback(wdname, on_mouse, 0);

    for (;;)
    {
        imshow("image", img);

        int c = waitKey(0);
        if ((c & 255) == 27)
        {
            cout << "Exiting ...\n";
            break;
        }
        if ((char)c == 'c')
        {
            flag = false;
        }
        if ((char)c == 'q')
        {
            destroyAllWindows();
            break;
        }
    }
    svm();
    return 0;
}

//鼠標在圖像上取樣本點,按q鍵退出
void on_mouse(int event, int x, int y, int flags, void* ustc)
{
    if (event == CV_EVENT_LBUTTONDOWN)
    {
        Point pt = Point(x, y);
        Vec3b point = img.at<Vec3b>(y, x);  //取出該坐標處的像素值,注意x,y的順序
        Mat tmp = (Mat_<float>(1, 3) << point[0], point[1], point[2]);
        if (flag)
        {
            targetData.push_back(tmp); //加入正樣本矩陣
            circle(img, pt, 2, Scalar(0, 255, 255), -1, 8); //畫出點擊的點 

        }

        else
        {
            backData.push_back(tmp); //加入負樣本矩陣
            circle(img, pt, 2, Scalar(255, 0, 0), -1, 8); 

        }
        imshow(wdname, img);
    }
}

void getTrainData(Mat &train_data, Mat &train_label)
{
    int m = targetData.rows;
    int n = backData.rows;
    cout << "正樣本數::" << m << endl;
    cout << "負樣本數:" << n << endl;
    vconcat(targetData, backData, train_data); //合並所有的樣本點,作為訓練數據
    train_label = Mat(m + n, 1, CV_32S, Scalar::all(1)); //初始化標注
    for (int i = m; i < m + n; i++)
        train_label.at<int>(i, 0) = -1;
}

void svm()
{
    Mat train_data, train_label;
    getTrainData(train_data, train_label); //獲取鼠標選擇的樣本訓練數據

    // 設置參數
    Ptr<SVM> svm = SVM::create();
    svm->setType(SVM::C_SVC);
    svm->setKernel(SVM::LINEAR);

    // 訓練分類器
    Ptr<TrainData> tData = TrainData::create(train_data, ROW_SAMPLE, train_label);
    svm->train(tData);

    Vec3b color(0, 0, 0);
    // Show the decision regions given by the SVM
    for (int i = 0; i < image.rows; ++i)
    for (int j = 0; j < image.cols; ++j)
    {
        Vec3b point = img.at<Vec3b>(i, j);  //取出該坐標處的像素值
        Mat sampleMat = (Mat_<float>(1, 3) << point[0], point[1], point[2]);
        float response = svm->predict(sampleMat);  //進行預測,返回1或-1,返回類型為float
        if ((int)response != 1)
            image.at<Vec3b>(i, j) = color;  //將背景設置為黑色
    }

    imshow("SVM Simple Example", image); 
    waitKey(0);
}

 

輸入原圖像:

程序運行后顯示:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM