使用 cv::ml::StatModel::train 以使用 KNN 的 Opencv 错误
Opencv Error using cv::ml::StatModel::train in order to use KNN
问题 #1:
我正在尝试使用 Visual Studio 2017 和 C++ 在 opencv 3.4 中实现 KNN。到目前为止,我已经能够解决我的问题,但昨天我 运行 陷入了这个错误:
"A nonstatic member reference must be relative to a specific object"
int main(int argc, const char *argv[]) {
ReadData("smokeDataBase.yml", 0);//14 smoke
ReadData("forestDataBase.yml" , 1); //14 forest
ReadData("skyDataBase.yml", 2); //12 sky
ReadData("testDataBase.yml", 3);
Mat trainClasses = (Mat_<float>(40, 1) << 1, 1, 1, 1, 1, 1, 1, 1,1,1, 1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0); //Couldn't figure out how to do this in some other way
//We prepare the data to use in KNN using self-made function that gets every
//vector in my .yml and appends them together
Mat trainData = prepTrain(forestDataBase, skyDataBase, smokeDataBase);
//学习分类器
诠释 K = 10;
ptr knn = ml::KNearest::create();
ml::StatModel::train(trainData, ml::ROW_SAMPLE, trainClasses); //这一行给出错误
}
因为我不能训练 KNN(虽然 KNN 严格来说不是一种学习方法)我不能使用 KNearest::findNearest 从代码中实际得到我想要的东西。我找不到任何适合我的问题的答案,所以我写这篇文章。
我删除了所有未使用的代码部分,以使你们更容易帮助我。
问题 #2:
当我创建变量 TrainData 时,我将 smoke/forest/skyDatabase 上的所有数据放在一起。换句话说,我将所有数据附加到一个单一的大向量中。这是正确的方法吗?我是否应该划分成一个 "vector TrainData" 变量,其中每个 TrainData[i](i 从 0 到 TrainData.size)是代表我的数据样本的向量?
这是你的第一个问题:
这是 official documentation
中描述的函数 train 的签名
virtual bool cv::ml::StatModel::train ( InputArray samples,
int layout,
InputArray responses
)
如您所见,该方法是虚拟的,这意味着您不能以这种方式调用它!。此功能应由 StatModel 的子 classes 实现。因此,当您想要使用该方法时,您可以从实现该方法的子 class 中调用该方法。 class KNearest 实现了这一点。您的代码应更改为:
Ptr<ml::KNearest> knn = ml::KNearest::create();
knn->train(trainData, ml::ROW_SAMPLE , trainClasses);
现在回答你的第二个问题:
您可以将数据准备为 ROW_SAMPLE 或 COL_SAMPLE。
在 ROW_SAMPLE 中,每个样本都在一行中。因此,如果您的样本由三个浮点数组成并且您有 10 个样本,那么您最终应该得到一个具有 10 行和 3 列的 Mat 对象。
在COL_SAMPLE中,一切都颠倒了。所以你最终得到 3 行和 10 列。
问题 #1:
我正在尝试使用 Visual Studio 2017 和 C++ 在 opencv 3.4 中实现 KNN。到目前为止,我已经能够解决我的问题,但昨天我 运行 陷入了这个错误: "A nonstatic member reference must be relative to a specific object"
int main(int argc, const char *argv[]) {
ReadData("smokeDataBase.yml", 0);//14 smoke
ReadData("forestDataBase.yml" , 1); //14 forest
ReadData("skyDataBase.yml", 2); //12 sky
ReadData("testDataBase.yml", 3);
Mat trainClasses = (Mat_<float>(40, 1) << 1, 1, 1, 1, 1, 1, 1, 1,1,1, 1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0); //Couldn't figure out how to do this in some other way
//We prepare the data to use in KNN using self-made function that gets every
//vector in my .yml and appends them together
Mat trainData = prepTrain(forestDataBase, skyDataBase, smokeDataBase);
//学习分类器 诠释 K = 10; ptr knn = ml::KNearest::create(); ml::StatModel::train(trainData, ml::ROW_SAMPLE, trainClasses); //这一行给出错误
}
因为我不能训练 KNN(虽然 KNN 严格来说不是一种学习方法)我不能使用 KNearest::findNearest 从代码中实际得到我想要的东西。我找不到任何适合我的问题的答案,所以我写这篇文章。
我删除了所有未使用的代码部分,以使你们更容易帮助我。
问题 #2:
当我创建变量 TrainData 时,我将 smoke/forest/skyDatabase 上的所有数据放在一起。换句话说,我将所有数据附加到一个单一的大向量中。这是正确的方法吗?我是否应该划分成一个 "vector TrainData" 变量,其中每个 TrainData[i](i 从 0 到 TrainData.size)是代表我的数据样本的向量?
这是你的第一个问题: 这是 official documentation
中描述的函数 train 的签名virtual bool cv::ml::StatModel::train ( InputArray samples,
int layout,
InputArray responses
)
如您所见,该方法是虚拟的,这意味着您不能以这种方式调用它!。此功能应由 StatModel 的子 classes 实现。因此,当您想要使用该方法时,您可以从实现该方法的子 class 中调用该方法。 class KNearest 实现了这一点。您的代码应更改为:
Ptr<ml::KNearest> knn = ml::KNearest::create();
knn->train(trainData, ml::ROW_SAMPLE , trainClasses);
现在回答你的第二个问题:
您可以将数据准备为 ROW_SAMPLE 或 COL_SAMPLE。 在 ROW_SAMPLE 中,每个样本都在一行中。因此,如果您的样本由三个浮点数组成并且您有 10 个样本,那么您最终应该得到一个具有 10 行和 3 列的 Mat 对象。 在COL_SAMPLE中,一切都颠倒了。所以你最终得到 3 行和 10 列。