采用鼠標事件,手動選擇樣本點,包括目標樣本和背景樣本。組成訓練數據進行訓練
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); }
輸入原圖像:
程序運行后顯示: