private void NonMaximumSuppression(List <FaceInfo> input, List <FaceInfo> output, float nmsThreshold = 0.3f, NonMaximumSuppressionMode type = NonMaximumSuppressionMode.Minimum) { if (!input.Any()) { return; } input.Sort((f1, f2) => f1.Score.CompareTo(f2.Score)); var nPick = 0; var vScores = new List <Tuple <float, int> >(); var numBoxes = input.Count; var vPick = new int[numBoxes]; for (var i = 0; i < numBoxes; ++i) { vScores.Add(new Tuple <float, int>(input[i].Score, i)); } while (vScores.Count > 0) { var last = vScores.Last().Item2; vPick[nPick] = last; nPick += 1; for (var index = 0; index < vScores.Count;) { var it = vScores[index]; var itemIndex = it.Item2; var maxX = Math.Max(input[itemIndex].X1, input[last].X1); var maxY = Math.Max(input[itemIndex].Y1, input[last].Y1); var minX = Math.Min(input[itemIndex].X2, input[last].X2); var minY = Math.Min(input[itemIndex].Y2, input[last].Y2); //maxX1 and maxY1 reuse maxX = ((minX - maxX + 1) > 0) ? (minX - maxX + 1) : 0; maxY = ((minY - maxY + 1) > 0) ? (minY - maxY + 1) : 0; //IOU reuse for the area of two bbox var iou = maxX * maxY; switch (type) { case NonMaximumSuppressionMode.Union: iou = iou / (input[itemIndex].Area + input[last].Area - iou); break; case NonMaximumSuppressionMode.Minimum: iou = iou / ((input[itemIndex].Area < input[last].Area) ? input[itemIndex].Area : input[last].Area); break; } if (iou > nmsThreshold) { vScores.RemoveAt(index); } else { index++; } } } Array.Resize(ref vPick, nPick); Resize(output, nPick); for (var i = 0; i < nPick; i++) { output[i] = input[vPick[i]]; } }
private void NonMaximumSuppression(List <FaceInfo> input, ICollection <FaceInfo> output, NonMaximumSuppressionMode type = NonMaximumSuppressionMode.Blending) { input.Sort((f1, f2) => f1.Score.CompareTo(f2.Score)); var boxNum = input.Count; var merged = new int[boxNum]; for (var i = 0; i < boxNum; i++) { if (merged[i] > 0) { continue; } var buf = new List <FaceInfo> { input[i] }; merged[i] = 1; var h0 = input[i].Y2 - input[i].Y1 + 1; var w0 = input[i].X2 - input[i].X1 + 1; var area0 = h0 * w0; for (var j = i + 1; j < boxNum; j++) { if (merged[j] > 0) { continue; } var innerX0 = input[i].X1 > input[j].X1 ? input[i].X1 : input[j].X1; var innerY0 = input[i].Y1 > input[j].Y1 ? input[i].Y1 : input[j].Y1; var innerX1 = input[i].X2 < input[j].X2 ? input[i].X2 : input[j].X2; var innerY1 = input[i].Y2 < input[j].Y2 ? input[i].Y2 : input[j].Y2; var innerH = innerY1 - innerY0 + 1; var innerW = innerX1 - innerX0 + 1; if (innerH <= 0 || innerW <= 0) { continue; } var innerArea = innerH * innerW; var h1 = input[j].Y2 - input[j].Y1 + 1; var w1 = input[j].X2 - input[j].X1 + 1; var area1 = h1 * w1; var score = innerArea / (area0 + area1 - innerArea); if (score > this._IouThreshold) { merged[j] = 1; buf.Add(input[j]); } } switch (type) { case NonMaximumSuppressionMode.Hard: { output.Add(buf[0]); break; } case NonMaximumSuppressionMode.Blending: { var total = 0d; for (var j = 0; j < buf.Count; j++) { total += Math.Exp(buf[j].Score); } var rects = new FaceInfo(); for (var j = 0; j < buf.Count; j++) { var rate = Math.Exp(buf[j].Score) / total; rects.X1 += (float)(buf[j].X1 * rate); rects.Y1 += (float)(buf[j].Y1 * rate); rects.X2 += (float)(buf[j].X2 * rate); rects.Y2 += (float)(buf[j].Y2 * rate); rects.Score += (float)(buf[j].Score * rate); } output.Add(rects); break; } default: //{ // Console.WriteLine("wrong type of nms."); // exit(-1); //} break; } } #endregion #endregion }