www.pudn.com > motion.zip > MotionDetector3Optimized.cs
// Copyright © Andrew Kirillov, 2005
// andrew.kirillov@gmail.com
//
namespace motion
{
using System;
using System.Drawing;
using System.Drawing.Imaging;
using Tiger.Imaging;
using Tiger.Imaging.Filters;
///
/// MotionDetector3Optimized
///
public class MotionDetector3Optimized : IMotionDetector
{
private byte[] backgroundFrame = null;
private byte[] currentFrame = null;
private byte[] currentFrameDilatated = null;
private int counter = 0;
// Constructor
public MotionDetector3Optimized()
{
}
// Reset detector to initial state
public void Reset()
{
backgroundFrame = null;
currentFrame = null;
currentFrameDilatated = null;
counter = 0;
}
// Process new frame
public void ProcessFrame(ref Bitmap image)
{
int width = image.Width;
int height = image.Height;
int fW = (((width - 1) / 8) + 1);
int fH = (((height - 1) / 8) + 1);
int len = fW * fH;
if (backgroundFrame == null)
{
// alloc memory for a backgound image and for current image
backgroundFrame = new byte[len];
currentFrame = new byte[len];
currentFrameDilatated = new byte[len];
// lock image
BitmapData imgData = image.LockBits(
new Rectangle(0, 0, width, height),
ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
// create initial backgroung image
PreprocessInputImage(imgData, width, height, backgroundFrame);
// unlock the image
image.UnlockBits(imgData);
// just return for the first time
return;
}
// lock image
BitmapData data = image.LockBits(
new Rectangle(0, 0, width, height),
ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
// preprocess input image
PreprocessInputImage(data, width, height, currentFrame);
if (++counter == 2)
{
counter = 0;
// move background towards current frame
for (int i = 0; i < len; i++)
{
int t = currentFrame[i] - backgroundFrame[i];
if (t > 0)
backgroundFrame[i]++;
else if (t < 0)
backgroundFrame[i]--;
}
}
// difference and thresholding
for (int i = 0; i < len; i++)
{
int t = currentFrame[i] - backgroundFrame[i];
if (t < 0)
t = -t;
currentFrame[i] = (t >= 15) ? (byte) 255 : (byte) 0;
}
// dilatation analogue for borders extending
// it can be skipped
for (int i = 0; i < fH; i++)
{
for (int j = 0; j < fW; j++)
{
int k = i * fW + j;
int v = currentFrame[k];
// left pixels
if (j > 0)
{
v += currentFrame[k - 1];
if (i > 0)
{
v += currentFrame[k - fW - 1];
}
if (i < fH - 1)
{
v += currentFrame[k + fW - 1];
}
}
// right pixels
if (j < fW - 1)
{
v += currentFrame[k + 1];
if (i > 0)
{
v += currentFrame[k - fW + 1];
}
if (i < fH - 1)
{
v += currentFrame[k + fW + 1];
}
}
// top pixel
if (i > 0)
{
v += currentFrame[k - fW];
}
// right pixel
if (i < fH - 1)
{
v += currentFrame[k + fW];
}
currentFrameDilatated[k] = (v != 0) ? (byte) 255 : (byte) 0;
}
}
// postprocess the input image
PostprocessInputImage(data, width, height, currentFrameDilatated);
// unlock the image
image.UnlockBits(data);
}
// Preprocess input image
private void PreprocessInputImage(BitmapData data, int width, int height, byte[] buf)
{
int stride = data.Stride;
int offset = stride - width * 3;
int len = (int)((width - 1) / 8) + 1;
int rem = ((width - 1) % 8) + 1;
int[] tmp = new int[len];
int i, j, t1, t2, k = 0;
unsafe
{
byte * src = (byte *) data.Scan0.ToPointer();
for (int y = 0; y < height; )
{
// collect pixels
Array.Clear(tmp, 0, len);
// calculate
for (i = 0; (i < 8) && (y < height); i++, y++)
{
// for each pixel
for (int x = 0; x < width; x++, src += 3)
{
// grayscale value using BT709
tmp[(int) (x / 8)] += (int)(0.2125f * src[RGB.R] + 0.7154f * src[RGB.G] + 0.0721f * src[RGB.B]);
}
src += offset;
}
// get average values
t1 = i * 8;
t2 = i * rem;
for (j = 0; j < len - 1; j++, k++)
buf[k] = (byte)(tmp[j] / t1);
buf[k++] = (byte)(tmp[j] / t2);
}
}
}
// Postprocess input image
private void PostprocessInputImage(BitmapData data, int width, int height, byte[] buf)
{
int stride = data.Stride;
int offset = stride - width * 3;
int len = (int)((width - 1) / 8) + 1;
int lenWM1 = len - 1;
int lenHM1 = (int)((height - 1) / 8);
int rem = ((width - 1) % 8) + 1;
int i, j, k;
unsafe
{
byte * src = (byte *) data.Scan0.ToPointer();
// for each line
for (int y = 0; y < height; y++)
{
i = (y / 8);
// for each pixel
for (int x = 0; x < width; x++, src += 3)
{
j = x / 8;
k = i * len + j;
// check if we need to highlight moving object
if (buf[k] == 255)
{
// check for border
if (
((x % 8 == 0) && ((j == 0) || (buf[k - 1] == 0))) ||
((x % 8 == 7) && ((j == lenWM1) || (buf[k + 1] == 0))) ||
((y % 8 == 0) && ((i == 0) || (buf[k - len] == 0))) ||
((y % 8 == 7) && ((i == lenHM1) || (buf[k + len] == 0)))
)
{
src[RGB.R] = 255;
}
}
}
src += offset;
}
}
}
}
}