/// <summary> /// 负样本检测专家,专门检测被误判为正的负样本和增加负样本集合 /// </summary> /// <param name="detectCollection">检测模块产生的区域集合</param> /// <param name="trackerRect">跟踪模块产生的区域</param> /// <param name="bmp">被检测的位图</param> /// <returns>返回最可信对象区域</returns> public Rectangle NegativeExpert(RectangleCollection detectCollection, RectangleF trackerRect, Bitmap bmp) { // 复制一个矩形集合是为了让NExpert独立与PExpert RectangleCollection newRectCollection = new RectangleCollection(); if (detectCollection != null) { foreach (Rectangle detectrect in detectCollection) { newRectCollection.Add(detectrect); } } if (trackerRect != Rectangle.Empty) { // 将跟踪到的目标也加入待评估的对象集合 newRectCollection.Add(new Rectangle((int)trackerRect.X, (int)trackerRect.Y, (int)trackerRect.Width, (int)trackerRect.Height)); } DateTime dt = DateTime.Now; // 最可信的对象 Rectangle confidentRect = MinDistanceObject(newRectCollection, bmp); double elapse = DateTime.Now.Subtract(dt).TotalMilliseconds; if (confidentRect != Rectangle.Empty) { newRectCollection.Remove(confidentRect); } dt = DateTime.Now; foreach (Rectangle rect in newRectCollection) { // 判断目标是否确实为背景,正距离归一化系数大于0.5 // 目标加入负样本队列的第一道关,目标必须看起来像负样本(正距离归一化系数大于0.5) if (MinDistance(rect, bmp) > Parameter.MEDIAN_COEF) { double areainsect = AreaProportion(confidentRect, rect); // 与最可信对象交集面积小于AREA_INTERSECT_PROPORTION的为负样本,加入负样本列表 if (areainsect < Parameter.AREA_INTERSECT_PROPORTION) { Bitmap patch = ImgOper.CutImage(bmp, rect.X, rect.Y, rect.Width, rect.Height); TrainNegative(patch); } } } elapse = DateTime.Now.Subtract(dt).TotalMilliseconds; return(confidentRect); }
/// <summary> /// 正样本检测专家,专门检测被误判为负的正样本 /// </summary> /// <param name="detectCollection">检测模块产生的区域集合</param> /// <param name="trackerRect">跟踪模块产生的区域</param> /// <param name="bmp">被检测位图</param> public void PositiveExpert(RectangleCollection detectCollection, RectangleF trackerRect, Bitmap bmp) { double areaproportion = 0; bool nointersect = true; // 指明跟踪模块和检测模块得到的区域是否无交集 if (trackerRect == Rectangle.Empty) { return; } foreach (Rectangle rect in detectCollection) { areaproportion = AreaProportion(trackerRect, rect); if (areaproportion > Parameter.AREA_INTERSECT_PROPORTION) { nointersect = false; break; } } // 没有交集,说明存在被误判为负的正样例 if (nointersect) { // 判断跟踪到的目标是否确实为要识别的物体,正距离归一化系数小于0.5 // 目标加入正样本队列的第一道关,目标必须看起来像正样本(正距离归一化系数小于0.5) if (MinDistance(trackerRect, bmp) < Parameter.MEDIAN_COEF) { for (double lrshift = (-1) * Parameter.SHIFT_BORDER; lrshift < Parameter.SHIFT_BORDER + Parameter.SHIFT_INTERVAL; lrshift += Parameter.SHIFT_INTERVAL) { for (double tbshift = (-1) * Parameter.SHIFT_BORDER; tbshift < Parameter.SHIFT_BORDER + Parameter.SHIFT_INTERVAL; tbshift += Parameter.SHIFT_INTERVAL) { if (trackerRect.X + lrshift >= 0 && trackerRect.X + trackerRect.Width - 1 + lrshift < bmp.Width - 1 && trackerRect.Y + tbshift >= 0 && trackerRect.Y + trackerRect.Height - 1 + tbshift < bmp.Height - 1) { Bitmap patch = ImgOper.CutImage(bmp, (int)(trackerRect.X + lrshift), (int)(trackerRect.Y + tbshift), (int)trackerRect.Width, (int)trackerRect.Height); TrainPositive(patch); } } } } } }
/// <summary> /// 计算正样本最大相关系数,数值越大,被检测对象越接近目标 /// </summary> /// <param name="rect">检测目标区域</param> /// <param name="bmp">位图</param> /// <returns>正样本最大相关系数</returns> public double MostAssociate(Rectangle rect, Bitmap bmp) { double maxcoef = 0; // 返回值 double coef = 0; double maxposcoef = 0; double maxnegcoef = 0; if (rect == Rectangle.Empty) { return(maxcoef); } Bitmap patch = ImgOper.CutImage(bmp, rect.X, rect.Y, rect.Width, rect.Height); patch = ImgOper.ResizeImage(patch, Parameter.DETECT_WINDOW_SIZE.Width, Parameter.DETECT_WINDOW_SIZE.Height); patch = ImgOper.Grayscale(patch); foreach (ValuedBitmap posbmp in PosMapCollection) { coef = ImgStatCompute.ComputeAssociationCoef(patch, posbmp.VBitmap); if (maxposcoef < coef) { maxposcoef = coef; } } foreach (ValuedBitmap negbmp in NegMapCollection) { coef = ImgStatCompute.ComputeAssociationCoef(patch, negbmp.VBitmap); if (maxnegcoef < coef) { maxnegcoef = coef; } } if (maxnegcoef != 0 || maxposcoef != 0) { maxcoef = maxposcoef / (maxposcoef + maxnegcoef); } return(maxcoef); }
private void btnOk_Click(object sender, EventArgs e) { Bitmap patch = null; if (pri_tld != null && pri_bmp != null && pri_choose_rect != Rectangle.Empty) { for (double lrshift = (-1) * Parameter.SHIFT_BORDER; lrshift < Parameter.SHIFT_BORDER + Parameter.SHIFT_INTERVAL; lrshift += Parameter.SHIFT_INTERVAL) { for (double tbshift = (-1) * Parameter.SHIFT_BORDER; tbshift < Parameter.SHIFT_BORDER + Parameter.SHIFT_INTERVAL; tbshift += Parameter.SHIFT_INTERVAL) { if (pri_choose_rect.X + lrshift >= 0 && pri_choose_rect.X + pri_choose_rect.Width - 1 + lrshift < pri_bmp.Width - 1 && pri_choose_rect.Y + tbshift >= 0 && pri_choose_rect.Y + pri_choose_rect.Height - 1 + tbshift < pri_bmp.Height - 1) { patch = ImgOper.CutImage(pri_bmp, (int)(pri_choose_rect.X + lrshift), (int)(pri_choose_rect.Y + tbshift), (int)pri_choose_rect.Width, (int)pri_choose_rect.Height); pri_tld.TrainPositive(patch); //patch.Save("Image\\VideoSave\\" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".jpg"); } } } for (int row = 0; row < pri_bmp.Height - Parameter.DETECT_WINDOW_SIZE.Height + 1; row += Parameter.DETECT_WINDOW_SIZE.Height) { for (int col = 0; col < pri_bmp.Width - Parameter.DETECT_WINDOW_SIZE.Width + 1; col += Parameter.DETECT_WINDOW_SIZE.Width) { Rectangle rect = new Rectangle(col, row, pri_choose_rect.Width, pri_choose_rect.Height); double areaportion = pri_tld.AreaProportion(rect, pri_choose_rect); if (areaportion < Parameter.AREA_INTERSECT_PROPORTION) { patch = ImgOper.CutImage(pri_bmp, rect.X, rect.Y, rect.Width, rect.Height); pri_tld.TrainNegative(patch); } } } } pri_player.Start(); this.Close(); }
/// <summary> /// 计算最近正样本距离系数,按照距离而不是相关系数,这样效率高,系数越小,检测对象越接近目标 /// </summary> /// <param name="rect">检测目标区域</param> /// <param name="bmp">整幅位图</param> /// <returns>最近距离系数, double.MaxValue表示计算异常或没计算</returns> public double MinDistance(RectangleF rect, Bitmap bmp) { double mindistance = double.MaxValue; // 返回值 double dist = double.MaxValue; double minposdist = double.MaxValue; double minnegdist = double.MaxValue; if (rect == Rectangle.Empty) { return(mindistance); } DateTime dt = DateTime.Now; double elapse = 0; Bitmap patch = ImgOper.CutImage(bmp, (int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height); patch = ImgOper.ResizeImage(patch, Parameter.DETECT_WINDOW_SIZE.Width, Parameter.DETECT_WINDOW_SIZE.Height); patch = ImgOper.Grayscale(patch); int[,] patchgram = ImgOper.Integrogram(patch, 1); byte[] patchdata = ImgOper.GetGraybmpData(patch); double patchmean = (double)patchgram[patch.Height - 1, patch.Width - 1] / (double)(patch.Width * patch.Height); double[] patchdatad = new double[patchdata.Length]; for (int i = 0; i < patchdata.Length; i++) { patchdatad[i] = patchdata[i] - patchmean; } foreach (ValuedBitmap posbmp in PosMapCollection) { int[,] posgram = ImgOper.Integrogram(posbmp.VBitmap, 1); byte[] posdata = ImgOper.GetGraybmpData(posbmp.VBitmap); double posmean = (double)posgram[posbmp.VBitmap.Height - 1, posbmp.VBitmap.Width - 1] / (double)(posbmp.VBitmap.Width * posbmp.VBitmap.Height); double[] posdatad = new double[posdata.Length]; for (int i = 0; i < posdata.Length; i++) { posdatad[i] = posdata[i] - posmean; } dist = ImgStatCompute.ComputeDistance(patchdatad, posdatad); if (dist < minposdist) { minposdist = dist; } } foreach (ValuedBitmap negbmp in NegMapCollection) { int[,] neggram = ImgOper.Integrogram(negbmp.VBitmap, 1); byte[] negdata = ImgOper.GetGraybmpData(negbmp.VBitmap); double negmean = (double)neggram[negbmp.VBitmap.Height - 1, negbmp.VBitmap.Width - 1] / (double)(negbmp.VBitmap.Width * negbmp.VBitmap.Height); double[] negdatad = new double[negdata.Length]; for (int i = 0; i < negdata.Length; i++) { negdatad[i] = negdata[i] - negmean; } dist = ImgStatCompute.ComputeDistance(patchdatad, negdatad); if (dist < minnegdist) { minnegdist = dist; } } if (minnegdist != 0 || minposdist != 0) { // 带归一化的系数,如果用minposdist/minnegdist,值可能会溢出 mindistance = minposdist / (minposdist + minnegdist); } elapse = DateTime.Now.Subtract(dt).TotalMilliseconds; return(mindistance); }
/// <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); }
/// <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); } } }