0

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

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

顺便说一句,我的原始训练文件是一个文本文件,我仍会将其转换为 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 步骤背后的概念。文章或相关样品将不胜感激!

4

2 回答 2

2

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

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

对于另一个特征提取,您可以使用 PCA。通常,您可以连续提供所有像素值来训练 SVM,但即使对于 200*200 的图像,这也会产生 40.000 个特征,哇,这么多。您需要在不丢失太多信息的情况下减少此特征维度,这意味着保留可接受的方差百分比。所以 PCA 用于此,减少特征空间维度并以可接受的速率保持方差。

我将尝试向您展示如何使用 PCA 减少特征空间。首先,您需要获取图像,而不是将图像逐行滚动到 Mat 变量:

读取 csv

void read_csv(const string& filename, vector& images, vector& labels, char separator = ';')
{
    std::ifstream 文件(filename.c_str(), ifstream::in);
    如果(!文件)
    {
        string error_message = "没有给出有效的输入文件,请检查给定的文件名。";
        CV_Error(1, error_message);
    }
    字符串行、路径、类标签;
    而(getline(文件,行))
    {
        串流线(线);

        getline(线条,路径,分隔符);
        getline(线条,类标签);

        if(!path.empty() && !classlabel.empty())
        {
            Mat im = imread(path, 0);

            images.push_back(im);
            标签.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 一起使用。您还可以在我的 SO 帖子中查看如何使用 MLP 对其进行训练:

OpenCV 神经网络 Sigmoid 输出

于 2014-03-07T09:13:08.433 回答
1

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

当然,你可以很好地训练一个 3 维的 SVM。但是忽略 SVM,平均颜色是否甚至是您图像的明智指标?

于 2014-03-07T07:57:36.443 回答