我正在尝试实现找到的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)
我不知道为什么会发生异常,因为根据示例创建了用于该方法的数据。
非常感谢任何帮助。
答案 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.DivideByZeroException
,trainClasses
,trainClasses1
和trainClasses2
的错误类型,抛出 trainClasses3
(如@ user3082029所述)。类型应为Matrix<int>
,而不是Matrix<float>
由于在OpenCV Emgu.CV.ML.SVM.SvmKernelType.Linear
中引入optimize_linear_svm()函数不会产生example中已知的预期支持向量。在这种情况下,您可以修改opencv_ml模块并替换项目中的opencv_ml300.dll
。或者您可以使用Emgu.CV.ML.SVM.SvmKernelType.Inter
要绘制支持向量,您可以使用
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