/// <summary> /// Adds a Haar feature node to list /// </summary> /// <param name="nodes">List of HaarFeatureNodes</param> /// <param name="threshold">threshold of node</param> /// <param name="leftValue">left value</param> /// <param name="rightValue">right value</param> /// <param name="rectangles">HaarRectangle</param> public static void AddHaarFeature(this List<HaarFeatureNode> nodes, double threshold, double leftValue, double rightValue, params HaarRectangle[] rectangles) { HaarFeatureNode node = new HaarFeatureNode(); node.Threshold = (float)threshold; node.LeftValue = (float)leftValue; node.RightValue = (float)rightValue; node.RectCount = rectangles.Length; if (node.RectCount < 2 || node.RectCount > 3) throw new ArgumentException("Haar feature nodes must have 2 or 3 rectangles only"); node.Rect1 = rectangles[0]; node.Rect2 = rectangles[1]; if (node.RectCount > 2) node.Rect3 = rectangles[2]; nodes.Add(node); }
/// <summary> /// Detects the presence of an object in a given window. /// </summary> protected bool Compute(HaarFeatureNode[] stageNodes, int stagesCount, int[] stageNodeCounts, float[] stageThresholds, IImage2DUIntA integralImage, IImage2DUIntA integral2Image, float invArea, int x, int y, int w, int h) { float mean = (float)integralImage.GetIntegralSum(x, y, w, h) * invArea; float normFactor = (float)integral2Image.GetIntegralSum(x, y, w, h) * invArea - (mean * mean); normFactor = (normFactor >= 0) ? (float)Math.Sqrt(normFactor) : 1; int pos = 0; for (int j = 0; j < stagesCount; j++) { int count = stageNodeCounts[j]; float threshold = stageThresholds[j]; float value = 0; for (int i = 0; i < count; i++) { // evaluate the node's feature float sum = HaarExtensions.GetNodeSum(ref stageNodes[pos], integralImage, x, y); // and increase the value accumulator HaarFeatureNode node = stageNodes[pos++]; value += ((sum < node.Threshold * normFactor) ? node.LeftValue : node.RightValue); } if (value <= threshold) return false; // window has been rejected } return true; }
/// <summary> /// Sets the scale and weight of a Haar-like rectangular feature container. /// </summary> public static void SetScaleAndWeight(ref HaarFeatureNode node, float scale, float weight) { // manual loop unfolding if (node.RectCount == 2) { ScaleRectangle(ref node.Rect2, scale, weight); ScaleRectangle(ref node.Rect1, scale, weight); node.Rect1.ScaledWeight = -(node.Rect2.GetArea() * node.Rect2.ScaledWeight) / node.Rect1.GetArea(); } else // rectangles.Length == 3 { ScaleRectangle(ref node.Rect3, scale, weight); ScaleRectangle(ref node.Rect2, scale, weight); ScaleRectangle(ref node.Rect1, scale, weight); node.Rect1.ScaledWeight = -(node.Rect2.GetArea() * node.Rect2.ScaledWeight + node.Rect3.GetArea() * node.Rect3.ScaledWeight) / (node.Rect1.GetArea()); } }
/// <summary> /// Gets the sum of the areas of the rectangular features in an integral image. /// </summary> public static float GetNodeSum(ref HaarFeatureNode node, IImage2DUIntA integralImage, int x, int y) { float sum; sum = GetSum(ref node.Rect1, integralImage, x, y); sum += GetSum(ref node.Rect2, integralImage, x, y); if (node.RectCount == 3) sum += GetSum(ref node.Rect3, integralImage, x, y); return sum; }