/// <summary> /// Constructs a new Integral image from a Bitmap image. /// </summary> /// /// <param name="image">The source image from where the integral image should be computed.</param> /// <param name="channel">The image channel to consider in the computations. Default is 0.</param> /// <param name="computeTilted"><c>True</c> to compute the tilted version of the integral image, /// <c>false</c> otherwise. Default is false.</param> /// /// <returns> /// The <see cref="IntegralImage2"/> representation of /// the <paramref name="image">source image</paramref>.</returns> /// public static IntegralImage2 FromBitmap(Bitmap image, int channel, bool computeTilted) { // check image format if (!(image.PixelFormat == PixelFormat.Format8bppIndexed || image.PixelFormat == PixelFormat.Format24bppRgb || image.PixelFormat == PixelFormat.Format32bppArgb || image.PixelFormat == PixelFormat.Format32bppRgb)) { throw new UnsupportedImageFormatException("Only grayscale, 24 and 32 bpp RGB images are supported."); } // lock source image BitmapData imageData = image.LockBits( new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, image.PixelFormat); // process the image IntegralImage2 im = FromBitmap(imageData, channel, computeTilted); // unlock image image.UnlockBits(imageData); return(im); }
/// <summary> /// Constructs a new Integral image from an unmanaged image. /// </summary> /// /// <param name="image">The source image from where the integral image should be computed.</param> /// <param name="channel">The image channel to consider in the computations. Default is 0.</param> /// <param name="computeTilted"><c>True</c> to compute the tilted version of the integral image, /// <c>false</c> otherwise. Default is false.</param> /// /// <returns> /// The <see cref="IntegralImage2"/> representation of /// the <paramref name="image">source image</paramref>.</returns> /// public static IntegralImage2 FromBitmap(UnmanagedImage image, int channel, bool computeTilted) { // check image format if (!(image.PixelFormat == PixelFormat.Format8bppIndexed || image.PixelFormat == PixelFormat.Format24bppRgb || image.PixelFormat == PixelFormat.Format32bppArgb || image.PixelFormat == PixelFormat.Format32bppRgb)) { throw new UnsupportedImageFormatException("Only grayscale, 24 and 32 bpp RGB images are supported."); } // get source image size int width = image.Width; int height = image.Height; IntegralImage2 im = new IntegralImage2(width, height, computeTilted); im.Update(image, channel); return(im); }
/// <summary> /// Gets the sum of the areas of the rectangular features in an integral image. /// </summary> /// public double GetSum(IntegralImage2 image, int x, int y) { double sum = 0.0; if (!Tilted) { // Compute the sum for a standard feature foreach (HaarRectangle rect in Rectangles) { sum += image.GetSum(x + rect.ScaledX, y + rect.ScaledY, rect.ScaledWidth, rect.ScaledHeight) * rect.ScaledWeight; } } else { // Compute the sum for a rotated feature foreach (HaarRectangle rect in Rectangles) { sum += image.GetSumT(x + rect.ScaledX, y + rect.ScaledY, rect.ScaledWidth, rect.ScaledHeight) * rect.ScaledWeight; } } return sum; }
/// <summary> /// Detects the presence of an object in a given window. /// </summary> /// public bool Compute(IntegralImage2 image, Rectangle rectangle) { int x = rectangle.X; int y = rectangle.Y; int w = rectangle.Width; int h = rectangle.Height; double mean = image.GetSum(x, y, w, h) * invArea; double var = image.GetSum2(x, y, w, h) * invArea - (mean * mean); double sdev = (var >= 0) ? Math.Sqrt(var) : 1; // For each classification stage in the cascade foreach (HaarCascadeStage stage in cascade.Stages) { // Check if the stage has rejected the image if (stage.Classify(image, x, y, sdev) == false) { return false; // The image has been rejected. } } // If the object has gone all stages and has not // been rejected, the object has been detected. return true; // The image has been detected. }
/// <summary> /// Constructs a new Integral image from an unmanaged image. /// </summary> /// public static IntegralImage2 FromBitmap(UnmanagedImage image, int channel, bool computeTilted /*, TODO: Rectangle roi*/) { // check image format if (!(image.PixelFormat == PixelFormat.Format8bppIndexed || image.PixelFormat == PixelFormat.Format24bppRgb || image.PixelFormat == PixelFormat.Format32bppArgb)) { throw new UnsupportedImageFormatException("Only grayscale and 24 bpp RGB images are supported."); } int pixelSize = System.Drawing.Image.GetPixelFormatSize(image.PixelFormat) / 8; // get source image size int width = image.Width; int height = image.Height; int stride = image.Stride; int offset = stride - width * pixelSize; // create integral image IntegralImage2 im = new IntegralImage2(width, height, computeTilted); int* nSum = im.nSum, sSum = im.sSum, tSum = im.tSum; int nWidth = im.nWidth, nHeight = im.nHeight; int tWidth = im.tWidth, tHeight = im.tHeight; if (image.PixelFormat == PixelFormat.Format8bppIndexed && channel != 0) throw new ArgumentException("Only the first channel is available for 8 bpp images.", "channel"); byte* srcStart = (byte*)image.ImageData.ToPointer() + channel; // do the job byte* src = srcStart; // for each line for (int y = 1; y <= height; y++) { int yy = nWidth * (y); int y1 = nWidth * (y - 1); // for each pixel for (int x = 1; x <= width; x++, src += pixelSize) { int p1 = *src; int p2 = p1 * p1; int r = yy + (x); int a = yy + (x - 1); int b = y1 + (x); int c = y1 + (x - 1); nSum[r] = p1 + nSum[a] + nSum[b] - nSum[c]; sSum[r] = p2 + sSum[a] + sSum[b] - sSum[c]; } src += offset; } if (computeTilted) { src = srcStart; // Left-to-right, top-to-bottom pass for (int y = 1; y <= height; y++, src += offset) { int yy = tWidth * (y); int y1 = tWidth * (y - 1); for (int x = 2; x < width + 2; x++, src += pixelSize) { int a = y1 + (x - 1); int b = yy + (x - 1); int c = y1 + (x - 2); int r = yy + (x); tSum[r] = *src + tSum[a] + tSum[b] - tSum[c]; } } { int yy = tWidth * (height); int y1 = tWidth * (height + 1); for (int x = 2; x < width + 2; x++, src += pixelSize) { int a = yy + (x - 1); int c = yy + (x - 2); int b = y1 + (x - 1); int r = y1 + (x); tSum[r] = tSum[a] + tSum[b] - tSum[c]; } } // Right-to-left, bottom-to-top pass for (int y = height; y >= 0; y--) { int yy = tWidth * (y); int y1 = tWidth * (y + 1); for (int x = width + 1; x >= 1; x--) { int r = yy + (x); int b = y1 + (x - 1); tSum[r] += tSum[b]; } } for (int y = height + 1; y >= 0; y--) { int yy = tWidth * (y); for (int x = width + 1; x >= 2; x--) { int r = yy + (x); int b = yy + (x - 2); tSum[r] -= tSum[b]; } } } return im; }
/// <summary> /// Classifies an image as having the searched object or not. /// </summary> /// public bool Classify(IntegralImage2 image, int x, int y, double factor) { double value = 0; // For each feature in the feature tree of the current stage, foreach (HaarFeatureNode[] tree in Trees) { int current = 0; do { // Get the feature node from the tree HaarFeatureNode node = tree[current]; // Evaluate the node's feature double sum = node.Feature.GetSum(image, x, y); // And increase the value accumulator if (sum < node.Threshold * factor) { value += node.LeftValue; current = node.LeftNodeIndex; } else { value += node.RightValue; current = node.RightNodeIndex; } } while (current > 0); // Stop early if we have already surpassed the stage threshold value. //if (value > this.Threshold) return true; } // After we have evaluated the output for the // current stage, we will check if the value // is still lesser than the stage threshold. if (value < this.Threshold) { // If it is, the stage has rejected the current // image and it doesn't contains our object. return false; } else { // The stage has accepted the current image return true; } }
/// <summary> /// Constructs a new Integral image from an unmanaged image. /// </summary> /// public static IntegralImage2 FromBitmap(UnmanagedImage image, int channel, bool computeTilted /*, TODO: Rectangle roi*/) { // check image format if (!(image.PixelFormat == PixelFormat.Format8bppIndexed || image.PixelFormat == PixelFormat.Format24bppRgb || image.PixelFormat == PixelFormat.Format32bppArgb)) { throw new UnsupportedImageFormatException("Only grayscale and 24 bpp RGB images are supported."); } int pixelSize = System.Drawing.Image.GetPixelFormatSize(image.PixelFormat) / 8; // get source image size int width = image.Width; int height = image.Height; int stride = image.Stride; int offset = stride - width * pixelSize; // create integral image IntegralImage2 im = new IntegralImage2(width, height, computeTilted); int * nSum = im.nSum, sSum = im.sSum, tSum = im.tSum; int nWidth = im.nWidth, nHeight = im.nHeight; int tWidth = im.tWidth, tHeight = im.tHeight; if (image.PixelFormat == PixelFormat.Format8bppIndexed && channel != 0) { throw new ArgumentException("Only the first channel is available for 8 bpp images.", "channel"); } byte *srcStart = (byte *)image.ImageData.ToPointer() + channel; // do the job byte *src = srcStart; // for each line for (int y = 1; y <= height; y++) { int yy = nWidth * (y); int y1 = nWidth * (y - 1); // for each pixel for (int x = 1; x <= width; x++, src += pixelSize) { int p1 = *src; int p2 = p1 * p1; int r = yy + (x); int a = yy + (x - 1); int b = y1 + (x); int c = y1 + (x - 1); nSum[r] = p1 + nSum[a] + nSum[b] - nSum[c]; sSum[r] = p2 + sSum[a] + sSum[b] - sSum[c]; } src += offset; } if (computeTilted) { src = srcStart; // Left-to-right, top-to-bottom pass for (int y = 1; y <= height; y++, src += offset) { int yy = tWidth * (y); int y1 = tWidth * (y - 1); for (int x = 2; x < width + 2; x++, src += pixelSize) { int a = y1 + (x - 1); int b = yy + (x - 1); int c = y1 + (x - 2); int r = yy + (x); tSum[r] = *src + tSum[a] + tSum[b] - tSum[c]; } } { int yy = tWidth * (height); int y1 = tWidth * (height + 1); for (int x = 2; x < width + 2; x++, src += pixelSize) { int a = yy + (x - 1); int c = yy + (x - 2); int b = y1 + (x - 1); int r = y1 + (x); tSum[r] = tSum[a] + tSum[b] - tSum[c]; } } // Right-to-left, bottom-to-top pass for (int y = height; y >= 0; y--) { int yy = tWidth * (y); int y1 = tWidth * (y + 1); for (int x = width + 1; x >= 1; x--) { int r = yy + (x); int b = y1 + (x - 1); tSum[r] += tSum[b]; } } for (int y = height + 1; y >= 0; y--) { int yy = tWidth * (y); for (int x = width + 1; x >= 2; x--) { int r = yy + (x); int b = yy + (x - 2); tSum[r] -= tSum[b]; } } } return(im); }