How to implement motion detector using C#

This article demonstrates how to implement and configure a Motion Detector for the purpose to detect moving objects on input videos. Please note that, before you begin to develop your own application, you have to add reference to ozeki.dll.

What is Motion Detector? When does it needed?

A motion detector is a device that detects moving objects, particularly people. A motion detector is often integrated as a component of a system that automatically performs a task or alerts a user of motion in an area.

Motion detectors have found wide use in domestic and commercial applications. One common everyday application is activation of automatic door openers in businesses and public buildings. Motion sensors are also widely used in lieu of a true occupancy sensor in activating street lights or indoor lights in walkways (such as lobbies and staircases).
A motion detector may be among the sensors of a burglar alarm that is used to alert the home owner or security service when it detects the motion of a possible intruder. Such a detector may also trigger a red light camera in put to work order to record the possible intrusion.

How to develop Motion Detector in C#?

Ozeki VoIP SIP SDK provides a mediahandler, called MotionDetectorHandler for the purpose to detect motion on input videos. This media handler is able to receive and send the video data, which means it can forward the input video after processing that.
The detector's sensitivy is configurable, and with the SDK it's also possible to send instant messages or e-mails, make calls etc. when motion is being detected.

graphical user interface for a motion detector application
Figure 1 - Example Graphical User Interface for a motion detector application

MotionDetectorHandler can receive video data from any mediahandlers which implement the IVideoSender interface (WebCamera, AVPlayer, IPCamera etc.), and is able to send video data to any mediahandlers, which implement the IVideoReceiver interface (DrawingImageProvider, MPEG4Recorder etc.). To define these connections, you have to use the MediaConnector, provided by Ozeki VoIP SIP SDK, for example:

_connector.Connect(_videoPlayer.VideoPlayer, _detector);
_connector.Connect(_detector, _imageProvider);

As the code snippet shows above, the _videoPlayer's video channel is being connected to the _detector object, and than the _detector is being connected to the _imageProvider instance.

The MotionDetectorHandler provides the opportunity to configure it's sensitivy, choose from highlighting modes, select a color for highlighting, subscribe to an event, which indicates when there is a detected moving object and more.

How to configure the MotionDetectorHandler?

A MotionDetectorHandler instance can be configured through its properties. These properties have their default values, but since the success of detection depends on these parameters, it might needs some configuration for the correct results.
The detection is depends on the following properties:

  • PixelIntensitySensitivy: the detector is calculating on greyscale images, so the intensity of a single pixel can be between 0 and 255. When it is processing two frames, this property sets that how much difference should be found between two frames on the same position (pixel) to be recognized as a possible part of a moving object.
    Default value is 30 as integer.
  • PixelAmountSensitivy: defines that how many pixeles should be detected as moving object parts to recognize motion.
    Default value is 0.3 as double, which means 30% difference between two frames.
  • DetectionFPS: defines that how many frames should be checked per seconds.
    Default value is 5 as integer.

MotionDetectorHandler also provides the opportunity to highlight the detected moving object(s). The mode of highlighting can be set through the HighlightMotin property, and there are 3 modes of that:

  • HighlightMotion.None: no highlight is being applied. Recommended for slover systems or slower network connection (in case of receivin/sending through network), since the received media data is not being modified.
  • HighlightMotion.DrawAround: draws around the detected object with the set color.
  • HighlightMotion.Highlight: fills the detected object with the selected color.

For highlighting moving object, you can set the color which will be used to indicate that object by the MotionColor property; it can be set through the MotionColor enum, and can be Red, Green and Blue.

How to get notified when motion has been detected?

MotionDetectorHandler has an event for the purpose to indicate motions' beginings and endings. This event is called MotionDetection. The event's argument carries the information whether the motion is starting or ending, for example:

_detector.MotionDetection += _detector_MotionDetection;

void _detector_MotionDetection(object sender, MotionDetectionEvent e)
{
    if (e.Detection)
    {
        _motionCount++;

        InvokeGuiThread(() => { lbl_MotionCount.Text = _motionCount.ToString(); });

        panel_MotionIndicator.BackColor = _color;
    }
    else
        panel_MotionIndicator.BackColor = Color.Gray;
}

If the value of e.Detection is true, than the motion is just beginning. If the value is false, than it is ending. In this example, _motionCount is an integer value which stores the amount of detected motions, InvokeGuiThread is a helper method which solves thread blockings, and the panel_MotionIndicator is a simple panel which changes its color to indicate motions.

Motion Detector application in C#

Please note that, in order to work with the following code, you have to:

  • add reference to ozeki.dll
  • create a Windows Forms application with a GUI and rename the objects as they are used in the source code
  • you have to provide a "video.mp4" file in order to be able run the detector on something
using System;
using System.Drawing;
using System.Windows.Forms;
using Ozeki.Media.MediaHandlers;
using Ozeki.Media.MediaHandlers.Video;
using Ozeki.Media.Video.Controls;

namespace MotionDetector
{
    public partial class MotionDetectorForm : Form
    {
        DrawingImageProvider _imageProvider;
        VideoViewerWF _videoViewer;

