public void ProcessFrame( UnmanagedImage videoFrame )
{
lock ( sync )
{
// check background frame
if ( backgroundFrame == null )
{
lastTimeMeasurment = DateTime.Now;
// save image dimension
width = videoFrame.Width;
height = videoFrame.Height;
// alocate memory for previous and current frames
backgroundFrame = UnmanagedImage.Create( width, height, PixelFormat.Format8bppIndexed );
motionFrame = UnmanagedImage.Create( width, height, PixelFormat.Format8bppIndexed );
frameSize = motionFrame.Stride * height;
// temporary buffer
if ( suppressNoise )
{
tempFrame = UnmanagedImage.Create( width, height, PixelFormat.Format8bppIndexed );
}
// convert source frame to grayscale
Accord.Vision.Tools.ConvertToGrayscale(videoFrame, backgroundFrame);
return;
}
// check image dimension
if ( ( videoFrame.Width != width ) || ( videoFrame.Height != height ) )
return;
// convert current image to grayscale
Accord.Vision.Tools.ConvertToGrayscale(videoFrame, motionFrame);
unsafe
{
// pointers to background and current frames
byte* backFrame;
byte* currFrame;
int diff;
// update background frame
if ( millisecondsPerBackgroundUpdate == 0 )
{
// update background frame using frame counter as a base
if ( ++framesCounter == framesPerBackgroundUpdate )
{
framesCounter = 0;
backFrame = (byte*) backgroundFrame.ImageData.ToPointer( );
currFrame = (byte*) motionFrame.ImageData.ToPointer( );
for ( int i = 0; i < frameSize; i++, backFrame++, currFrame++ )
{
diff = *currFrame - *backFrame;
if ( diff > 0 )
{
( *backFrame )++;
}
else if ( diff < 0 )
{
( *backFrame )--;
}
}
}
}
else
{
// update background frame using timer as a base
// get current time and calculate difference
DateTime currentTime = DateTime.Now;
TimeSpan timeDff = currentTime - lastTimeMeasurment;
// save current time as the last measurment
lastTimeMeasurment = currentTime;
int millisonds = (int) timeDff.TotalMilliseconds + millisecondsLeftUnprocessed;
// save remainder so it could be taken into account in the future
millisecondsLeftUnprocessed = millisonds % millisecondsPerBackgroundUpdate;
// get amount for background update
int updateAmount = (int) ( millisonds / millisecondsPerBackgroundUpdate );
backFrame = (byte*) backgroundFrame.ImageData.ToPointer( );
currFrame = (byte*) motionFrame.ImageData.ToPointer( );
for ( int i = 0; i < frameSize; i++, backFrame++, currFrame++ )
{
diff = *currFrame - *backFrame;
if ( diff > 0 )
{
( *backFrame ) += (byte) ( ( diff < updateAmount ) ? diff : updateAmount );
}
else if ( diff < 0 )
{
( *backFrame ) += (byte) ( ( -diff < updateAmount ) ? diff : -updateAmount );
}
}
}
backFrame = (byte*) backgroundFrame.ImageData.ToPointer( );
currFrame = (byte*) motionFrame.ImageData.ToPointer( );
// 1 - get difference between frames
// 2 - threshold the difference
for ( int i = 0; i < frameSize; i++, backFrame++, currFrame++ )
{
// difference
diff = (int) *currFrame - (int) *backFrame;
// treshold
*currFrame = ( ( diff >= differenceThreshold ) || ( diff <= differenceThresholdNeg ) ) ? (byte) 255 : (byte) 0;
}
if ( suppressNoise )
{
// suppress noise and calculate motion amount
Accord.SystemTools.CopyUnmanagedMemory( tempFrame.ImageData, motionFrame.ImageData, frameSize );
erosionFilter.Apply( tempFrame, motionFrame );
if ( keepObjectEdges )
{
Accord.SystemTools.CopyUnmanagedMemory( tempFrame.ImageData, motionFrame.ImageData, frameSize );
dilatationFilter.Apply( tempFrame, motionFrame );
}
}
// calculate amount of motion pixels
pixelsChanged = 0;
byte* motion = (byte*) motionFrame.ImageData.ToPointer( );
for ( int i = 0; i < frameSize; i++, motion++ )
{
pixelsChanged += ( *motion & 1 );
}
}
}
}