Example #1
0
        /// <summary>
        /// 构造函数,由Hog图生成块内归一化后的向量图
        /// </summary>
        /// <param name="hogGram">Hog图</param>
        /// <param name="blockWidth">块宽</param>
        /// <param name="blockHeight">块高</param>
        public NormBlockVectorGram(HogGram hogGram, int blockWidth, int blockHeight)
        {
            BlockSize.Width  = blockWidth;
            BlockSize.Height = blockHeight;

            int hogWidth  = hogGram.HogSize.Width;
            int hogHeight = hogGram.HogSize.Height;

            int hogPartNumber = hogGram.PartNumber;

            BlockGramWidth  = hogWidth - blockWidth + 1;
            BlockGramHeight = hogHeight - blockHeight + 1;

            NormBlockVectors = new ArrayList();

            if (hogGram != null && hogWidth >= blockWidth && hogHeight >= blockWidth)
            {
                HGram = hogGram;

                for (int row = 0; row < BlockGramHeight; row++)
                {
                    for (int col = 0; col < BlockGramWidth; col++)
                    {
                        double[] vec    = new double[blockWidth * blockHeight * hogPartNumber];
                        double   vecsum = 0;
                        for (int i = 0; i < blockHeight; i++)
                        {
                            for (int j = 0; j < blockWidth; j++)
                            {
                                for (int p = 0; p < hogPartNumber; p++)
                                {
                                    double r = hogGram.HogCells[(col + j) + (row + i) * hogWidth].HistElements[p].rho;

                                    // hogGram.HogCells的索引是从小到大。
                                    vec[p + j * hogPartNumber + i * hogPartNumber * blockWidth] = r;
                                    //vecsum += r * r;    // 这种归一化是将向量约束在“半径”为1的“球面”上,因为r>=0,实际上是分布在1/4个球面
                                    vecsum += r;         // 这种归一化是将向量约束在“边长为1的”立方体“内
                                }
                            }
                        }

                        // 归一化向量(非常重要)
                        for (int i = 0; i < vec.Length; i++)
                        {
                            if (vecsum != 0)
                            {
                                //vec[i] = vec[i] / Math.Sqrt(vecsum);  // 对应上述第一种归一化法
                                vec[i] = vec[i] / vecsum;
                            }
                            else
                            {
                                vec[i] = 0;
                            }
                        }

                        NormBlockVectors.Add(vec);
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        /// 绘制Hog示意图
        /// </summary>
        /// <param name="hogGram">Hog图数据</param>
        /// <param name="width">示意图宽</param>
        /// <param name="height">示意图高</param>
        public static Bitmap DrawHogGram(HogGram hogGram, int width, int height)
        {
            Bitmap   bmp         = new Bitmap(width, height, PixelFormat.Format24bppRgb);
            Graphics g           = Graphics.FromImage(bmp);
            int      grid_width  = width / hogGram.HogSize.Width;   // 格子宽
            int      grid_height = height / hogGram.HogSize.Height; // 格子高
            // 格子中心相对坐标
            PointF rel_center = new PointF((float)(grid_width / 2), (float)(grid_height / 2));
            float  radius     = Math.Min((float)(grid_width / 2), (float)(grid_height / 2));

            double maxval = 0;

            double[] transval = new double[hogGram.HogCells.Length * hogGram.PartNumber];
            for (int i = 0; i < hogGram.HogCells.Length; i++)
            {
                for (int j = 0; j < hogGram.PartNumber; j++)
                {
                    transval[j + i * hogGram.PartNumber] = hogGram.HogCells[i].HistElements[j].rho;
                    if (transval[j + i * hogGram.PartNumber] > maxval)
                    {
                        maxval = transval[j + i * hogGram.PartNumber];
                    }
                }
            }

            for (int i = 0; i < transval.Length; i++)
            {
                if (maxval != 0)
                {
                    transval[i] = 255 * Math.Sqrt(transval[i]) / Math.Sqrt(maxval);
                }
            }

            HogHistElement he;
            PointF         center;
            PointF         right;
            PointF         left;

            for (int row = 0; row < hogGram.HogSize.Height; row++)
            {
                for (int col = 0; col < hogGram.HogSize.Width; col++)
                {
                    for (int i = 0; i < hogGram.PartNumber; i++)
                    {
                        he     = hogGram.HogCells[col + row * hogGram.HogSize.Width].HistElements[i];
                        center = new PointF(col * grid_width + grid_width / 2, row * grid_height + grid_height / 2);
                        right  = new PointF((float)(center.X + radius * Math.Cos(he.theta)), (float)(center.Y + radius * Math.Sin(he.theta)));
                        left   = new PointF((float)(center.X - radius * Math.Cos(he.theta)), (float)(center.Y - radius * Math.Sin(he.theta)));
                        int idx = i + (col + row * hogGram.HogSize.Width) * hogGram.PartNumber;
                        // hog示意图体现在某个方向灰度的亮度上,而不是在该方向上线段的长短上
                        Pen p = new Pen(Color.FromArgb((int)transval[idx], (int)transval[idx], (int)transval[idx]));
                        g.DrawLine(p, right, left);
                    }
                }
            }
            //Pen p = new Pen(Color.Red);
            //g.DrawLine(p, new PointF(20.5f, 20.5f), new PointF(100.4f, 100.4f));
            return(bmp);
        }
Example #3
0
        /// <summary>
        /// 从位图(灰度图)中获取Hog图,位图像素是以从左到右、从下到上的顺序在内存中从低地址排列到高地址
        /// 但是C#的Bitmap对象好像把这顺序颠倒过来了,根据实际经验发现,在BitmapData中,位图数据以从左到
        /// 右、从上到下的顺序排列,和图像坐标的顺序一致
        /// </summary>
        /// <param name="bitmapSource">源位图</param>
        /// <param name="cellHeight">单元的高度</param>
        /// <param name="cellWidth">单元的宽度</param>
        /// <param name="partNumber">PI弧度等分数</param>
        /// <returns>Hog图</returns>
        public static HogGram GetHogFromBitmap(Bitmap bitmapSource, int cellWidth, int cellHeight, int partNumber)
        {
            HogGram hogGram = null;

            if (bitmapSource != null && bitmapSource.PixelFormat == PixelFormat.Format8bppIndexed)
            {
                int width  = bitmapSource.Width;
                int height = bitmapSource.Height;

                hogGram = new HogGram(width, height, cellWidth, cellHeight, partNumber);

                if (hogGram == null)
                {
                    return(hogGram);
                }

                Rectangle rect = new Rectangle(0, 0, width, height);

                // 获得位图内容数据
                BitmapData dataSource = bitmapSource.LockBits(rect, ImageLockMode.ReadOnly, bitmapSource.PixelFormat);

                // Stride为位图中每一行以4字节对齐的行宽
                int strideSource = dataSource.Stride;

                unsafe
                {
                    byte *ptrSource = (byte *)dataSource.Scan0.ToPointer();
                    byte *ptr1      = null;
                    for (int row = 0; row < height; row++)
                    {
                        ptr1 = ptrSource + strideSource * row;
                        for (int col = 0; col < width; col++)
                        {
                            GradientElement ge = new GradientElement();
                            if (row == 0 || row == height - 1 || col == 0 || col == width - 1)
                            {
                                ge.rho   = 0;
                                ge.theta = 0;
                            }
                            else
                            {
                                // 位图的在内存中的排列是从左到右,从下到上的,但BitmapData貌似做了优化,把位图数据在内存中的排列
                                // 顺序改为与坐标系一致,即从左到右、从上到下
                                double gradX = *(ptr1 + 1) - *(ptr1 - 1);
                                double gradY = *(ptr1 + strideSource) - *(ptr1 - strideSource);
                                ge.rho   = Math.Sqrt(gradX * gradX + gradY * gradY);
                                ge.theta = Math.Atan2(gradY, gradX);   // 注意坐标系是垂直翻转的
                            }

                            int bmpX = col;
                            int bmpY = row;
                            //int bmpY = height - 1 - row;  // 由于BitmapData自动颠倒了位图存储序,所以这个写法是错的。
                            hogGram.VoteHog(bmpX, bmpY, ge);

                            ptr1++;
                        }
                    }
                }

                bitmapSource.UnlockBits(dataSource);
            }
            return(hogGram);
        }
Example #4
0
        /// <summary>
        /// 训练正样本
        /// </summary>
        /// <param name="bmp">正样本位图</param>
        public void TrainPositive(Bitmap bmp)
        {
            Bitmap samplebmp    = null;
            double neg_distance = 0;
            double pos_distance = 0;
            bool   hasinserted  = false; // 指明样本是否已插入队列

            samplebmp = ImgOper.ResizeImage(bmp, Parameter.DETECT_WINDOW_SIZE.Width, Parameter.DETECT_WINDOW_SIZE.Height);
            samplebmp = ImgOper.Grayscale(samplebmp);

            for (double angle = (-1) * Parameter.ANGLE_BORDER; angle < Parameter.ANGLE_BORDER; angle += Parameter.ANGLE_INTERVAL)
            {
                Bitmap bmpclone = ImgOper.RotateImage(samplebmp, angle);
                bmpclone = ImgOper.ResizeImage(bmpclone, Parameter.DETECT_WINDOW_SIZE.Width, Parameter.DETECT_WINDOW_SIZE.Height);

                for (double scale = (-1) * Parameter.SCALE_BORDER; scale < Parameter.SCALE_BORDER; scale += Parameter.SCALE_INTERVAL)
                {
                    // 往两个方向去,所以是减号
                    IntPoint lt       = new IntPoint((int)(bmpclone.Width * scale / 2), (int)(bmpclone.Height * scale / 2));
                    IntPoint rt       = new IntPoint(bmpclone.Width - 1 - (int)(bmpclone.Width * scale / 2), (int)(bmpclone.Height * scale / 2));
                    IntPoint rb       = new IntPoint(bmpclone.Width - 1 - (int)(bmpclone.Width * scale / 2), bmpclone.Height - 1 - (int)(bmpclone.Height * scale / 2));
                    IntPoint lb       = new IntPoint((int)(bmpclone.Width * scale / 2), bmpclone.Height - 1 - (int)(bmpclone.Height * scale / 2));
                    Bitmap   scalebmp = ImgOper.QuadrilateralTransform(bmpclone, lt, rt, rb, lb);

                    HogGram             hogGram   = HogGram.GetHogFromBitmap(scalebmp, Parameter.CELL_SIZE.Width, Parameter.CELL_SIZE.Height, Parameter.PART_NUMBER);
                    NormBlockVectorGram blockGram = new NormBlockVectorGram(hogGram, Parameter.BLOCK_SIZE.Width, Parameter.BLOCK_SIZE.Height);

                    Rectangle rect = new Rectangle(0, 0, hogGram.HogSize.Width, hogGram.HogSize.Height);
                    double[]  vect = blockGram.GetHogWindowVec(rect);

                    if (Dimension != 0 && vect.Length != Dimension)
                    {
                        throw new Exception("输入正样本的尺寸与其他样本尺寸不一致!");
                    }

                    ValuedBitmap vbmp = null;
                    if (NegCenter != null && PosCenter != null)
                    {
                        // 计算离正负中心的距离
                        for (int i = 0; i < vect.Length; i++)
                        {
                            neg_distance += Math.Abs(vect[i] - NegCenter[i]);
                            pos_distance += Math.Abs(vect[i] - PosCenter[i]);
                        }

                        // 与负样本中心重合时,说明是负样本,不能插入正样本队列
                        if (neg_distance == 0)
                        {
                            return;
                        }

                        // 检测到的正样本加入样本队列的第二道关,如果不够接近正样本中心,就无法加入队列
                        // 按照Hog检测的判定条件,正距离乘以Parameter.POS_DIST_COEF,使其避开边界
                        if (neg_distance < pos_distance * Parameter.POS_DIST_COEF)
                        {
                            return;
                        }

                        // 带归一化的系数,如果用pos_distance/neg_distance,值可能会溢出;
                        // 将pos_distance / (pos_distance + neg_distance)作为正样本的评价系数,值越小越接近正样本
                        vbmp = new ValuedBitmap(scalebmp, pos_distance / (pos_distance + neg_distance));
                    }
                    else
                    {
                        // 如果正或负样本库还没建立起来,则Val暂时赋值为1
                        vbmp = new ValuedBitmap(scalebmp, 1);
                    }

                    // 检测到的正样本加入样本队列的第三道关,与正样本评价系数的有序队列比较后,决定是否加入样本队列
                    hasinserted = InsertValuedBitmap(ref PosMapCollection, vbmp, Parameter.POS_LIMITED_NUMBER);
                    PosLength   = PosMapCollection.Count;

                    //// 人工观察正样本插入情况
                    //if (hasinserted && vbmp != null)
                    //{
                    //    vbmp.VBitmap.Save("Image\\pos_save\\" + poscnt + "_" + vbmp.Val + ".jpg");
                    //    poscnt++;
                    //}

                    // 如果样本已经插入队列,说明样本比较可信,重新计算样本中心
                    if (hasinserted)
                    {
                        if (PosCenter == null)
                        {
                            Dimension = vect.Length;
                            PosCenter = new double[Dimension];
                        }

                        for (int i = 0; i < Dimension; i++)
                        {
                            PosCenter[i] = (PosCenter[i] * PosLength + vect[i]) / (PosLength + 1);
                        }
                    }
                }
            }
        }
Example #5
0
        /// <summary>
        /// 计算最近正样本距离系数,按照距离而不是相关系数,这样效率高,系数越小,检测对象越接近目标
        /// </summary>
        /// <param name="rect">检测目标区域</param>
        /// <param name="bmp">位图</param>
        /// <returns>最近距离系数, double.MaxValue表示计算异常或没计算</returns>
        private double NearestNeighbour(Rectangle rect, Bitmap bmp)
        {
            Bitmap sample = null;
            Bitmap detect = null;

            Rectangle gramRect = Rectangle.Empty;

            HogGram sampleHGram = null;
            HogGram detectHGram = null;

            NormBlockVectorGram sampleBlock = null;
            NormBlockVectorGram detectBlock = null;

            double[]  detectvect = null;
            double[]  samplevect = null;
            ArrayList posvects   = null;
            ArrayList negvects   = null;

            double minposdist  = double.MaxValue;
            double minnegdist  = double.MaxValue;
            double dist        = 0;
            double nearestdist = double.MaxValue;


            if (PosLength == 0 || NegLength == 0)
            {
                return(nearestdist);
            }

            // 正样本载入
            posvects = new ArrayList();
            for (int i = 0; i < PosLength; i++)
            {
                sample = PosMapCollection[i].VBitmap;
                sample = ImgOper.ResizeImage(sample, Parameter.DETECT_WINDOW_SIZE.Width, Parameter.DETECT_WINDOW_SIZE.Height);
                sample = ImgOper.Grayscale(sample);

                sampleHGram = HogGram.GetHogFromBitmap(sample, Parameter.CELL_SIZE.Width, Parameter.CELL_SIZE.Height, Parameter.PART_NUMBER);
                sampleBlock = new NormBlockVectorGram(sampleHGram, Parameter.BLOCK_SIZE.Width, Parameter.BLOCK_SIZE.Height);

                gramRect   = new Rectangle(0, 0, sampleHGram.HogSize.Width, sampleHGram.HogSize.Height);
                samplevect = sampleBlock.GetHogWindowVec(gramRect);
                posvects.Add(samplevect);
            }

            // 负样本载入
            negvects = new ArrayList();
            for (int i = 0; i < NegLength; i++)
            {
                sample = NegMapCollection[i].VBitmap;
                sample = ImgOper.ResizeImage(sample, Parameter.DETECT_WINDOW_SIZE.Width, Parameter.DETECT_WINDOW_SIZE.Height);
                sample = ImgOper.Grayscale(sample);

                sampleHGram = HogGram.GetHogFromBitmap(sample, Parameter.CELL_SIZE.Width, Parameter.CELL_SIZE.Height, Parameter.PART_NUMBER);
                sampleBlock = new NormBlockVectorGram(sampleHGram, Parameter.BLOCK_SIZE.Width, Parameter.BLOCK_SIZE.Height);

                gramRect   = new Rectangle(0, 0, sampleHGram.HogSize.Width, sampleHGram.HogSize.Height);
                samplevect = sampleBlock.GetHogWindowVec(gramRect);
                negvects.Add(samplevect);
            }


            detect = ImgOper.CutImage(bmp, rect.X, rect.Y, rect.Width, rect.Height);
            detect = ImgOper.ResizeImage(detect, Parameter.DETECT_WINDOW_SIZE.Width, Parameter.DETECT_WINDOW_SIZE.Height);
            detect = ImgOper.Grayscale(detect);

            detectHGram = HogGram.GetHogFromBitmap(detect, Parameter.CELL_SIZE.Width, Parameter.CELL_SIZE.Height, Parameter.PART_NUMBER);
            detectBlock = new NormBlockVectorGram(detectHGram, Parameter.BLOCK_SIZE.Width, Parameter.BLOCK_SIZE.Height);

            gramRect   = new Rectangle(0, 0, detectHGram.HogSize.Width, detectHGram.HogSize.Height);
            detectvect = detectBlock.GetHogWindowVec(gramRect);

            foreach (double[] svect in posvects)
            {
                dist = ImgStatCompute.ComputeDistance(detectvect, svect);
                if (dist < minposdist)
                {
                    minposdist = dist;
                }
            }

            foreach (double[] svect in negvects)
            {
                dist = ImgStatCompute.ComputeDistance(detectvect, svect);

                if (dist < minnegdist)
                {
                    minnegdist = dist;
                }
            }

            if (minnegdist != 0 || minposdist != 0)
            {
                nearestdist = minposdist / (minposdist + minnegdist);
            }

            return(nearestdist);
        }
Example #6
0
        /// <summary>
        /// Hog检测, 被检测到图像自动缩放到BMPLIMITSIZE容忍范围内,并在检测完后将检测框自动放大之前缩小的倍率
        /// </summary>
        /// <param name="bmp">位图</param>
        public RectangleCollection HogDetect(Bitmap bmp)
        {
            RectangleCollection resultCollection = null;

            if (bmp == null)
            {
                return(null);
            }

            if (NegCenter == null && PosCenter == null)
            {
                return(null);
            }

            DateTime dt     = DateTime.Now;
            double   elapse = 0;

            // 针对原图的缩放倍率
            double se = 1;

            if (bmp.Width > Parameter.BMPLIMITSIZE.Width || bmp.Height > Parameter.BMPLIMITSIZE.Height)
            {
                se = bmp.Width / (double)Parameter.BMPLIMITSIZE.Width > bmp.Height / (double)Parameter.BMPLIMITSIZE.Height ?
                     bmp.Width / (double)Parameter.BMPLIMITSIZE.Width : bmp.Height / (double)Parameter.BMPLIMITSIZE.Height;
                bmp = ImgOper.ResizeImage(bmp, (int)(bmp.Width / se), (int)(bmp.Height / se));
            }
            bmp = ImgOper.Grayscale(bmp);

            //bmp = ImgOper.GaussianConvolution(bmp, GAUSSIAN_SIGMA, GAUSSIAN_SIZE);   // 高斯卷积,使得图像平滑

            // 所有层的检测结果
            ArrayList resultlayers = new ArrayList();
            // 初始缩放因子
            double scalecoef = 1.0;
            Bitmap scalebmp  = null;
            int    newwidth  = (int)(bmp.Width / scalecoef);
            int    newheight = (int)(bmp.Height / scalecoef);
            // 每层最小距离点的集合
            ArrayList idx_layermindistance = new ArrayList();
            int       cnt = 0;

            do
            {
                scalebmp = ImgOper.ResizeImage(bmp, newwidth, newheight);
                HogGram             hogGram   = HogGram.GetHogFromBitmap(scalebmp, Parameter.CELL_SIZE.Width, Parameter.CELL_SIZE.Height, Parameter.PART_NUMBER);
                NormBlockVectorGram blockGram = new NormBlockVectorGram(hogGram, Parameter.BLOCK_SIZE.Width, Parameter.BLOCK_SIZE.Height);

                DetectResultLayer detectlayer = new DetectResultLayer();
                // !!!!!!检测窗口的像素尺寸必须能被cell尺寸整除!!!!!!像素尺寸除以hog尺寸就是检测窗口的尺寸
                detectlayer.DetectResult = blockGram.DetectImgByHogWindow(
                    new Size(Parameter.DETECT_WINDOW_SIZE.Width / Parameter.CELL_SIZE.Width, Parameter.DETECT_WINDOW_SIZE.Height / Parameter.CELL_SIZE.Height),
                    NegCenter, PosCenter, Parameter.POS_DIST_COEF);
                if (detectlayer.DetectResult == null)
                {
                    return(null);
                }

                detectlayer.ScaleCoef = scalecoef;
                resultlayers.Add(detectlayer);        // 本层检测结果加入队列

                scalecoef *= Parameter.SCALE_COEF;    // 逐次缩小图像
                newwidth   = (int)(bmp.Width / scalecoef);
                newheight  = (int)(bmp.Height / scalecoef);
                cnt++;
            } while (newwidth > 2 * Parameter.DETECT_WINDOW_SIZE.Width && newheight > 2 * Parameter.DETECT_WINDOW_SIZE.Height);

            elapse = DateTime.Now.Subtract(dt).TotalSeconds;

            // 框出所有可能的物体
            WindowResult[] wr = null;
            Rectangle      rect;
            double         mindist       = -1;
            WindowResult   min_obj       = null;
            double         min_scalecoef = 1;

            resultCollection = new RectangleCollection();

            foreach (DetectResultLayer layer in resultlayers)
            {
                wr = layer.DetectResult;
                for (int i = 0; i < wr.Length; i++)
                {
                    if (wr[i].label == 1)
                    {
                        if (mindist == -1 || mindist > wr[i].PosDistance)
                        {
                            mindist       = wr[i].PosDistance;
                            min_obj       = wr[i];
                            min_scalecoef = layer.ScaleCoef;
                        }

                        rect = new Rectangle((int)(wr[i].ImageRegion.X * layer.ScaleCoef * se),
                                             (int)(wr[i].ImageRegion.Y * layer.ScaleCoef * se),
                                             (int)(wr[i].ImageRegion.Width * layer.ScaleCoef * se),
                                             (int)(wr[i].ImageRegion.Height * layer.ScaleCoef * se));
                        resultCollection.Add(rect);
                    }
                }
            }

            //rect = new Rectangle((int)(min_obj.ImageRegion.X * min_scalecoef * se),
            //    (int)(min_obj.ImageRegion.Y * min_scalecoef * se),
            //    (int)(min_obj.ImageRegion.Width * min_scalecoef * se),
            //    (int)(min_obj.ImageRegion.Height * min_scalecoef * se));
            //resultCollection.Add(rect);
            return(resultCollection);
        }
Example #7
0
        /// <summary>
        /// 训练负样本
        /// </summary>
        /// <param name="bmp">负样本位图</param>
        public void TrainNegative(Bitmap bmp)
        {
            Bitmap samplebmp    = null;
            double neg_distance = 0;
            double pos_distance = 0;
            bool   hasinserted  = false; // 指明样本是否已插入队列

            if (bmp.Width / Parameter.DETECT_WINDOW_SIZE.Width > bmp.Height / Parameter.DETECT_WINDOW_SIZE.Height)
            {
                samplebmp = ImgOper.ResizeImage(bmp,
                                                (int)(bmp.Width * Parameter.DETECT_WINDOW_SIZE.Height / bmp.Height), Parameter.DETECT_WINDOW_SIZE.Height);
            }
            else
            {
                samplebmp = ImgOper.ResizeImage(bmp, Parameter.DETECT_WINDOW_SIZE.Width,
                                                (int)(bmp.Height * Parameter.DETECT_WINDOW_SIZE.Width / bmp.Width));
            }
            samplebmp = ImgOper.CutImage(samplebmp, 0, 0, Parameter.DETECT_WINDOW_SIZE.Width, Parameter.DETECT_WINDOW_SIZE.Height);
            samplebmp = ImgOper.Grayscale(samplebmp);

            HogGram             hogGram   = HogGram.GetHogFromBitmap(samplebmp, Parameter.CELL_SIZE.Width, Parameter.CELL_SIZE.Height, Parameter.PART_NUMBER);
            NormBlockVectorGram blockGram = new NormBlockVectorGram(hogGram, Parameter.BLOCK_SIZE.Width, Parameter.BLOCK_SIZE.Height);

            Rectangle rect = new Rectangle(0, 0, hogGram.HogSize.Width, hogGram.HogSize.Height);

            double[] vect = blockGram.GetHogWindowVec(rect);

            if (Dimension != 0 && vect.Length != Dimension)
            {
                throw new Exception("输入负样本的尺寸与其他样本尺寸不一致!");
            }

            ValuedBitmap vbmp = null;

            if (PosCenter != null && NegCenter != null)
            {
                // 计算离正负中心的距离
                for (int i = 0; i < vect.Length; i++)
                {
                    neg_distance += Math.Abs(vect[i] - NegCenter[i]);
                    pos_distance += Math.Abs(vect[i] - PosCenter[i]);
                }

                // 与正样本中心重合时,说明是正样本,不能插入负样本队列
                if (pos_distance == 0)
                {
                    return;
                }

                // 负样本加入样本队列的第二道关,如果不够接近负样本中心,就无法加入队列
                // 按照Hog检测的判定条件,正距离乘以Parameter.POS_DIST_COEF,使其避开边界
                if (pos_distance * Parameter.POS_DIST_COEF < neg_distance)
                {
                    return;
                }

                // 带归一化的系数,如果用neg_distance / pos_distance,值可能会溢出;
                // 将neg_distance / (pos_distance + neg_distance)作为负样本的评价系数,值越小越接近负样本
                vbmp = new ValuedBitmap(samplebmp, neg_distance / (pos_distance + neg_distance));
            }
            else
            {
                // 如果正样本库还没建立起来,则Val暂时赋值为1
                vbmp = new ValuedBitmap(samplebmp, 1);
            }

            // 负样本加入样本队列的第三道关,与负样本评价系数的有序队列比较后,决定是否加入样本队列
            hasinserted = InsertValuedBitmap(ref NegMapCollection, vbmp, Parameter.NEG_LIMITED_NUMBER);
            NegLength   = NegMapCollection.Count;

            //// 人工观察负样本插入情况
            //if (hasinserted && vbmp != null)
            //{
            //    vbmp.VBitmap.Save("Image\\neg_save\\" + negcnt + "_" + vbmp.Val + ".jpg");
            //    negcnt++;
            //}

            // 如果样本已经插入队列,说明样本比较可信,重新计算样本中心
            if (hasinserted)
            {
                if (NegCenter == null)
                {
                    Dimension = vect.Length;
                    NegCenter = new double[Dimension];
                }

                for (int i = 0; i < Dimension; i++)
                {
                    NegCenter[i] = (NegCenter[i] * NegLength + vect[i]) / (NegLength + 1);
                }
            }
        }