using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.ML;
using Emgu.CV.Structure;
namespace RichCreator.Editor.Utils
{
public class HOGTrain
{
public HOGTrain(System.Drawing.Size winSize,
System.Drawing.Size blockSize,
System.Drawing.Size strideSize,
System.Drawing.Size cellSize,
Int32 channel)
{
this.WinSize = winSize;
this.BlockSize = blockSize;
this.StrideSize = strideSize;
this.CellSize = cellSize;
this.Channel = channel;
Initizlize();
}
public System.Drawing.Size WinSize { get; set; }
public System.Drawing.Size BlockSize { get; set; }
public System.Drawing.Size StrideSize { get; set; }
public System.Drawing.Size CellSize { get; set; }
public Int32 Channel { get; set; }
///
/// 训练数据
///
private List FeatureDatas = new List();
///
/// 维数
///
public Int32 Dimensional { get; set; }
private HOGDescriptor hog;
private void Initizlize()
{
//计算Dimensional
/// a = (winsize宽-block宽) / stride宽 +1 23
/// b = (winsize高-block高) / stride高 +1 14
/// c = block宽 / cell宽 2
/// d = block高 / block高 2
/// 纬度 = a* b*c* d*channel数,本示例中:23*14*2*2*9=11592
Int32 a = (this.WinSize.Width - this.BlockSize.Width) / this.StrideSize.Width + 1;
Int32 b = (this.WinSize.Height - this.BlockSize.Height) / this.StrideSize.Height + 1;
Int32 c = this.BlockSize.Width / this.CellSize.Width;
Int32 d = this.BlockSize.Height / this.CellSize.Height;
this.Dimensional = a * b * c * d * Channel;
//第一个参数:winsize:窗口大小,我取样本大小;
//第二个参数:block,我的是12 * 12;当然,也可以设置为18 * 18或者6 * 6,切记:BLOCK大小不能是技术值,至于为什么,看一下cell和block的关系即可。同时:设计的过程中,BLOCK要可被winsize整除。网上的资料都是16 * 16,也没有说清楚为什么,其实这个看懂了HOG后可以自行设置
//第三个参数:stride,我的设置是6 * 6,当然也可以设置为12 * 12或者4 * 4,不同的设置,将得到不同的纬度数量;
//第四个参数:cell,4个cell构成1个block,这也就是block一定要是偶数的原因。
//第五个参数:需要得到几个channel的值,默认是9个,具体原因请参见HOG原论文
hog = new HOGDescriptor(this.WinSize, this.BlockSize, this.StrideSize, this.CellSize, this.Channel);
}
///
/// 训练
///
/// 样本图片列表
/// 样本类型,1正向样本,-1负向样本
public void Train(string[] files, Int32 featureClasses)
{
Mat tempMat = null;
Image im = null;
for (int f = 0; f < files.Length; f++)
{
tempMat = CvInvoke.Imread(files[f]);
im = tempMat.ToImage();
float[] fArr = hog.Compute(im);
this.FeatureDatas.Add(new HogFeatureDataContainer(fArr, featureClasses));
}
}
///
///
///
///
public void Save(string saveToXmlPath)
{
Matrix hogFeatureData = new Matrix(this.FeatureDatas.Count, this.Dimensional);//样本数,HOG纬度
Matrix featureClasses = new Matrix(this.FeatureDatas.Count, 1);//样本数
HogFeatureDataContainer container;
for (int i = 0; i < this.FeatureDatas.Count; i++)
{
container = this.FeatureDatas[i];
for (int t = 0; t < container.FeatureDatas.Length; t++)
{
hogFeatureData[i, t] = container.FeatureDatas[t];
}
featureClasses.Data[i, 0] = container.FeatureClass;
}
//训练并保存训练结果
SVM svm = new SVM();
svm.Type = SVM.SvmType.CSvc;
svm.SetKernel(SVM.SvmKernelType.Linear);//线性
svm.C = 1;
svm.TermCriteria = new MCvTermCriteria(1000, 0.001);//1000次或者收敛达到0.001就跳出
svm.Train(hogFeatureData, Emgu.CV.ML.MlEnum.DataLayoutType.RowSample, featureClasses);
svm.Save(saveToXmlPath);
}
///
/// 训练数据包装器
///
private struct HogFeatureDataContainer
{
public HogFeatureDataContainer(float[] featureDatas, Int32 featureClass)
{
this.FeatureDatas = featureDatas;
this.FeatureClass = featureClass;
}
public float[] FeatureDatas;
public Int32 FeatureClass;
}
}
}