HOG+SVM的EMGU2.4版本转换EMGU3.0

目标:

      把hog+svm的程序中用的emgu2.4版本改写成3.0版本

本文内容:

       写出emgu2.4和3.0版本在hog和svm上改了哪些,和对应功能的替换方法
       
       网上好像对于两个版本的参考资料很少,而且都很分散;刚好因为项目要求,就借着这次机会整理一下
       
       2.4版本到3.0版本更新了好多东西,其实改版本远不如重新写一个3.0来的省力。。。。

流程

根据hog+svm的整体思路,我们的改动是按照写的顺序一步步来:

1、根据训练样本,设计HOG描述子;

2、获取正负样本HOG值;

3、训练SVM;(改动)

4、从训练好的SVM提取出hog描述值(改动)

5、检测(改动)

详细描述

设计HOG描述子

在设计hog描述子只这一块,函数并没有因为版本而发生变化;
2.4与3.0:

            public HOGDescriptor hog;
            hog = new HOGDescriptor(new Size(100, 50), new Size(10, 5), new Size(5, 5), new Size(5, 5), 9, 1, -1, 0.2, true);
           //检测窗口(100,50),块尺寸(10,10),块步长(5,5),cell尺寸(5,5),直方图bin个数9  

有些在设计HOG的时候并没有写后面这一部分(1,-1,0.2,true);这部分可写可不写,不写就直接采取默认值,关系不大。

参数1. 检测窗口,最好与正负样本取的像素大小一致
参数2.块尺寸
参数3.块步长
参数4.细胞尺寸
参数5.直方图bin个数,一般默认都是9

获取正负样本HOG值

用NegSamNO代表负样本数,PosSamNO代表正样本数;(可以直接输入,也可以用循环得到)
以下是获取正样本的代码

    class Train
    {
        public HOGDescriptor hog;
        public int descriptorDim;                             //HOG描述子的维数,由图片大小、检测窗口大小、块大小、细胞单元中直方图bin个数决定 
        bool isInitial = true;
        public Matrix<float> sampleFeatureMat;   //所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于HOG描述子维数 
        public Matrix<int> sampleLabelMat;          //训练样本的类别向量,行数等于所有样本的个数,列数等于1;1表示有人,-1表示无人 
         //分类的数字格式更改为int//在2.4版本中int和float均可
        public Train()
        {
            int NegSamNO = xx;
            int PosSamNO = xx;
            hog = new HOGDescriptor(new Size(100, 50), new Size(10, 5), new Size(5, 5), new Size(5, 5), 9, 1, -1, 0.2, true);
            for (int index = 0; index < PosSamNO; index++)                        //依次读取正样本图片,生成HOG描述子  
            {
                string Path = posImgPath + "(" + (index + 1) + ").bmp";
                float[] pos_descriptors;
                Image<Bgr, Byte> img = isGray ? new Image<Gray, byte>(Path).Convert<Bgr, Byte>() : new Image<Bgr, byte>(Path);
                pos_descriptors = hog.Compute(img, new Size(5, 5), Size.Empty, null);
              
                if (isInitial)
                {
                    descriptorDim = pos_descriptors.Length;                         //hog描述子的长度
                    //初始化所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于HOG描述子维数sampleFeatureMat  
                    sampleFeatureMat = new Matrix<float>(PosSamNO + NegSamNO, descriptorDim);
                    sampleFeatureMat.SetZero();
                    //初始化训练样本的类别向量,行数等于所有样本的个数,列数等于1;1表示有人,0表示无人  
                    sampleLabelMat = new Matrix<int>(PosSamNO + NegSamNO, 1);
                    sampleLabelMat.SetZero();

                    isInitial = false;
                }
                for (int i = 0; i < descriptorDim; i++)
                {
                    sampleFeatureMat[index, i] = pos_descriptors[i];//第index个样本的特征向量中的第i个元素  
                }
                sampleLabelMat[index, 0] = 1;
            }
``        
           //for(xxxx)//同理可以得到负样本
           //{
           //}
      }
}



