C++ OpenCV SVM 预测不工作
Posted
技术标签:
【中文标题】C++ OpenCV SVM 预测不工作【英文标题】:C++ OpenCV SVM Predict Not Working 【发布时间】:2015-03-15 02:03:06 【问题描述】:试图创建一个功能性的SVM
。我有 114 张训练图像、60 张正面图像/54 张负面图像和 386 张测试图像供 SVM
预测。
我将训练图像特征读入float
,如下所示:
trainingDataFloat[i][0] = trainFeatures.rows;
trainingDataFloat[i][1] = trainFeatures.cols;
测试图像也是如此:
testDataFloat[i][0] = testFeatures.rows;
testDataFloat[i][2] = testFeatures.cols;
然后,使用 Micka 的 answer to this question,我将 testDataFloat
转换为一维数组,然后像这样将其输入到 Mat
,以便在 SVM
上进行预测:
float* testData1D = (float*)testDataFloat;
Mat testDataMat1D(height*width, 1, CV_32FC1, testData1D);
float testPredict = SVMmodel.predict(testDataMat1D);
一切就绪后,就会出现以下调试错误:
cvPreparePredictData 中输入参数的大小不匹配(样本大小与用于训练的大小不同)
看着this post,我发现(感谢berak):
“所有图像(用于训练和预测)的大小必须相同”
所以我添加了一个调整大小的功能,可以将图像重新调整为您希望的任意大小的正方形 (100x100, 200x200, 1000, 1000 etc.
)
再次运行它,将图像重新调整到程序现在从中加载图像的新目录,我得到与以前完全相同的错误:
cvPreparePredictData 中输入参数的大小不匹配(样本大小与用于训练的大小不同)
我只是不知道该怎么做。为什么它仍然抛出该错误?
编辑
我变了
Mat testDataMat1D(TestDFheight*TestDFwidth, 1, CV_32FC1, testData1D);
到
Mat testDataMat1D(1, TestDFheight*TestDFwidth, CV_32FC1, testData1D);
并将.predict
放在将features
分配给float
的循环中,以便每个图像都单独分配给.predict
,因为this question。随着 int
的交换,.cols
= 1 和 .rows
= TestDFheight*TestDFwidth
程序似乎实际运行,但随后在图像 160 (.exe has stopped working
) 上停止...所以这是一个新问题。
编辑 2
添加了一个简单的
std::cout << testPredict;
查看 SVM 的确定输出,它似乎正匹配所有内容,直到 Image 160 停止运行:
【问题讨论】:
请发布您的svm.train(...);
行并详细说明您提供给它的参数。
我正在使用默认的 SVM 参数和火车:SVMmodel.train(trainingDataMat, labelsMat, Mat(), Mat(), SVMParams());
trainingDataMat
的尺寸是多少,您的训练和预测图像的尺寸是多少?
Training Mat: Mat trainingDataMat(height, width, CV_32FC1, trainingDataFloat);
- height
= 114 width
= 2. 训练和测试的图像都调整为 500x500
根据***.com/questions/14694810/… 它应该类似于:Mat trainingDataMat(114, 500*500, CV_32FC1, trainingDataFloat);
而不是...其中 114 是输入图像的数量,而 500*500 是您想要输入的一维数组的大小稍后预测。
【参考方案1】:
请检查您的训练和测试特征向量。
我假设您的特征数据是某种形式的 cv::Mat,每行都包含特征。 在这种情况下,您希望您的训练矩阵是每个图像中每个特征矩阵的串联。 这些行看起来不正确:
trainingDataFloat[i][0] = trainFeatures.rows;
trainingDataFloat[i][1] = trainFeatures.cols;
这是将二维矩阵的元素设置为 trainFeatures 中的行数和列数。这与 trainFeatures 矩阵中的实际数据无关。
你想检测什么?如果每个图像都是正面和负面的例子,那么您是否试图检测图像中的某些东西?你有什么特点?
如果您尝试在每张图像的基础上检测图像中的对象,那么您需要一个特征向量在一个向量中描述整个图像。在这种情况下,您会对训练数据执行以下操作:
int N; // Set to number of images you plan on using for training
int feature_size; // Set to the number of features extracted in each image. Should be constant across all images.
cv::Mat X = cv::Mat::zeros(N, feature_size, CV_32F); // Feature matrix
cv::Mat Y = cv::Mat::zeros(N, 1, CV_32F); // Label vector
// Now use a for loop to copy data into X and Y, Y = +1 for positive examples and -1 for negative examples
for(int i = 0; i < trainImages.size(); ++i)
X.row(i) = trainImages[i].features; // Where features is a cv::Mat row vector of size N of the extracted features
Y.row(i) = trainImages[i].isPositive ? 1:-1;
// Now train your cv::SVM on X and Y.
【讨论】:
当你说“应该在所有图像中保持不变。”,你的意思是每个图像提取的特征数量应该相同吗?并设置feature_size
我会喂它trainFeatures.rows
?你会在一个循环中完成所有这些,然后再训练吗?
另外,trainImages
将是 vector
是吗?而且我不明白你的措辞“特征是提取特征的大小为 N 的 cv::Mat 行向量”。
是的,要能够训练 SVM,您需要恒定数量的特征。我假设 trainImages 是所有特征图像结构的向量。该结构将只包含一个用于该图像特征的 cv::Mat 和一个布尔参数 isPositive,如果它是一个正类则为 true。
但是如果你将所有特征的SVM
和Mat
一起提供,为什么每张图像都需要检测到完全相同数量的特征呢?我的印象是,你不能一次训练一个 SVM
,而是给它一个 Mat
,其中每个 row
包含每个单独图像的特征。
您确实需要将所有特征连接到我上面描述的 X 矩阵中。该矩阵每行包含一个样本。现在的问题更是如此,你在寻找什么?如果您从每个图像中提取可变数量的特征,并且您知道每个特征对应于您的目标,那么您可以在每个特征上训练 SVM 是可行的。但是例如,如果您要提取 sift 并在 sift 上训练 SVM,那么您正在训练 SVM 以基于单个提取点检测整个对象。所以请更清楚地描述你的目标。以上是关于C++ OpenCV SVM 预测不工作的主要内容,如果未能解决你的问题,请参考以下文章