SVM OpenCV c++ 预测只返回 1
SVM OpenCV c++ Predict returning nothing but 1's
我相信我已经成功地训练了一个 SVM
,但是当我尝试用它进行预测时,输出完全是 1。
我的训练代码如下所示:
for(size_t i = 0; i < (testPosArraySize); i++){
testGivenImg = imread(imagePosDir[i]);
detector->detect(testGivenImg, testKeypointsPos);
bowDE.compute(testGivenImg, testKeypointsPos, testFeaturesPos);
testFeaturesPos.reshape(1, 1);
testFeaturesVec.push_back(testFeaturesPos);
}
for(size_t i = 0; i < (testNegaArraySize); i++){
testGivenImg = imread(image[i]);
detector->detect(testGivenImg, testKeypointsNega);
bowDE.compute(testGivenImg, testKeypointsNega, testFeaturesNega);
testFeaturesNega.reshape(1, 1);
testFeaturesVec.push_back(testFeaturesNega);
}
Mat labels(numSamples, 1, CV_32F);
labels.rowRange(0, testPosArraySize).setTo(1);
labels.rowRange(testPosArraySize + 1, numSamples).setTo(-1);
SVM.model.train(fileTestFeat, labels, Mat(), Mat(), SVMParams());
我的预测代码如下所示:
vector<Mat> predictMatVec(predictArraySize); // -- amount of testing images
for(size_t i = 0; i < (predictArraySize); i++){
predictImg = imread(imageNegaDir[i]);
detector->detect(predictImg, predictKeypoints);
bowDE.compute(predictImg, predictKeypoints, predictFeatures);
predictFeatures.reshape(1, 1);
predictMatVec[i].push_back(predictFeatures);
Mat predictMat = Mat(predictMatVec);
float* predictFloat1D = (float*)predictMat.data;
Mat predictMat1D(1, fileTestFeat.cols, CV_32FC1, predictFloat1D);
float predictFloat = model.predict(predictMat1D);
cout << " -- SVM output: " << predictFloat << endl;
}
但它只返回 1。
有什么问题吗?
因此,词汇表已经创建(例如 BOWKMeansTrainer
),您可以开始训练 SVM classifier,对吧?
此时你有一个特征检测器、提取器、匹配器和一个 BOW 图像描述符提取器(使用视觉词袋计算图像描述符),例如:
cv::Ptr<cv::FeatureDetector> detector = cv::FeatureDetector::create("SURF");
cv::Ptr<cv::DescriptorExtractor> extractor = cv::DescriptorExtractor::create("SURF");
cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create("BruteForce ");
cv::BOWImgDescriptorExtractor bowide(extractor, matcher);
bowide->setVocabulary(vocabulary);
首先我们需要搜索直方图的训练集:
cv::Mat samples;
cv::Mat labels(0, 1, CV_32FC1);
for(auto& it : imagePosDir)
{
cv::Mat image = cv::imread(it);
std::vector<cv::KeyPoint> keypoints;
detector->detect(image, keypoints);
if(keypoints.empty()) continue;
// Responses to the vocabulary
cv::Mat imgDescriptor;
bowide.compute(image, keypoints, imgDescriptor);
if(imgDescriptor.empty()) continue;
if(samples.empty())
{
samples.create(0, imgDescriptor.cols, imgDescriptor.type());
}
// Copy class samples and labels
std::cout << "Adding " << imgDescriptor.rows << " positive sample." << std::endl;
samples.push_back(imgDescriptor);
cv::Mat classLabels = cv::Mat::ones(imgDescriptor.rows, 1, CV_32FC1);
labels.push_back(classLabels);
}
对 imagePosNeg
执行相同的操作,除了 classLabels
将具有零值,例如:
...
cv::Mat classLabels = cv::Mat::zeros(imgDescriptor.rows, 1, CV_32FC1);
labels.push_back(classLabels);
...
请注意我是如何构建样本和标签的,我用标签“1”标记了正样本,然后用标签“0”标记了负样本。所以我们有 samples
中每个 class 的训练数据(这里是正面和负面)。让我们开始训练吧:
cv::Mat samples_32f;
samples.convertTo(samples_32f, CV_32F);
CvSVM svm;
svm.train(samples_32f, labels);
// Do something with the classifier, like saving it to file
然后测试让我们开始测试 classifier:
for(auto& it : testDir)
{
cv::Mat image = cv::imread(it);
std::vector<cv::KeyPoint> keypoints;
detector->detect(image, keypoints);
if(keypoints.empty()) continue;
// Responses to the vocabulary
cv::Mat imgDescriptor;
bowide.compute(image, keypoints, imgDescriptor);
if(imgDescriptor.empty()) continue;
float res = svm.predict(imgDescriptor, true);
std::cout << "- Result of prediction: " << res << std::endl;
}
有效吗?
更新#1:
这里我做了一个关于OpenCV 3.0下的BOW+SVM的简单例子:
https://github.com/bkornel/OpenCV_BOW_SVM/blob/master/main.cpp
这对 class 化可口可乐/百事可乐瓶很有效。我还发布了二进制文件,因此您可以尝试使用您的数据库。希望它有效:)
我相信我已经成功地训练了一个 SVM
,但是当我尝试用它进行预测时,输出完全是 1。
我的训练代码如下所示:
for(size_t i = 0; i < (testPosArraySize); i++){
testGivenImg = imread(imagePosDir[i]);
detector->detect(testGivenImg, testKeypointsPos);
bowDE.compute(testGivenImg, testKeypointsPos, testFeaturesPos);
testFeaturesPos.reshape(1, 1);
testFeaturesVec.push_back(testFeaturesPos);
}
for(size_t i = 0; i < (testNegaArraySize); i++){
testGivenImg = imread(image[i]);
detector->detect(testGivenImg, testKeypointsNega);
bowDE.compute(testGivenImg, testKeypointsNega, testFeaturesNega);
testFeaturesNega.reshape(1, 1);
testFeaturesVec.push_back(testFeaturesNega);
}
Mat labels(numSamples, 1, CV_32F);
labels.rowRange(0, testPosArraySize).setTo(1);
labels.rowRange(testPosArraySize + 1, numSamples).setTo(-1);
SVM.model.train(fileTestFeat, labels, Mat(), Mat(), SVMParams());
我的预测代码如下所示:
vector<Mat> predictMatVec(predictArraySize); // -- amount of testing images
for(size_t i = 0; i < (predictArraySize); i++){
predictImg = imread(imageNegaDir[i]);
detector->detect(predictImg, predictKeypoints);
bowDE.compute(predictImg, predictKeypoints, predictFeatures);
predictFeatures.reshape(1, 1);
predictMatVec[i].push_back(predictFeatures);
Mat predictMat = Mat(predictMatVec);
float* predictFloat1D = (float*)predictMat.data;
Mat predictMat1D(1, fileTestFeat.cols, CV_32FC1, predictFloat1D);
float predictFloat = model.predict(predictMat1D);
cout << " -- SVM output: " << predictFloat << endl;
}
但它只返回 1。
有什么问题吗?
因此,词汇表已经创建(例如 BOWKMeansTrainer
),您可以开始训练 SVM classifier,对吧?
此时你有一个特征检测器、提取器、匹配器和一个 BOW 图像描述符提取器(使用视觉词袋计算图像描述符),例如:
cv::Ptr<cv::FeatureDetector> detector = cv::FeatureDetector::create("SURF");
cv::Ptr<cv::DescriptorExtractor> extractor = cv::DescriptorExtractor::create("SURF");
cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create("BruteForce ");
cv::BOWImgDescriptorExtractor bowide(extractor, matcher);
bowide->setVocabulary(vocabulary);
首先我们需要搜索直方图的训练集:
cv::Mat samples;
cv::Mat labels(0, 1, CV_32FC1);
for(auto& it : imagePosDir)
{
cv::Mat image = cv::imread(it);
std::vector<cv::KeyPoint> keypoints;
detector->detect(image, keypoints);
if(keypoints.empty()) continue;
// Responses to the vocabulary
cv::Mat imgDescriptor;
bowide.compute(image, keypoints, imgDescriptor);
if(imgDescriptor.empty()) continue;
if(samples.empty())
{
samples.create(0, imgDescriptor.cols, imgDescriptor.type());
}
// Copy class samples and labels
std::cout << "Adding " << imgDescriptor.rows << " positive sample." << std::endl;
samples.push_back(imgDescriptor);
cv::Mat classLabels = cv::Mat::ones(imgDescriptor.rows, 1, CV_32FC1);
labels.push_back(classLabels);
}
对 imagePosNeg
执行相同的操作,除了 classLabels
将具有零值,例如:
...
cv::Mat classLabels = cv::Mat::zeros(imgDescriptor.rows, 1, CV_32FC1);
labels.push_back(classLabels);
...
请注意我是如何构建样本和标签的,我用标签“1”标记了正样本,然后用标签“0”标记了负样本。所以我们有 samples
中每个 class 的训练数据(这里是正面和负面)。让我们开始训练吧:
cv::Mat samples_32f;
samples.convertTo(samples_32f, CV_32F);
CvSVM svm;
svm.train(samples_32f, labels);
// Do something with the classifier, like saving it to file
然后测试让我们开始测试 classifier:
for(auto& it : testDir)
{
cv::Mat image = cv::imread(it);
std::vector<cv::KeyPoint> keypoints;
detector->detect(image, keypoints);
if(keypoints.empty()) continue;
// Responses to the vocabulary
cv::Mat imgDescriptor;
bowide.compute(image, keypoints, imgDescriptor);
if(imgDescriptor.empty()) continue;
float res = svm.predict(imgDescriptor, true);
std::cout << "- Result of prediction: " << res << std::endl;
}
有效吗?
更新#1:
这里我做了一个关于OpenCV 3.0下的BOW+SVM的简单例子: https://github.com/bkornel/OpenCV_BOW_SVM/blob/master/main.cpp
这对 class 化可口可乐/百事可乐瓶很有效。我还发布了二进制文件,因此您可以尝试使用您的数据库。希望它有效:)