Emgu CV SVM 示例不适用于版本 3.0.0
Emgu CV SVM example not working on version 3.0.0
我正在尝试实现找到的 SVM 示例代码
Here。它是 Emgu CV 文档中提供的官方示例,但它适用于 1.5 版(至少)。
除非我弄错了,否则此示例中的许多 classes 在版本 3.0.0 中的工作方式有所不同,或者根本不存在并已被替换。
一个示例是 SVMParams
class,如图所示 Here 已不存在。
此外,开发了 TrainData
class,它是 SVM 对象的 TrainAuto
方法的新输入,取代了 Matrix<single>
class。
在更改了我认为需要更改的内容后,我尝试实现该示例,但代码到达 bool trained = model.TrainAuto(td, 5);
行和 returns 除以零异常。
也许这一行之后还有更多问题,但这是我的代码编译的范围。
这是我要执行的操作:
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)
我不知道为什么会出现异常,因为用于该方法的数据是按照示例创建的。
任何帮助将不胜感激。
和你有同样的问题,但似乎 trainClasses
现在是整数矩阵而不是浮点数矩阵了。
我尝试了这个,它在 Vb.net:
中对我起作用
Dim trainClasses As Matrix(Of Single) => Dim trainClasses As Matrix(Of Integer)
Tt 将在 C# 中:
Matrix<float> trainClasses => Matrix<Int> trainClasses
希望对你有用。
纪尧姆
需要解决三个问题:
System.DivideByZeroException
通过对 trainClasses
、trainClasses1
、trainClasses2
和 [=15= 使用不正确的类型抛出(如@user3082029 所解释) ].类型应该是 Matrix<int>
而不是 Matrix<float>
自引入 optimize_linear_svm() function in OpenCV Emgu.CV.ML.SVM.SvmKernelType.Linear
wouldn't produce expected support vectors known from example. In this situation you can modify 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);
}
要准确绘制支持向量,必须使用POLY类型的内核
model.SetKernel(SVM.SvmKernelType.Poly);
model.Degree = 1.0
Emgu.CV4.5.1 的情况也一样。 (我用过。)
bool _successful = _svm.TrainAuto(_traindatastructure, crossValidationParam);
returns错误,
************* Exception Text **************
System.DivideByZeroException: Attempted to divide by zero.
at Emgu.CV.ML.MlInvoke.cveSVMTrainAuto(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)
当参数类型不匹配时,
TrainData _traindatastructure = new TrainData(_samples, Emgu.CV.ML.MlEnum.DataLayoutType.RowSample, _responese);
要解决错误,只需按照 Emgu CV 文档 here 中指定的方式转换输入参数的类型即可。类型转换如下。
Mat _samples = new Mat();
_traindata.ConvertTo(_samples, DepthType.Cv32F); // Matrix of samples. It should have CV_32F type.
Mat _responese = new Mat();
_trainclasses.ConvertTo(_responese, DepthType.Cv32S); // The matrix should have type CV_32F or CV_32S (in the former case the responses are considered as ordered by default; in the latter case - as categorical)
我正在尝试实现找到的 SVM 示例代码
Here。它是 Emgu CV 文档中提供的官方示例,但它适用于 1.5 版(至少)。
除非我弄错了,否则此示例中的许多 classes 在版本 3.0.0 中的工作方式有所不同,或者根本不存在并已被替换。
一个示例是 SVMParams
class,如图所示 Here 已不存在。
此外,开发了 TrainData
class,它是 SVM 对象的 TrainAuto
方法的新输入,取代了 Matrix<single>
class。
在更改了我认为需要更改的内容后,我尝试实现该示例,但代码到达 bool trained = model.TrainAuto(td, 5);
行和 returns 除以零异常。
也许这一行之后还有更多问题,但这是我的代码编译的范围。 这是我要执行的操作:
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)
我不知道为什么会出现异常,因为用于该方法的数据是按照示例创建的。
任何帮助将不胜感激。
和你有同样的问题,但似乎 trainClasses
现在是整数矩阵而不是浮点数矩阵了。
我尝试了这个,它在 Vb.net:
Dim trainClasses As Matrix(Of Single) => Dim trainClasses As Matrix(Of Integer)
Tt 将在 C# 中:
Matrix<float> trainClasses => Matrix<Int> trainClasses
希望对你有用。 纪尧姆
需要解决三个问题:
System.DivideByZeroException
通过对trainClasses
、trainClasses1
、trainClasses2
和 [=15= 使用不正确的类型抛出(如@user3082029 所解释) ].类型应该是Matrix<int>
而不是Matrix<float>
自引入 optimize_linear_svm() function in OpenCV
Emgu.CV.ML.SVM.SvmKernelType.Linear
wouldn't produce expected support vectors known from example. In this situation you can modify 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); }
要准确绘制支持向量,必须使用POLY类型的内核
model.SetKernel(SVM.SvmKernelType.Poly);
model.Degree = 1.0
Emgu.CV4.5.1 的情况也一样。 (我用过。)
bool _successful = _svm.TrainAuto(_traindatastructure, crossValidationParam);
returns错误,
************* Exception Text **************
System.DivideByZeroException: Attempted to divide by zero.
at Emgu.CV.ML.MlInvoke.cveSVMTrainAuto(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)
当参数类型不匹配时,
TrainData _traindatastructure = new TrainData(_samples, Emgu.CV.ML.MlEnum.DataLayoutType.RowSample, _responese);
要解决错误,只需按照 Emgu CV 文档 here 中指定的方式转换输入参数的类型即可。类型转换如下。
Mat _samples = new Mat();
_traindata.ConvertTo(_samples, DepthType.Cv32F); // Matrix of samples. It should have CV_32F type.
Mat _responese = new Mat();
_trainclasses.ConvertTo(_responese, DepthType.Cv32S); // The matrix should have type CV_32F or CV_32S (in the former case the responses are considered as ordered by default; in the latter case - as categorical)