我是OpenCv的新手,正在从OpenCv2.4过渡到OpenCv3…我已经训练SVM分类器存储在*.xml文件。
我在转换过程中的问题是如何准备cv::Mat正确,以便它可以输入cv::ml::SVM预测。
CvMat* NumExtractor::prepareDataSVM(cv::Mat & other){
resize(other, other, Size(28,28));
cv::Size s = other.size();
int width = (int)s.width;
int height = (int)s.height;
cv::Mat ret = other.clone();
CvMat* mat = cvCreateMat(width*height, 1, CV_32FC1);
for(int i = 0; i < height; ++i)
{
for(int j = 0; j < width; ++j)
{
mat.data.fl[i*width+j] = (float)other.at<uchar>(i,j);
}
}
return mat;
}
但是我正在努力如何用cv::Mat做到这一点。有人能帮帮我吗?
编辑:我想明白了。我使用了错误的API来存储值
下面的代码可以帮助您开始使用cv::ml::SVM的train()和predict()函数;下面是代码的解释(代码在openv4.2中运行良好)。输入图像是来自数据集的水下图像(这里有基准测试https://li-chongyi.github.io/proj_benchmark.html)。代码的第一部分处理图像的红色通道补偿,该补偿改善了图像的色差。对于红色通道补偿,论文中的公式8;基于CFA的水下图像色彩校正和基于密集像素的视网膜增强已经用过了。红色通道补偿图像存储在代码中的image2中。
然后,选择图像中仅包含水像素的矩形部分作为训练数据。训练数据被分类成一个3列矩阵,每列分别保存红、绿、蓝强度值(例如mx3)。
由于我们需要两个玻璃杯,那么图像中包含非水像素的矩形部分被选择作为数据的另一部分。
然后,将只有水的数据和没有水的数据连接起来,形成训练数据。标签矩阵被安排成水像素+ 1和水像素- 1。然后设法使支持向量机与线性核一起运行,但也为gamma设置一个值以便与RBF核一起运行。{输入图像}
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/ml/ml.hpp>
using namespace cv;
using namespace cv::ml;
using namespace std;
int main()
{
std::cout << "Hello World!n";
//read an image
Mat image = imread("9554.png", 1);
//check for existance of data
if (!image.data)
{ printf("no image data.n"); return -1; }
//planes is a vector for holding rgb channels separately
//std::vector<Mat> planes;
Mat planes[3];
//split the image into channels
//planes[2] is the red channel
split(image, planes);
// converting planes from uchar to double
planes[0].convertTo(planes[0], CV_64FC1);
planes[1].convertTo(planes[1], CV_64FC1);
planes[2].convertTo(planes[2], CV_64FC1);
// defining coefficients of green and blue channel for blending
double a = 0.05, b = 0.95;
//sum_im stores pixelwise sum of Red, Green and Blue planes
Mat imBlendNormal_B_G, sum_im;
//converting to double
imBlendNormal_B_G.convertTo(imBlendNormal_B_G, CV_64FC1);
sum_im.convertTo(sum_im, CV_64FC1);
//blending green and blue planes with a and b coefficients
// and 0.0 offset(or gamma)
addWeighted(planes[1], a, planes[0], b, 0.0, imBlendNormal_B_G);
// sum of red, green and blue pixel in two addWeighted calls
addWeighted(planes[2], 1.0, planes[1], 1.0, 0.0, sum_im);
addWeighted(planes[0], 1.0, sum_im, 1.0, 0.0, sum_im);
//dividing blended green and blue image to total RGB sum
divide(imBlendNormal_B_G, sum_im, imBlendNormal_B_G);
//defining average kernel 3x3
Mat avg3x3_kernel = (Mat_<double>(3, 3) << 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0);
//defining matrices for storing 3x3 average of blue and green planes
Mat blueAverage, greenAverage;
// converting to double type
blueAverage.convertTo(blueAverage, CV_64FC1);
greenAverage.convertTo(greenAverage, CV_64FC1);
// taking 3x3 average
filter2D(planes[0], blueAverage, planes[0].depth(), avg3x3_kernel);
filter2D(planes[1], greenAverage, planes[1].depth(), avg3x3_kernel);
//imBlendAverage_B_G_R: for blending of averaged green and blue channels
Mat imBlendAverage_B_G_R;
//convert to double
imBlendAverage_B_G_R.convertTo(imBlendAverage_B_G_R, CV_64FC1);
//blend averaged green and blue with a and b coeffs
addWeighted(greenAverage, a, blueAverage, b, 0.0, imBlendAverage_B_G_R);
//differentiate red values
addWeighted(imBlendAverage_B_G_R, 1.0, planes[2], -1.0, 0.0, imBlendAverage_B_G_R);
//CompensationTermRed: storing finally compensated red channel intensities
Mat CompensationTermRed;
//coverting to double
CompensationTermRed.convertTo(CompensationTermRed, CV_64FC1);
//multiplication term
CompensationTermRed = imBlendAverage_B_G_R.mul(imBlendNormal_B_G);
//final add term
addWeighted(CompensationTermRed, 1.0, planes[2], 1.0, 0.0, CompensationTermRed);
// assign new red channel values to planes[2]
planes[2] = CompensationTermRed;
Mat image2;
cv::merge(planes, 3, image2);
image2.convertTo(image2, CV_8UC3);
imshow("merge",image2);
printf("ndims of image2 (merge): %d %dn", image2.rows, image2.cols);
//defining rectangle of coordination
Rect waterrect(5,5,365,135);
// water only image
Mat WaterOnlyImage = image(waterrect);
imshow("water only image", WaterOnlyImage);
// separating WaterOnlyImage planes
Mat WaterOnlyPlanes[3];
split(WaterOnlyImage, WaterOnlyPlanes);
printf("size of WaterOnlyPlanes[0]: %d %d %dn", WaterOnlyPlanes[0].rows,WaterOnlyPlanes[0].cols, WaterOnlyPlanes[0].channels());
// vector of each plane
Mat WaterOnlyRedVector, WaterOnlyGreenVector, WaterOnlyBlueVector;
// reshape each plane into vector separately
// column vector
WaterOnlyRedVector = WaterOnlyPlanes[2].reshape(0, 1).t();
WaterOnlyGreenVector = WaterOnlyPlanes[1].reshape(0, 1).t();
WaterOnlyBlueVector = WaterOnlyPlanes[0].reshape(0, 1).t();
printf("WaterOnlyRedVector size: %d %d %dn", WaterOnlyRedVector.rows, WaterOnlyRedVector.cols, WaterOnlyRedVector.channels());
// (row*com)x3 vector holding all RGB pixels of water
// (WaterOnlyRedVector.rows, 3);
Mat WaterOnlyRGBVector;
// concatenation of three vectors values using hconcat
// hconcate: horizontal concatenation
hconcat(WaterOnlyRedVector, WaterOnlyGreenVector, WaterOnlyRGBVector);
hconcat(WaterOnlyRGBVector, WaterOnlyBlueVector, WaterOnlyRGBVector);
printf("WaterOnlyRGBVector dims is: %d %d %dn", WaterOnlyRGBVector.rows, WaterOnlyRGBVector.cols, WaterOnlyRGBVector.channels());
// label vector for water pixels, all preset one
Mat WaterOnlyLabelVector_float = Mat::ones(WaterOnlyRGBVector.rows, 1, CV_32SC1);
printf("WaterOnlyLabelVector_float dims: %dt%dt%dtn", WaterOnlyLabelVector_float.rows, WaterOnlyLabelVector_float.cols, WaterOnlyLabelVector_float.channels());
//std::cout << WaterOnlyLabelVector_float << "n";
// defining non water coordination
Rect nonWaterRect(1, 400, 640, 320);
//non water image
Mat NonWaterImage = image(nonWaterRect);
imshow("non water image", NonWaterImage);
//holding plited nonwater image planes
Mat NonWaterPlanes[3];
//split nonwater image sample
split(NonWaterImage, NonWaterPlanes);
printf("NonWaterPlanes[0] dims: %dt%dt%d n", NonWaterPlanes[0].rows, NonWaterPlanes[0].cols, NonWaterPlanes[0].channels());
// 3 column vector for each of rgb planes
Mat NonWaterRedVector, NonWaterGreenVector, NonWaterBlueVector;
// reshaping each plane to get a column vector Mx1
NonWaterRedVector = NonWaterPlanes[2].reshape(0, 1).t();//red 1st
NonWaterGreenVector = NonWaterPlanes[1].reshape(0, 1).t();//green 2nd
NonWaterBlueVector = NonWaterPlanes[0].reshape(0, 1).t();//blue
printf("NonWaterGreenVector size is: %dt%dt%dtn", NonWaterGreenVector.rows, NonWaterGreenVector.cols, NonWaterGreenVector.channels());
// Mx3 vector holding all RGB pixels of NonWater
Mat NonWaterRGBVector;
// concatenate 3 column vec into one place (Mx3)
cv::hconcat(NonWaterRedVector, NonWaterGreenVector, NonWaterRGBVector);
cv::hconcat(NonWaterRGBVector, NonWaterBlueVector, NonWaterRGBVector);
printf("NonWaterRGBVector dims: %dt%dt%dtn", NonWaterRGBVector.rows, NonWaterRGBVector.cols, NonWaterRGBVector.channels());
// label vector for NonWater pixels
Mat NonWaterLabelVector_float = cv::Mat::zeros(NonWaterRGBVector.rows, 1, CV_32SC1) - 1.0;
printf("NonWaterLabelVector_float dims: %dt%dt%dtn", NonWaterLabelVector_float.rows, NonWaterLabelVector_float.cols, NonWaterLabelVector_float.channels());
//cout << NonWaterLabelVector_float << "n";
// label matrix for all data
Mat AllLabelVector_float;
cv::vconcat(WaterOnlyLabelVector_float, NonWaterLabelVector_float, AllLabelVector_float);
printf("AllLabelVector_float dims: %dt%dt%dtn", AllLabelVector_float.rows, AllLabelVector_float.cols, AllLabelVector_float.channels());
//concatenation of all training data
// uchar mat
Mat AllTrainingDataVector_uchar;
cv::vconcat(WaterOnlyRGBVector, NonWaterRGBVector, AllTrainingDataVector_uchar);
// convert to double
Mat AllTrainingDataVector_float;
AllTrainingDataVector_uchar.convertTo(AllTrainingDataVector_float, CV_32F);
printf("AllTrainingDataVector_float dims: %dt%dt%dtn", AllTrainingDataVector_float.rows, AllTrainingDataVector_float.cols, AllTrainingDataVector_float.channels());
//std::cout << AllTrainingDataVector_float << "n";
// define support vector machine
Ptr<ml::SVM> WaterSVMParams = ml::SVM::create();
WaterSVMParams->setType(cv::ml::SVM::C_SVC);
WaterSVMParams->setKernel(cv::ml::SVM::RBF);
WaterSVMParams->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER,100,1e-6));
WaterSVMParams->setGamma(0.000000001);
// train data
WaterSVMParams->train(AllTrainingDataVector_float, ROW_SAMPLE, AllLabelVector_float);
// prediction responses image
Mat WaterPredictionImage = Mat::zeros(image.rows, image.cols, CV_8UC3);
// blue for water and green for nonwater
Vec3b green(0, 255, 0), blue(255, 0, 0);
// loop to fill the response image with prediction colors
for (int i = 0; i < image.rows; i++)
{
for (int j = 0; j < image.cols; j++) {
// getting one pixel at (i,j)
Vec3b oneTestPixel = image.at<Vec3b>(i, j);
// getting rgb vals
float oneTestPixelRed = (float)oneTestPixel.val[2];
float oneTestPixelGreen = (float)oneTestPixel.val[1];
float oneTestPixelBlue = (float)oneTestPixel.val[0];
Mat samplePixelMat = (Mat_<float>(1, 3) << oneTestPixelRed, oneTestPixelGreen, oneTestPixelBlue);
//cout <<"curret test pixel:t" << samplePixelMat << "n";
float responseSVM = WaterSVMParams->predict(samplePixelMat);
if (responseSVM == 1.0) {
WaterPredictionImage.at<Vec3b>(i, j) = blue;
}
if (responseSVM == -1.0) {
WaterPredictionImage.at<Vec3b>(i, j) = green;
}
}//end of for j
}//end of for i
imshow("WaterPredictionImage-Linear Kernel", WaterPredictionImage);
waitKey(0);
return 0;
}