SVM每行训练矩阵的长度

时间:2014-03-07 07:11:02

标签: c++ opencv matrix svm training-data

我在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步骤背后的更多概念。文章或相关样品将不胜感激!

2 个答案:

答案 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训练它:

OpenCV Neural Network Sigmoid Output

答案 1 :(得分:1)

如果图像的每个像素都是您想要训练SVM的特征,则每行应列出所有特征,因此列出所有像素。在您的情况下,似乎每个图像只有3个特征(平均R,G,B),所以不应该有任何问题。

当然,您可以很好地训练具有3维的SVM。但忽略SVM,平均颜色甚至是图像的合理指标吗?