Emgu CV SVM示例不适用于3.0.0版

时间:2015-08-19 15:21:25

标签: c# svm emgucv

我正在尝试实现找到的SVM示例代码 Here。它是Emgu CV文档中提供的官方示例,但它适用于1.5版(至少)。 除非我非常错误,否则本示例中的许多类在3.0.0版中的工作方式不同,或者根本不存在并且已被替换。
一个例子是SVMParams类,如图所示Here不再存在 此外,已经开发了TrainData类,它是SVM对象的TrainAuto方法的新输入,已替换Matrix<single>类。 我已经尝试在更改我认为需要更改的内容后实现该示例,但代码到达bool trained = model.TrainAuto(td, 5);行并返回除以零的异常。

也许在这一行之后还有更多的问题,但这就是我的代码编译。 以下是我要执行的内容:

private void Classify()
    {
        int trainingSampleCount = 150;
        int sigma = 60;

        #region Generate the training data and classes

        Matrix<float> trainData = new Matrix<float>(trainingSampleCount, 2);
        Matrix<float> trainClasses = new Matrix<float>(trainingSampleCount, 1);

        Image<Bgr, Byte> img = new Image<Bgr, Byte>(500, 500);

        Matrix<float> sample = new Matrix<float>(1, 2);

        Matrix<float> trainData1 = trainData.GetRows(0, trainingSampleCount / 3, 1);
        trainData1.GetCols(0, 1).SetRandNormal(new MCvScalar(100), new MCvScalar(sigma));
        trainData1.GetCols(1, 2).SetRandNormal(new MCvScalar(300), new MCvScalar(sigma));


        Matrix<float> trainData2 = trainData.GetRows(trainingSampleCount / 3, 2 * trainingSampleCount / 3, 1);
        trainData2.SetRandNormal(new MCvScalar(400), new MCvScalar(sigma));

        Matrix<float> trainData3 = trainData.GetRows(2 * trainingSampleCount / 3, trainingSampleCount, 1);
        trainData3.GetCols(0, 1).SetRandNormal(new MCvScalar(300), new MCvScalar(sigma));
        trainData3.GetCols(1, 2).SetRandNormal(new MCvScalar(100), new MCvScalar(sigma));

        Matrix<float> trainClasses1 = trainClasses.GetRows(0, trainingSampleCount / 3, 1);
        trainClasses1.SetValue(1);
        Matrix<float> trainClasses2 = trainClasses.GetRows(trainingSampleCount / 3, 2 * trainingSampleCount / 3, 1);
        trainClasses2.SetValue(2);
        Matrix<float> trainClasses3 = trainClasses.GetRows(2 * trainingSampleCount / 3, trainingSampleCount, 1);
        trainClasses3.SetValue(3);

        #endregion

        using (SVM model = new SVM())
        {
            //changed from example
            model.SetKernel(Emgu.CV.ML.SVM.SvmKernelType.Linear);
            model.Type = SVM.SvmType.CSvc;
            model.C = 1;
            model.TermCriteria = new MCvTermCriteria(100, 0.00001);

            TrainData td = new TrainData(trainData, Emgu.CV.ML.MlEnum.DataLayoutType.RowSample, trainClasses);
            bool trained = model.TrainAuto(td, 5);
            //changes up to this point

            for (int i = 0; i < img.Height; i++)
            {
                for (int j = 0; j < img.Width; j++)
                {
                    sample.Data[0, 0] = j;
                    sample.Data[0, 1] = i;

                    float response = model.Predict(sample);

                    img[i, j] =
                        response == 1 ? new Bgr(90, 0, 0) :
                        response == 2 ? new Bgr(0, 90, 0) :
                        new Bgr(0, 0, 90);
                }
            }
            // changed the GetSupportVectors()
            Mat supvec = model.GetSupportVectors();
            int c = supvec.Height;

            for (int i = 0; i < c; i++)
            {
                // The way the data is received changed as well 
                byte[] b = supvec.GetData(i);
                float[] v = new float[] { (float)b[0], (float)b[1] };

                PointF p1 = new PointF(v[0], v[1]);
                img.Draw(new CircleF(p1, 4), new Bgr(128, 128, 128), 2);
            }
        }

        //display the original training samples
        for (int i = 0; i < (trainingSampleCount / 3); i++)
        {
            PointF p1 = new PointF(trainData1[i, 0], trainData1[i, 1]);
            img.Draw(new CircleF(p1, 2.0f), new Bgr(255, 100, 100), -1);
            PointF p2 = new PointF(trainData2[i, 0], trainData2[i, 1]);
            img.Draw(new CircleF(p2, 2.0f), new Bgr(100, 255, 100), -1);
            PointF p3 = new PointF(trainData3[i, 0], trainData3[i, 1]);
            img.Draw(new CircleF(p3, 2.0f), new Bgr(100, 100, 255), -1);
        }

        Emgu.CV.UI.ImageViewer.Show(img);
    }

以下是描述异常

的堆栈跟踪的一部分
at Emgu.CV.ML.MlInvoke.CvSVMTrainAuto(IntPtr model, IntPtr trainData, Int32 kFold, MCvParamGrid& cGrid, MCvParamGrid& gammaGrid, MCvParamGrid& pGrid, MCvParamGrid& nuGrid, MCvParamGrid& coefGrid, MCvParamGrid& degreeGrid, Boolean balanced)
at Emgu.CV.ML.SVM.TrainAuto(TrainData trainData, Int32 kFold, MCvParamGrid cGrid, MCvParamGrid gammaGrid, MCvParamGrid pGrid, MCvParamGrid nuGrid, MCvParamGrid coefGrid, MCvParamGrid degreeGrid, Boolean balanced)
at Emgu.CV.ML.SVM.TrainAuto(TrainData trainData, Int32 kFold)

我不知道为什么会发生异常,因为根据示例创建了用于该方法的数据。

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:0)

和你一样有同样的问题,但似乎trainClasses现在是一个整数矩阵而不再是浮点矩阵。 我尝试这个,它在Vb.net中形成了我的作品:

Dim trainClasses As Matrix(Of Single) =>  Dim trainClasses As Matrix(Of Integer)

Tt将在C#中:

Matrix<float> trainClasses => Matrix<Int> trainClasses

希望它适合你。 纪尧姆

答案 1 :(得分:0)

要解决三个问题:

    通过使用System.DivideByZeroExceptiontrainClassestrainClasses1trainClasses2的错误类型,抛出
  1. trainClasses3(如@ user3082029所述)。类型应为Matrix<int>,而不是Matrix<float>

  2. 由于在OpenCV Emgu.CV.ML.SVM.SvmKernelType.Linear中引入optimize_linear_svm()函数不会产生example中已知的预期支持向量。在这种情况下,您可以修改opencv_ml模块并替换项目中的opencv_ml300.dll。或者您可以使用Emgu.CV.ML.SVM.SvmKernelType.Inter

  3. 要绘制支持向量,您可以使用

    var supportVectors = model.GetSupportVectors();
    var vectors = new Matrix<float>(supportVectors.Rows, supportVectors.Cols, supportVectors.DataPointer);
    
    for (var i = 0; i < supportVectors.Rows; i++)
    {
        var p1 = new PointF(vectors[i, 0], vectors[i, 1]);
        img.Draw(new CircleF(p1, 4), new Bgr(128, 128, 128), 2);
    }
    

答案 2 :(得分:0)

准确地绘制支持向量,必须使用POLY类型的内核

model.SetKernel(SVM.SvmKernelType.Poly);
model.Degree = 1.0