private CentralMoments meanShift(UnmanagedImage frame)
{
// Variable initialization
int width = frame.Width;
int height = frame.Height;
// (assume all frames have equal dimensions)
if (map == null) map = new float[height, width];
// Grab the current region of interest in the current frame
Rectangle roi = conservative ? searchWindow : new Rectangle(0, 0, frame.Width, frame.Height);
// Compute the histogram for the current frame
float[] currentHistogram = createHistogram(frame, roi);
// Use the previous histogram to compute a ratio histogram (storing in current)
computeHistogramRatio(originalHistogram, currentHistogram, currentHistogram);
// Compute the back-projection map using the ratio histogram
lock (sync) generateBackprojectionMap(frame, currentHistogram);
RawMoments moments = new RawMoments(1);
// Mean shift with fixed number of iterations
for (int i = 0; i < MAX_ITERATIONS - 1; i++)
{
// Locate first order moments
moments.Compute(map, searchWindow);
// Shift the mean (centroid)
searchWindow.X += (int)(moments.CenterX - searchWindow.Width / 2f);
searchWindow.Y += (int)(moments.CenterY - searchWindow.Height / 2f);
}
// Locate second order moments and perform final shift
moments.Order = 2; moments.Compute(map, searchWindow);
searchWindow.X += (int)(moments.CenterX - searchWindow.Width / 2f);
searchWindow.Y += (int)(moments.CenterY - searchWindow.Height / 2f);
// Keep the search window inside the image
searchWindow.X = Math.Max(0, Math.Min(searchWindow.X, width));
searchWindow.Y = Math.Max(0, Math.Min(searchWindow.Y, height));
return new CentralMoments(moments); // moments to be used by Camshift
}