c++ - SVM 训练矩阵每行的长度

标签 c++ opencv matrix svm training-data

我在这里找到了与此主题相关的优秀/全面的帖子/答案 using OpenCV and SVM with images .但是,我有一些问题想从链接中的答案中澄清。 (因为我没有足够的声誉来写评论)。

我一直在做什么: 我正在使用 OpenCV SVM 进行训练。用于训练矩阵的特征是通过计算每个图像的归一化平均 R、G 和 B 值获得的。因此,在训练矩阵中,每行(或每个图像)有 4 列。这些列对应于标签(1 或 0), ****r channel 中的归一化均值****,gb channel 。

顺便说一句,我原来的训练文件是一个文本文件,我仍然会将其转换为 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

显然,这与链接中声明每行的大小必须等于图像的大小的声明相矛盾>。它是协议(protocol)还是某种规则?我只是无法理解为什么它应该(如果是的话)。

我的问题是,在构建训练矩阵时,每一行的长度是否必须对应于图像的面积或大小?在我制作的训练矩阵中,每行的长度只有 4。这是错误的吗?

此外,是否只有 3 个特征(3 列)用于训练足以进行分类/SVM?请引导我走上正确的道路,我怀疑我是否应该继续这样做,或者是否有其他更好的方法来解决这个问题。

我希望我能了解更多支持 vector 机步骤背后的概念。文章或相关示例将不胜感激!

最佳答案

每行的大小不必等于图像大小。这取决于你有什么功能。使用平均值进行图像分类是不够的。想想看图片时如何对对象进行分类。您不计算平均值,但您可能会查看轮廓、连接区域,有时还会查看大脑处理背景中的单个像素值。

所以为了获得更多的功能,我有一个建议给你。计算特征提取部分每列的平均值。这可能会更有用。

对于另一个特征提取,您可以使用 PCA。通常,您可以连续给出所有像素值来训练 SVM,但即使对于 200*200 的图像,这也会产生 40.000 个特征,哇,太多了。您需要在不丢失太多信息的情况下减少此特征维度,这意味着要保留可接受的方差百分比。因此,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()));
        }
    }
}

Rolling images row by row :

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 redcution 将 200*200 个图像(40000 个特征)减少到 500 个特征大小。比我应用 MLP 对此进行分类。这个 testData 和 trainData 变量也可以与 SVM 一起使用。您还可以在我的 SO 帖子中查看如何使用 MLP 对其进行训练:

OpenCV Neural Network Sigmoid Output

关于c++ - SVM 训练矩阵每行的长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22243809/

相关文章:

c++ - 使用 dcmtk 将 bmp 文件另存为 dicom

c - 我们如何检测具有相同背景的图像的边缘?

c++ - 为模板类声明模板方法

c++ - Flex -- C++ 连接?

c++ - 为什么我的代码抛出 "does not name a type error"?

c++ - 每种类型都有相应的文字吗?

python - 我无法让 OpenCV 中的 CV2.waitKey 正常工作。运行 waitKey 后代码没有响应

c++ - OpenCV 随机决策森林 : How to get posterior probability

R:成对矩阵的矢量化循环

python - R 相当于 Python 的 3D 数组的 np.dot