/// <summary> /// Convert an float image to a squared integral image /// </summary> /// <remarks> /// We skip the last line to keep the original size (better performance) /// </remarks> /// <param name="source">image source</param> /// <param name="dest">image destination</param> public void IntegralSquare(IImage2DByteA source, IImage2DUIntA dest) { if (source == null) throw new ArgumentNullException("source"); if (dest == null) throw new ArgumentNullException("dest"); if ((source.Width > dest.Width) || (source.Height > dest.Height)) throw new ArgumentException("Destination image (" + dest.Width + "x" + dest.Height + ") must have at least the source image width and height but is only " + source.Width + "x" + source.Height); int height = source.Height; int width = source.Width; byte[] sBuf = source.HostBuffer; uint[] dBuf = dest.HostBuffer; for (int x = 0; x < width; x++) dest.HostBuffer[x] = 0; // zero first line for (int y = 0, a = width * height; y < a; y += width) dest.HostBuffer[y] = 0; // zero first column // for each line int ySumIndex = 0; int y1SumIndex; int yIndex = 0; for (int y = 1; y < height; y++) { y1SumIndex = ySumIndex; ySumIndex += width; // for each pixel for (int x = 1; x < width; x++) { uint p = sBuf[yIndex + x - 1]; dBuf[ySumIndex + x] = p * p + dBuf[ySumIndex + x - 1] + dBuf[y1SumIndex + x] - dBuf[y1SumIndex + x - 1]; } yIndex += width; } }
/// <summary> /// Convert an float image to an integral image /// </summary> /// <remarks> /// We skip the last line to keep the original size (better performance) /// </remarks> /// <param name="source">image source</param> /// <param name="dest">image destination</param> public void Integral(IImage2DByteA source, IImage2DUIntA dest) { if (source == null) throw new ArgumentNullException("source"); if (dest == null) throw new ArgumentNullException("dest"); if ((source.Width > dest.Width) || (source.Height > dest.Height)) throw new ArgumentException("Destination image (" + dest.Width + "x" + dest.Height + ") must have at least the source image width and height but is only " + source.Width + "x" + source.Height); int heightS = source.Height; int widthS = source.Width; int heightD = dest.Height; int widthD = dest.Width; byte[] sBuf = source.HostBuffer; uint[] dBuf = dest.HostBuffer; for (int x = 0; x < widthD; x++) dest.HostBuffer[x] = 0; // zero first line for (int y = 0, a = widthD * heightD; y < a; y += widthD) dest.HostBuffer[y] = 0; // zero first column int y1IndexS = 0; int yIndexD = widthD; int y1IndexD = 0; // last // for each line for (int y = 1; y < heightS; y++) { // for each pixel for (int x = 1; x < widthS; x++) { uint p = sBuf[y1IndexS + x - 1]; dBuf[yIndexD + x] = p + dBuf[yIndexD + x - 1] + dBuf[y1IndexD + x] - dBuf[y1IndexD + x - 1]; } yIndexD += widthD; y1IndexS += widthS; y1IndexD += widthD; } }
/// <summary> /// Free resources being used /// </summary> public void Dispose() { try { if (_ownIntegralImage) { _integralImage.Dispose(); _integralImage = null; } } catch { } try { if (_ownIntegral2Image) { _integral2Image.Dispose(); _integral2Image = null; } } catch { } try { if (_ownResultRectangles) { _resultRectangles.Dispose(); _resultRectangles = null; } } catch { } }
/// <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> /// Gets the sum of a rectangular feature in an integral image. /// </summary> public static float GetSum(ref HaarRectangle rect, IImage2DUIntA integralImage, int x, int y) { return integralImage.GetIntegralSum(x + rect.ScaledX, y + rect.ScaledY, rect.ScaledWidth, rect.ScaledHeight) * rect.ScaledWeight; }
/// <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; }