以上代码来自 https://www.cnblogs.com/KC-Mei/p/4553024.html 博主

训练SVM(改动开始)

2.4version

            Train my_train = new Train();
            SVMParams p = new SVMParams();
            p.SVMType = Emgu.CV.ML.MlEnum.SVM_TYPE.C_SVC;
            p.KernelType = Emgu.CV.ML.MlEnum.SVM_KERNEL_TYPE.LINEAR;
            p.Degree = 0;
            p.Gamma = 1;
            p.Coef0 = 0;
            p.C = 0.01;
            p.Nu = 0;
            p.P = 0;
            p.TermCrit = new MCvTermCriteria(1000, 0.00001);
            bool trained = svm.Train(my_train.sampleFeatureMat, my_train.sampleLabelMat, null, null, p);

3.0version

            Train my_train = new Train();
            Emgu.CV.ML.SVM p;
            p = new Emgu.CV.ML.SVM();
            p.SetKernel(Emgu.CV.ML.SVM.SvmKernelType.Linear);
            p.Type = SVM.SvmType.CSvc;
            p.C = 0.01;
            p.TermCriteria = new MCvTermCriteria(1000, 0.001);         
            TrainData td = new TrainData(my_train.sampleFeatureMat, Emgu.CV.ML.MlEnum.DataLayoutType.RowSample, my_train.sampleLabelMat);
            //在3.0中trained设置的参数类型改变了,于是通过TrainData来设置trained
            bool trained = p.TrainAuto(td);                             

当在改写的时候报出“尝试除以零”的错误,把分类的数字格式改为int;

从训练好的SVM提取出hog描述值

2.4version
以下是获取特征向量的代码,在3.0版本中相关函数被重写

                GetData gd = new GetData();
                svm.Load(LOAD_PATH);
                int DescriptorDim = svm.GetVarCount();                       //特征向量的维数,即HOG描述子的维数  
                int supportVectorNum = svm.GetSupportVectorCount();          //支持向量的个数 
                Matrix<float> supportVectorMat = new Matrix<float>(supportVectorNum, DescriptorDim);//支持向量矩阵  
                supportVectorMat.SetZero();
                //将支持向量的数据复制到supportVectorMat矩阵中  
                for (int i = 0; i < supportVectorNum; i++)
                {
                    float[] pSVData = svm.GetSupportVector(i);//返回第i个支持向量的数据指针  
                    for (int j = 0; j < DescriptorDim; j++)
                    {
                        supportVectorMat[i, j] = pSVData[j];
                    }
                }

3.0version

 public void beginSVM()
        {
                svm =new Emgu.CV.ML.SVM();
                Emgu.CV.FileStorage fsr = new Emgu.CV.FileStorage(LOAD_PATH, Emgu.CV.FileStorage.Mode.Read);
                svm.Read(fsr.GetFirstTopLevelNode());
                //在emgu2中svm没有load
                XmlDocument xml = new XmlDocument();
                xml.Load(LOAD_PATH);
                GetData gd = new GetData();
                int DescriptorDim = svm.GetSupportVectors().Width;//特征向量的维数,即HOG描述子的维数 没有GetVarCount() 
                int supportVectorNum = svm.GetSupportVectors().Height;//支持向量的个数     没有GetSupportVectorCount()
                Matrix<float> alphaMat = new Matrix<float>(1, supportVectorNum);//alpha向量,长度等于支持向量个数  
                alphaMat.SetZero();
                Matrix<float> supportVectorMat = new Matrix<float>(supportVectorNum, DescriptorDim);//支持向量矩阵  
                supportVectorMat.SetZero();
                Matrix<float> resultMat = new Matrix<float>(1, DescriptorDim);//alpha向量乘以支持向量矩阵的结果  
                resultMat.SetZero();
                Emgu.CV.Mat supporVectorMat1;
                supporVectorMat1 = svm.GetSupportVectors();
                supporVectorMat1.CopyTo(supportVectorMat);           //格式转化
              
                for (int i = 0; i < supportVectorNum; i++)
                {
                    alphaMat[0, i] = (float)gd.alpha[i];
                }
                //计算-(alphaMat * supportVectorMat),结果放到resultMat中  
                resultMat = -1 * alphaMat * supportVectorMat;
                //得到最终的setSVMDetector(const vector<float>& detector)参数中可用的检测子  
                float[] myDetector = new float[DescriptorDim + 1];
                //将resultMat中的数据复制到数组myDetector中  
                for (int i = 0; i < DescriptorDim; i++)
                {
                    //myDetector.push_back(resultMat.at<float>(0, i));
                    myDetector[i] = resultMat.Data[0, i];
                }
                //最后添加偏移量rho,得到检测子  
                myDetector[myDetector.Length - 1] = (float)gd.rho;
                //检测窗口(100,50),块尺寸(10,10),块步长(5,5),cell尺寸(5,5),直方图bin个数9  
                Hog_Descriptor = new Emgu.CV.HOGDescriptor(new System.Drawing.Size(100, 50), new System.Drawing.Size(10, 5), new System.Drawing.Size(5, 5), new System.Drawing.Size(5, 5), 9, 1, -1, 0.2, false);
                Hog_Descriptor.SetSVMDetector(myDetector);
        }

