我在using OpenCV and SVM with images找到了与此主题相关的优秀/全面的帖子/答案。但是,我想从链接中的答案中澄清一些问题。 (因为我没有足够的声誉来撰写评论)。
我一直在做什么: 我正在使用OpenCV SVM进行培训。用于训练矩阵的特征是通过计算每个图像的归一化平均R,G和B值来获得的。因此,在训练矩阵中,每行(或每个图像)中有4列。这些列对应于r信道****中的 标签(1或0), ****规范化均值, g 和 b 频道。
顺便说一句,我的原始训练文件是一个文本文件,我仍然会将其转换为float [] [],并且甚至可以转换为Mat对象以提供给opencv的SVM。这是文件的样子:
1 0.267053 0.321014 0.411933
1 0.262904 0.314294 0.422802
。
。
0 0.29101 0.337208 0.371782
0 0.261792 0.314494 0.423714
显然,这与链接中的声明相矛盾,该声明指出每行的大小必须等于图像的大小。这是一个协议还是某种规则?我无法理解为什么它应该(如果是的话)。
我的问题是,在构建训练矩阵时,每行的长度是否必须与图像的区域或大小相对应?在我所做的训练矩阵中,每行的长度只有4.这是错的吗?
此外,是否只有3个功能(3列)用于足够的分类/ SVM训练?请引导我走上正确的道路,我怀疑我是否应继续这样做,或者是否还有其他更好的解决方法。
我希望我能够理解SVM步骤背后的更多概念。文章或相关样品将不胜感激!
答案 0 :(得分:2)
每行的大小不必等于图像大小。这取决于你的功能。使用平均值进行图像分类是不够的。只要想想你在看图片时如何对物体进行分类。您不能计算平均值,但您可能会查看轮廓,连接区域,有时是大脑处理背景中的单个像素值。
为了获得更多功能,我有一个建议。计算每个列的特征提取部分的平均值。这可能会更有用。
对于另一个功能提取,您可以使用PCA。通常你可以连续给出所有像素值来训练SVM,但即使对于200 * 200图像,这也会产生40.000个特征,WOW,这是如此之多。您需要减少此要素维度而不会丢失太多信息,这意味着保留可接受的差异百分比。因此PCA用于此目的,减少了特征空间维度并以可接受的速率保持方差。
我将尝试向您展示如何使用PCA减少功能空间。首先,您需要获取图像,而不是逐行将图像滚动到Mat变量:
阅读csv :
void read_csv(const string& filename, vector& images, vector& labels, char separator = ';') { std::ifstream file(filename.c_str(), ifstream::in); if (!file) { string error_message = "No valid input file was given, please check the given filename."; CV_Error(1, error_message); } string line, path, classlabel; while (getline(file, line)) { stringstream liness(line); getline(liness, path, separator); getline(liness, classlabel); if(!path.empty() && !classlabel.empty()) { Mat im = imread(path, 0); images.push_back(im); labels.push_back(atoi(classlabel.c_str())); } } }
逐行滚动图片:
Mat rollVectortoMat(const vector<Mat> &data) // data is vector of Mat images
{
Mat dst(static_cast<int>(data.size()), data[0].rows*data[0].cols, CV_32FC1);
for(unsigned int i = 0; i < data.size(); i++)
{
Mat image_row = data[i].clone().reshape(1,1);
Mat row_i = dst.row(i);
image_row.convertTo(row_i,CV_32FC1, 1/255.);
}
return dst;
}
主要强>
int main()
{
PCA pca;
vector<Mat> images_train;
vector<Mat> images_test;
vector<int> labels_train;
vector<int> labels_test;
read_csv("train1k.txt",images_train,labels_train);
read_csv("test1k.txt",images_test,labels_test);
Mat rawTrainData = rollVectortoMat(images_train);
Mat rawTestData = rollVectortoMat(images_test);
Mat trainLabels = getLabels(labels_train);
Mat testLabels = getLabels(labels_test);
int pca_size = 500;
Mat trainData(rawTrainData.rows, pca_size,rawTrainData.type());
Mat testData(rawTestData.rows,pca_size,rawTestData.type());
pca(rawTrainData,Mat(),CV_PCA_DATA_AS_ROW,pca_size);
for(int i = 0; i < rawTrainData.rows ; i++)
pca.project(rawTrainData.row(i),trainData.row(i));
for(int i = 0; i < rawTestData.rows ; i++)
pca.project(rawTestData.row(i),testData.row(i));
}
总结一下,你读了一个像image_path; label的csv文件。比你逐行将图像滚动到Mat变量。您应用pca减少到500个功能。我应用这些PCA重新扫描将200 * 200图像(40000个特征)减少到500个特征尺寸。比我应用MLP来分类这个。此testData和trainData变量也可以与SVM一起使用。您还可以在我的帖子中查看如何使用MLP训练它:
答案 1 :(得分:1)
如果图像的每个像素都是您想要训练SVM的特征,则每行应列出所有特征,因此列出所有像素。在您的情况下,似乎每个图像只有3个特征(平均R,G,B),所以不应该有任何问题。
当然,您可以很好地训练具有3维的SVM。但忽略SVM,平均颜色甚至是图像的合理指标吗?