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; } } }