        MotionDetectorHandler _detector;

        MediaConnector _connector;

        AVPlayer _videoPlayer;

        Color _color;

        int _motionCount;

        public MotionDetectorForm()
        {
            InitializeComponent();
        }

        void MotionDetectorForm_Load(object sender, EventArgs e)
        {
            _imageProvider = new DrawingImageProvider();
            _videoViewer = new VideoViewerWF();
            _connector = new MediaConnector();
            _detector = new MotionDetectorHandler();

            // subscribes to the event, which indicates when motions are being detected
            _detector.MotionDetection += _detector_MotionDetection;

            _color = Color.Red;

            // the videoplayer is being set, it will play the "video.mp4" file when being started
            _videoPlayer = new AVPlayer("video.mp4");

            SetVideoViewer();

            // connects the input video to the detector
            _connector.Connect(_videoPlayer.VideoPlayer, _detector);

            // connects the detector to the output
            _connector.Connect(_detector, _imageProvider);

            _videoViewer.SetImageProvider(_imageProvider);

            // fills the ComboBox with the available colors
            cmb_DrawColor.DataSource = Enum.GetValues(typeof(MotionColor));
        }

        // occurrs, when motion is being detected or the detected motion ends
        void _detector_MotionDetection(object sender, MotionDetectionEvent e)
        {
            // stores if the event indicates the beginning or the ending of the motion
            if (e.Detection)
            {
                // increments the counter of detected motions
                _motionCount++;

                InvokeGuiThread(() => { lbl_MotionCount.Text = _motionCount.ToString(); });

                // indicates the motion within a simple panel
                panel_MotionIndicator.BackColor = _color;
            }
            else
                panel_MotionIndicator.BackColor = Color.Gray;
        }

        // sets the VideoViewerWF object programmatically
        void SetVideoViewer()
        {
            _videoViewer.Location = new Point(10, 10);
            _videoViewer.Size = new Size(375, 300);
            _videoViewer.BackColor = Color.Black;
            _videoViewer.TabStop = false;

            Controls.Add(_videoViewer);
        }

        // plays the video
        void btn_Play_Click(object sender, EventArgs e)
        {
            _videoViewer.Start();
            _videoPlayer.Start();
        }

        #region Detector

        void btn_Detect_Click(object sender, EventArgs e)
        {
            // _detector.IsRunning indicates if the MotionDetectorHandler is currently detecting or not
            if (!_detector.IsRunning)
            {
                // starts the detector
                _detector.Start();

                btn_Detect.Text = "Stop";
            }
            else
            {
                // stops the detector
                _detector.Stop();

                btn_Detect.Text = "Start";

                panel_MotionIndicator.BackColor = Color.Gray;
            }
        }

        // when the ComboBox of MotionColors is being set, it sets the detector's MotionColor property
        void cmb_DrawColor_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (cmb_DrawColor.SelectedIndex)
            {
                case 0:
                    _detector.MotionColor = MotionColor.Red;
                    _color = Color.DarkRed;
                    break;
                case 1:
                    _detector.MotionColor = MotionColor.Green;
                    _color = Color.DarkGreen;
                    break;
                case 2:
                    _detector.MotionColor = MotionColor.Blue;
                    _color = Color.Blue;
                    break;
                default:
                    _detector.MotionColor = MotionColor.Red;
                    _color = Color.DarkRed;
                    break;
            }
        }

        void InvokeGuiThread(Action action)
        {
            Invoke(action);
        }

        void btn_MotionIntensity_Click(object sender, EventArgs e)
        {
            // how much difference should be found between two frames
            //on the same position (pixel) to be recognized as a possible part of a moving object.
            _detector.PixelIntensitySensitivy = Int32.Parse(tb_MotionIntensity.Text);
        }

        void btn_MotionAmount_Click(object sender, EventArgs e)
        {
            // how many pixeles should be detected as moving object parts to recognize motion
            _detector.PixelAmountSensitivy = Int32.Parse(tb_MotionAmount.Text);
        }

        void btn_MotionFrame_Click(object sender, EventArgs e)
        {
            // how many frames should be checked per seconds
            _detector.DetectionFPS = Int32.Parse(tb_MotionFrames.Text);
        }

        void radio_NoDraw_CheckedChanged(object sender, EventArgs e)
        {
            // sets the mode of highlighting
            _detector.HighlightMotion = HighlightMotion.None;
        }

        void radio_Draw_CheckedChanged(object sender, EventArgs e)
        {
            _detector.HighlightMotion = HighlightMotion.DrawAround;
        }

        void radio_HighLight_CheckedChanged(object sender, EventArgs e)
        {
            _detector.HighlightMotion = HighlightMotion.Highlight;
        }

        void btn_ResetCounter_Click(object sender, EventArgs e)
        {
            // resets the motion counter
            _motionCount = 0;
            InvokeGuiThread(() => { lbl_MotionCount.Text = _motionCount.ToString(); });
        }

        #endregion

    }
}

Related Pages

More information