为 svm::predict 准备 cv::mat
Posted
技术标签:
【中文标题】为 svm::predict 准备 cv::mat【英文标题】:cv::mat preparation for svm::predict 【发布时间】:2015-07-09 19:09:20 【问题描述】:我是 OpenCv 的新手,正在从 OpenCv2.4 过渡到 OpenCv3... 我已经训练了存储在 *.xml 文件中的 SVM 分类器。
我在过渡期间的问题是如何正确准备 cv::Mat 以便它可以作为 cv::ml::SVM predict 的输入。
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 来存储值。
【问题讨论】:
other
是什么?以及为什么要调整为 28x28?
其他是带有数字的输入图像,我想将其提供给 svm 进行分类。我调整它的大小是因为我在 28x28 样本上训练了 svm
那么,你的一维特征是什么?
嗯,有问题,或者它是......我需要将我的图像转换为 1d 并将其存储在 cv::mat 中,以便我可以提供给 svm。我不知道怎么把它放在垫子里,但我刚刚想通了。 :)
好吧,然后解决了.. :D 只是一些建议:返回一个Mat1f
(没有指针),使other
一个Mat1b
,创建mat
喜欢:Mat1f mat(width*height, 1, 0.f)
, 将数据设置为mat
like: mat(i*width+j) = float(other(i,j))
.
【参考方案1】:
以下代码帮助您开始使用 cv::ml::SVM 的 train() 和 predict() 函数;这是代码的解释(代码在opencv4.2中运行良好)。 输入图像是来自数据集的水下图像(可在此处获得基准https://li-chongyi.github.io/proj_benchmark.html)。代码的第一部分处理图像的红色通道补偿,以改善图像的色彩偏差。 对于红色通道补偿,使用了论文“Color Correction Based on CFA and Enhancement Based on Retinex With Dense Pixels for Underwater Images”的公式8。红色通道补偿后的图像在代码中存储在 image2 中。
然后,选择图像中仅包含水像素的矩形部分作为训练数据。训练数据被分类成一个 3 列矩阵,每列分别保存红色、绿色和蓝色强度值(例如 mx3)。
由于我们需要两副眼镜,因此选择图像中包含非水像素的矩形部分作为数据的另一部分。
然后,将纯水数据和非水数据连接起来形成训练数据。标签矩阵的排列方式使其为水像素保持 + 1 和 - 1 水像素。 然后 SVM 被管理以使用线性内核运行,但伽马也设置了一个值以便使用 RBF 内核运行。 input image
#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 %d\n", 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 %d\n", 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 %d\n", 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 %d\n", 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: %d\t%d\t%d\t\n", 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: %d\t%d\t%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: %d\t%d\t%d\t\n", 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: %d\t%d\t%d\t\n", 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: %d\t%d\t%d\t\n", 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: %d\t%d\t%d\t\n", 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: %d\t%d\t%d\t\n", 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;
【讨论】:
以上是关于为 svm::predict 准备 cv::mat的主要内容,如果未能解决你的问题,请参考以下文章