/// <summary>
/// Performs object detection on the given frame.
/// </summary>
///
public Rectangle[] ProcessFrame(UnmanagedImage image, Action <string> logInfo)
{
int colorChannel =
image.PixelFormat == PixelFormat.Format8bppIndexed ? 0 : channel;
// Creates an integral image representation of the frame
if (integralImage == null || integralImage.Width != image.Width || integralImage.Height != image.Height)
{
integralImage = IntegralImage2.FromBitmap(image, colorChannel, classifier.Cascade.HasTiltedFeatures);
}
else
{
integralImage.Update(image, colorChannel);
}
// 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 ConcurrentBag <Rectangle>();
int numSteps = (int)Math.Ceiling((double)yEnd / yStep);
Exception parallelException = null;
// For each pixel in the window column
Parallel.For(0, numSteps, (j, options) =>
{
try
{
ProcessWindows(j, options, window, xStep, yStep, xEnd, bag);
}
catch (Exception ex)
{
if (logInfo != null)
{
logInfo($"Exception in HaarObjectDetector: {ex.Message}");
}
parallelException = ex;
options.Stop();
}
});
if (parallelException != null)
{
goto EXIT;
}
// 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.
}