最近在做一些纹理分割方面的东西,需要提取图像特征后进行训练分类。在师兄的指点下了解SVM(支持向量机)可以达到很好的效果。
在opencv(版本)自带OpenCV\samples\cpp\tutorial_code\ml\introduction_to_svm 下找到了简单的introduction_to_svm.cpp
- #include <opencv2/core/core.hpp>
- #include <opencv2/highgui/highgui.hpp>
- #include <opencv2/ml/ml.hpp>
-
- using namespace cv;
-
- int main()
- {
- // Data for visual representation
- int width = 512, height = 512;
- Mat image = Mat::zeros(height, width, CV_8UC3);
-
- // Set up training data
- float labels[4] = {1.0, -1.0, -1.0, -1.0};
- Mat labelsMat(4, 1, CV_32FC1, labels);
-
- float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };
- Mat trainingDataMat(4, 2, CV_32FC1, trainingData);
-
- // Set up SVM's parameters
- CvSVMParams params;
- params.svm_type = CvSVM::C_SVC;
- params.kernel_type = CvSVM::LINEAR;
- params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
-
- // Train the SVM
- CvSVM SVM;
- SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);
-
- Vec3b green(0,255,0), blue (255,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)
- {
- Mat sampleMat = (Mat_<float>(1,2) << i,j);
- float response = SVM.predict(sampleMat);
-
- if (response == 1)
- image.at<Vec3b>(j, i) = green;
- else if (response == -1)
- image.at<Vec3b>(j, i) = blue;
- }
-
- // Show the training 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 support vectors
- thickness = 2;
- lineType = 8;
- int c = SVM.get_support_vector_count();
-
- for (int i = 0; i < c; ++i)
- {
- const float* v = SVM.get_support_vector(i);
- circle( image, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thickness, lineType);
- }
-
- imwrite("result.png", image); // save the image
-
- imshow("SVM Simple Example", image); // show it to the user
- waitKey(0);
-
- }
在该段程序中,我们运行后得到结果图如下图所示:
但是如果我们将代码第10行的width值改为1024,则数组越界。
最后发现在代码的39行
- if (response == 1)
- image.at<Vec3b>(j, i) = green;
- else if (response == -1)
- image.at<Vec3b>(j, i) = blue;
中,将i,j位置改变后,
- if (response == 1)
- image.at<Vec3b>(i, j) = green;
- else if (response == -1)
- image.at<Vec3b>(i, j) = blue;
得到结果
- <IMG alt="" src="http://img.blog.csdn.net/20131212212856531">
明显结果有问题,由于我们改了坐标35行的Mat sampleMat = (Mat_<float>(1,2) << i,j); 顺序也要调换一下,改为Mat sampleMat = (Mat_<float>(1,2) << j,i);结果图就很正常了,如下图
分析该问题的产生原因,主要是image.at<Vec3b>(j, i)这段代码是先行后列,顺序反了。归根到底opencv中的svm以空间为特征的话,一定记得顺序的对应关系,否则会出现很奇怪的结果。 最终修改后代码如下所示:
- #include <opencv2/core/core.hpp>
- #include <opencv2/highgui/highgui.hpp>
- #include <opencv2/ml/ml.hpp>
-
- using namespace cv;
-
- int main()
- {
- // Data for visual representation
- int width = 1024, height = 512;
- Mat image = Mat::zeros(height, width, CV_8UC3);
-
- // Set up training data
- float labels[4] = {1.0, -1.0, -1.0, -1.0};
- Mat labelsMat(4, 1, CV_32FC1, labels);
-
- float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };
- Mat trainingDataMat(4, 2, CV_32FC1, trainingData);
-
- // Set up SVM's parameters
- CvSVMParams params;
- params.svm_type = CvSVM::C_SVC;
- params.kernel_type = CvSVM::LINEAR;
- params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
-
- // Train the SVM
- CvSVM SVM;
- SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);
-
- Vec3b green(0,255,0), blue (255,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)
- {
- 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 the training 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 support vectors
- thickness = 2;
- lineType = 8;
- int c = SVM.get_support_vector_count();
-
- for (int i = 0; i < c; ++i)
- {
- const float* v = SVM.get_support_vector(i);
- circle( image, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thickness, lineType);
- }
-
- imwrite("result.png", image); // save the image
-
- imshow("SVM Simple Example", image); // show it to the user
- waitKey(0);
-
- }
|