public Rectangle[] ProcessFrame(UnmanagedImage image)
{
int colorChannel =
image.PixelFormat == PixelFormat.Format8bppIndexed ? 0 : channel;
// Creates an integral image representation of the frame
IntegralImage2 integralImage = IntegralImage2.FromBitmap(
image, colorChannel, classifier.Cascade.HasTiltedFeatures);
// Creates a new list of detected objects.
this.detectedObjects.Clear();
int width = integralImage.Width;
int height = integralImage.Height;
// Update parameters only if different size
if (steps == null || width != lastWidth || height != lastHeight)
update(width, height);
Rectangle window = Rectangle.Empty;
// For each scaling step
for (int i = 0; i < steps.Length; i++)
{
float scaling = steps[i];
// Set the classifier window scale
classifier.Scale = scaling;
// Get the scaled window size
window.Width = (int)(baseWidth * scaling);
window.Height = (int)(baseHeight * scaling);
// Check if the window is lesser than the minimum size
if (window.Width < minSize.Width || window.Height < minSize.Height)
{
// If we are searching in greater to smaller mode,
if (scalingMode == ObjectDetectorScalingMode.GreaterToSmaller)
{
goto EXIT; // it won't get bigger, so we should stop.
}
else continue; // continue until it gets greater.
}
// Check if the window is greater than the maximum size
else if (window.Width > maxSize.Width || window.Height > maxSize.Height)
{
// If we are searching in greater to smaller mode,
if (scalingMode == ObjectDetectorScalingMode.GreaterToSmaller)
{
continue; // continue until it gets smaller.
}
else goto EXIT; // it won't get smaller, so we should stop. }
}
// Grab some scan loop parameters
int xStep = window.Width >> 3;
int yStep = window.Height >> 3;
int xEnd = width - window.Width;
int yEnd = height - window.Height;
if (!parallel) // Check if we should run in parallel
{
// Sequential mode. Scan the integral image searching
// for objects in the window without parallelization.
// For every pixel in the window column
for (int y = 0; y < yEnd; y += yStep)
{
window.Y = y;
// For every pixel in the window row
for (int x = 0; x < xEnd; x += xStep)
{
window.X = x;
if (searchMode == ObjectDetectorSearchMode.NoOverlap && overlaps(window))
continue; // We have already detected something here, moving along.
// Try to detect an object inside the window
if (classifier.Compute(integralImage, window))
{
// object has been detected
detectedObjects.Add(window);
if (searchMode == ObjectDetectorSearchMode.Single)
goto EXIT; // stop on first object found
}
}
}
}
#if !NET35
else // use parallel processing
{
// Parallel mode. Scan the integral image searching
// for objects in the window with parallelization.
var bag = new System.Collections.Concurrent.ConcurrentBag<Rectangle>();
int numSteps = (int)Math.Ceiling((double)yEnd / yStep);
// For each pixel in the window column
Parallel.For(0, numSteps, (j, options) =>
{
int y = j * yStep;
// Create a local window reference
Rectangle localWindow = window;
localWindow.Y = y;
// For each pixel in the window row
for (int x = 0; x < xEnd; x += xStep)
{
if (options.ShouldExitCurrentIteration) return;
localWindow.X = x;
// Try to detect and object inside the window
if (classifier.Compute(integralImage, localWindow))
{
// an object has been detected
bag.Add(localWindow);
if (searchMode == ObjectDetectorSearchMode.Single)
options.Stop();
}
}
});
// If required, avoid adding overlapping objects at
// the expense of extra computation. Otherwise, only
// add objects to the detected objects collection.
if (searchMode == ObjectDetectorSearchMode.NoOverlap)
{
foreach (Rectangle obj in bag)
if (!overlaps(obj)) detectedObjects.Add(obj);
}
else if (searchMode == ObjectDetectorSearchMode.Single)
{
if (bag.TryPeek(out window))
{
detectedObjects.Add(window);
goto EXIT;
}
}
else
{
foreach (Rectangle obj in bag)
detectedObjects.Add(obj);
}
}
#endif
}
EXIT:
Rectangle[] objects = detectedObjects.ToArray();
if (searchMode == ObjectDetectorSearchMode.Average)
objects = match.Group(objects);
checkSteadiness(objects);
lastObjects = objects;
return objects; // Returns the array of detected objects.
}