在3.0版本中我们可以用GetSupportVectors()直接读取支持向量;但是两者的格式需要转化,GetSupportVectors()得到的是Mat,我们需要的是Matrix;所以最后加了一个转化的函数

许多的hog+svm的教程都提到了hog纬度的计算,我们可以用以下代码来代替

int DescriptorDim = svm.GetSupportVectors().Width
int supportVectorNum = svm.GetSupportVectors().Height

对于alpha向量和resultMat = -1 * alphaMat * supportVectorMat 的提取在两个版本中可以通用
相关代码可以参考 关于SVM中的alpha、rho向量 这个博主的文章

检测

2.4 version

            beginSVM();
            regions = Hog_Descriptor.DetectMultiScale(img, 0, new Size(2, 2), Size.Empty,0.8,1,false);
            Image<Bgr,Byte> copy = img.Copy();
            int num_target = 0;
            foreach (Rectangle pedestrain in regions)
            {
                img.Draw(pedestrain, new Bgr(Color.Red), 5);
                //保存出识别结果
                copy.ROI = pedestrain;
                Image<Bgr, Byte> copy2 = copy.Copy();
                copy2.Resize(100, 50, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR).Save(@"D:\studyOFpostgraduate\信号灯识别\信号灯识别(HOG+SVM)\HOG_SVM\Results\" + num_target.ToString() + ".bmp");
                num_target++;
            }

3.0 version

            beginSVM();
            using (Emgu.CV.HOGDescriptor hog = new Emgu.CV.HOGDescriptor(new System.Drawing.Size(100, 50), new System.Drawing.Size(10, 5), new System.Drawing.Size(5, 5), new System.Drawing.Size(5, 5), 9))
            {
                MCvObjectDetection[] results = Hog_Descriptor.DetectMultiScale(img);
                regions = new Rectangle[results.Length];                //格式转变
                for (int i = 0; i < results.Length; i++)     
                {
                    regions[i] = results[i].Rect;
                }
                Image<Bgr, Byte> copy = img.Copy();
                int num_target = 0;

                foreach (Rectangle pedestrain in regions)
                {
                    img.Draw(pedestrain, new Bgr(Color.Red), 5);
                    //删去保存结果的功能,Emgu.CV.CvEnum中找不到INTER类
                    num_target++;
                }
            }

问题
1.Hog_Descriptor.DetectMultiScale的参数设置问题(HOG detectMultiScale 参数分析
2.regions的格式转化问题:将MCvObjectDetection[]的格式转变为 Rectangle[]

相关文章

本文很多代码都取自 https://www.cnblogs.com/KC-Mei/p/4553024.html 的博客作者

在EMGU3.1版本下的hog+svm的使用: https://blog.csdn.net/u011616825/article/details/72794527

HOG detectMultiScale 参数分析: https://www.cnblogs.com/klitech/p/5747895.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值