我的SURF / K Means分类器出了什么问题

时间:2014-03-31 17:11:48

标签: c# opencv emgucv bayesian-networks

我正在尝试使用SURF和Naive Bayesian创建分类器/预测器。我几乎遵循Dance,Csurka的“视觉分类与袋子的关键点”的技术......我使用的是SURF而不是SIFT。

我的结果非常可怕,我不确定我的错误在哪里。我正在使用来自CalTec套装的20个汽车样品(火腿)和20个摩托车样品(垃圾邮件)。我怀疑这是我创造词汇的方式。我可以看到,给定相同的SURF描述符输入,EMGU / OpenCV kmeans2分类器返回不同的结果。这让我很怀疑。到目前为止,这是我的代码。

public Matrix<float> Extract<TColor, TDepth>(Image<TColor, TDepth> image)
        where TColor : struct, Emgu.CV.IColor
        where TDepth : new()
    {            
        ImageFeature[] modelDescriptors;

        using (var imgGray = image.Convert<Gray, byte>())
        {
            var modelKeyPoints = surfCPU.DetectKeyPoints(imgGray, null);
            //the surf descriptor is a size 64 vector describing the intensity pattern surrounding
            //the corresponding modelKeyPoint
            modelDescriptors = surfCPU.ComputeDescriptors(imgGray, null, modelKeyPoints);
        }

        var samples = new Matrix<float>(modelDescriptors.Length, DESCRIPTOR_COUNT);//SURF Descriptors have 64 samples
        for (int k = 0; k < modelDescriptors.Length; k++)
        {
            for (int i = 0; i < modelDescriptors[k].Descriptor.Length; i++)
            {
                samples.Data[k, i] = modelDescriptors[k].Descriptor[i];
            }

        }

        //group descriptors into clusters using K-means to form the feature vectors
        //create "vocabulary" based on square-error partitioning K-means
        var centers = new Matrix<float>(CLUSTER_COUNT, samples.Cols, 1);
        var term = new MCvTermCriteria();
        var labelVector = new Matrix<int>(modelDescriptors.Length, 1);
        var cluster = CvInvoke.cvKMeans2(samples, CLUSTER_COUNT, labelVector, term, 3, IntPtr.Zero, 0, centers, IntPtr.Zero);

        //this is the quantized feature vector as described in Dance, Csurska Bag of Keypoints (2004)
        var keyPoints = new Matrix<float>(1, CLUSTER_COUNT);

        //quantize the vector into a feature vector
        //making a histogram of the result counts
        for (int i = 0; i < labelVector.Rows; i++)
        {
            var value = labelVector.Data[i, 0];
            keyPoints.Data[0, value]++;
        }
        //normalize the histogram since it will have different amounts of points
        keyPoints = keyPoints / keyPoints.Norm;
        return keyPoints;
    }

输出被送入NormalBayesClassifier。这就是我培训的方式。

Parallel.For(0, hamCount, i =>
            {
                using (var img = new Image<Gray, byte>(_hams[i].FullName))
                {
                    var features = _extractor.Extract(img);
                    features.CopyTo(trainingData.GetRow(i));
                    trainingClass.Data[i, 0] = 1;
                }
            });

        Parallel.For(0, spamCount, j =>
        {
            using (var img = new Image<Gray, byte>(_spams[j].FullName))
            {
                var features = img.ClassifyFeatures(_extractor);
                features.CopyTo(trainingData.GetRow(j));
                trainingClass.Data[j + hamCount, 0] = 0;
            }
        });

        using (var classifier = new NormalBayesClassifier())
        {
            if (classifier.Train(trainingData, trainingClass, null, null, false))
            {

                classifier.Save(_statModelFilePath);
            }
        }

当我使用NormalBayesClassifier调用Predict时,它会为所有训练样本返回1(匹配)... ham和spam。

非常感谢任何帮助。

编辑。 另一个注意事项是我选择了5到500的CLUSTER_COUNT,结果相同。

1 个答案:

答案 0 :(得分:0)

问题更具概念性而非技术性。我不明白K Means集群正在构建“整个”数据集的词汇表。正确执行此操作的方法是为CvInvoke.cvKMeans2调用一个包含每个图像的所有功能的训练矩阵。我每次都是根据单个图像构建词汇。

我的最终解决方案是将SURF代码拉入自己的方法并在每个火腿和垃圾邮件图像上运行。然后我使用大量的结果集来构建训练矩阵并将其提供给CvInvoke.cvKMeans2方法。完成培训花了很长时间。我总共有大约3000张图片。

我的结果更好。使用训练数据预测率100%准确。我现在的问题是我可能会因为非训练数据的预测率仍然很差而过度拟合。我将使用SURF算法中的粗糙度阈值以及簇计数来查看是否可以最小化过拟合。