Motion Detection (This application I've created is free to anyone to use)

Rythorian

RYTHORIAN
Joined
Nov 5, 2024
Messages
54
Programming Experience
5-10

Motion Detection:​

This application is designed for motion detection using video input devices. The application captures video frames, processes them to detect motion. The detected motion will be highlighted in red. It is a practical implementation of video processing and motion detection techniques, leveraging the AForge.NET framework. I do have a few bugs to work out, when motion is detected, a system beep is supposed to occur, if I can figure this out I would be grateful.

Main Concepts To Understand:​

The application utilizes several key concepts:

Video Capture: It captures video from available input devices (cameras).
Motion Detection: It processes video frames to identify motion using a motion detector.
User Interface: It provides a graphical user interface (GUI) for user interaction, allowing users to select cameras and start/stop motion detection.
Timers: It employs timers to manage periodic actions, such as sound alerts when motion is detected.

Structuring Of Code:​

Several components to consider:

Imports: Necessary libraries from AForge.NET for video processing and motion detection.
Class Definition: The main class Form1 contains all the logic for the application.
Variables: It declares variables for video devices, motion detection, and UI elements.
Event Handlers: It includes event handlers for form loading, button clicks, and frame processing.

This app effectively demonstrates the integration of video processing and user interaction. By utilizing the AForge.NET framework, it captures video, detects motion, and provides real-time feedback to the user.
Motion Detection:
REM: Created by: Justin Linwood Ross | Creation Date: 4/29/25 11:30 AM | Last Modified: 4/30/25 5:30 PM | Github: rythorian77
Imports System.Media ' For playing system sounds
Imports AForge.Video ' For video processing
Imports AForge.Video.DirectShow ' For accessing video capture devices
Imports AForge.Vision.Motion ' For MessageBox, Timer, PictureBox, Label, ComboBox, Button, FormClosingEventArgs


Public Class Form1

#Region "Variable Declarations"
    ' Declare variables for video devices and video source
    Private videoDevices As FilterInfoCollection ' Collection of video input devices
    Private videoSource As VideoCaptureDevice ' The video capture device selected by the user
    Private Const MinimumMotionScore As Double = 0.005 ' This score is compared against motionDetector.MotionLevel to determine if motion is detected

    ' Declare a timer for periodic beeping when motion is detected
    Private WithEvents BeepTimer As New Timer() ' Timer object to trigger periodic beeping
    ' Changed beep interval to 3000 ms (3 seconds)
    Private Const BeepIntervalMs As Integer = 3000 ' Interval in milliseconds between each beep

    ' Added constant for the difference threshold in motion detection
    ' Adjust this value (0-255) - lower is more sensitive
    Private Const DifferenceThreshold As Integer = 10 ' Threshold for detecting differences between frames

    Private motionDetector As MotionDetector ' Motion detector object to process video frames
#End Region

#Region "Form Event Handlers"
    ' Event handler for form load
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' Set the interval for the beep timer
        BeepTimer.Interval = BeepIntervalMs
        ' Add event handler for the beep timer tick event
        AddHandler BeepTimer.Tick, AddressOf BeepTimer_Tick

        Try
            ' Get the collection of video input devices
            videoDevices = New FilterInfoCollection(FilterCategory.VideoInputDevice)

            ' Check if any video devices are found
            If videoDevices.Count = 0 Then
                ' Show an error message if no video devices are found
                MessageBox.Show("No video input devices found.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
                ' Disable the start button since no devices are available
                btnStart.Enabled = False
                ' Update the status label to indicate no devices are found
                UpdateStatusLabel("No video input devices found.", Color.Red)
            Else
                ' If video devices are found, add their names to the combo box
                For Each device As FilterInfo In videoDevices
                    cboCameras.Items.Add(device.Name)
                Next

                ' Set the default selected camera to the first one in the list
                cboCameras.SelectedIndex = 0
                ' Enable the start button
                btnStart.Enabled = True
                ' Disable the stop button (since the camera is not started yet)
                btnStop.Enabled = False
                ' Enable the camera combo box for camera selection
                cboCameras.Enabled = True
                ' Update the status label to prompt the user to select a camera and start it
                UpdateStatusLabel("Select camera and press Start.", SystemColors.ControlText)
            End If

        Catch ex As Exception
            ' Handle any exceptions that occur during video device enumeration
            MessageBox.Show("Error enumerating video devices: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            ' Disable the start and stop buttons, and the camera combo box
            btnStart.Enabled = False
            btnStop.Enabled = False
            cboCameras.Enabled = False
            ' Update the status label to indicate an error during initialization
            UpdateStatusLabel("Error initializing.", Color.Red)
        End Try
    End Sub

    ' Event handler for form closing
    Private Sub MainForm_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
        ' Ensure the camera is stopped when the form is closing
        StopCamera()
    End Sub

    ' Event handler for form shown event
    Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
        ' Set the size mode of the picture box to zoom when the form is shown
        pbCameraFeed.SizeMode = PictureBoxSizeMode.Zoom
    End Sub

    ' Event handler for the picture box resize event
    Private Sub PbCameraFeed_Resize(sender As Object, e As EventArgs) Handles pbCameraFeed.Resize
        ' Set the size mode of the picture box to zoom to fit the new size
        pbCameraFeed.SizeMode = PictureBoxSizeMode.Zoom
    End Sub
#End Region

#Region "Button Click Handlers"
    ' Event handler for the start button click
    Private Sub BtnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
        ' Check if a camera has been selected
        If cboCameras.SelectedItem Is Nothing Then
            ' Show a warning message if no camera is selected
            MessageBox.Show("Please select a camera.", "Selection Error", MessageBoxButtons.OK, MessageBoxIcon.Warning)
            ' Update the status label to indicate no camera is selected
            UpdateStatusLabel("Please select a camera.", Color.OrangeRed)
            ' Return without starting the camera
            Return
        End If

        Try
            ' Initialize the video source with the selected camera's moniker string
            videoSource = New VideoCaptureDevice(videoDevices(cboCameras.SelectedIndex).MonikerString)
            ' Add event handler for the new frame event
            AddHandler videoSource.NewFrame, AddressOf VideoSource_NewFrame
            ' Start the video source (camera)
            videoSource.Start()

            ' Initialize the motion detector with the specified DifferenceThreshold
            ' TwoFramesDifferenceDetector is used to compare the current frame with the previous one
            ' MotionBorderHighlighting is used to highlight the motion detected area in the frame
            motionDetector = New MotionDetector(New TwoFramesDifferenceDetector(DifferenceThreshold), New MotionBorderHighlighting())

            ' Disable the start button after starting the camera
            btnStart.Enabled = False
            ' Enable the stop button to allow stopping the camera
            btnStop.Enabled = True
            ' Disable the camera combo box while the camera is running
            cboCameras.Enabled = False
            ' Update the status label to indicate that motion detection has started
            UpdateStatusLabel("Processing Motion...", SystemColors.ControlText)
            ' Stop the beep timer if it was running
            BeepTimer.Stop()
        Catch ex As Exception
            ' Handle any exceptions that occur during initialization
            MessageBox.Show("Error starting camera: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            ' Disable the start button
            btnStart.Enabled = False
            ' Disable the stop button
            btnStop.Enabled = False
            ' Enable the camera combo box for user to make a selection
            cboCameras.Enabled = True
            ' Update the status label to indicate an error during initialization
            UpdateStatusLabel("Error initializing camera.", Color.Red)
        End Try
    End Sub

    ' Event handler for the stop button click
    Private Sub BtnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click
        ' Call the StopCamera subroutine to stop the video source and reset UI elements
        StopCamera()
    End Sub
#End Region

#Region "Video Source Event Handlers"
    ' Event handler for new frames captured by the video source
    Private Sub VideoSource_NewFrame(sender As Object, eventArgs As NewFrameEventArgs)
        ' Clone the current frame to avoid issues with the frame being used by the video source
        Dim currentFrame As Bitmap = eventArgs.Frame.Clone()
        ' Variable to store the motion score of the current frame
        ' The motion score is a property of the motion detector after processing
        Dim motionScore As Double = 0.0

        Try
            ' Check if motion detector is initialized
            If motionDetector IsNot Nothing Then
                ' Process the current frame to detect motion and get the motion level
                ' The ProcessFrame method returns a boolean indicating if motion was detected,
                ' and the motion level is stored in the MotionLevel property.
                motionDetector.ProcessFrame(currentFrame)

                ' Check if the motion score meets or exceeds the minimum motion score threshold
                If motionScore >= MinimumMotionScore Then
                    ' Motion detected: Update status and manage beeping
                    UpdateStatusLabel($"MOTION DETECTED! ({motionScore:P4})", Color.Red)
                    ' If the beep timer is not enabled, start it.
                    ' The beep will now be played by the timer's Tick event.
                    If Not BeepTimer.Enabled Then
                        BeepTimer.Start()
                    End If
                Else
                    ' No significant motion detected: Update status to "Processing Motion..."
                    UpdateStatusLabel("Processing Motion...", SystemColors.ControlText)
                    ' Stop the beep timer if motion stops
                    BeepTimer.Stop()
                End If
            Else
                ' Handle the case where the motion detector is not initialized
                UpdateStatusLabel("Motion detector not initialized.", SystemColors.ControlText)
                ' Stop the beep timer if the detector isn't ready
                BeepTimer.Stop()
            End If

            ' Update the picture box to display the current frame
            ' Ensure the UI update is performed on the main thread using Invoke
            Me.Invoke(Sub()
                          ' Dispose the previous image in the picture box if it exists
                          pbCameraFeed.Image?.Dispose()
                          ' Set the picture box's image to the current frame
                          pbCameraFeed.Image = currentFrame
                      End Sub)

        Catch ex As Exception
            ' Handle any exceptions that occur during frame processing
            Me.Invoke(Sub()
                          ' Write the error message to the debug output
                          Debug.WriteLine("Error in camera feed processing: " & ex.Message)
                          ' Show an error message box to the user
                          MessageBox.Show("Error in camera feed processing: " & ex.Message, "Processing Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
                          ' Stop the camera and reset UI elements in case of an error
                          StopCamera()
                      End Sub)
            ' Dispose the current frame if an exception occurred
            If currentFrame IsNot Nothing Then currentFrame.Dispose()
        End Try
    End Sub
#End Region

#Region "Timer Event Handlers"
    ' Event handler for the beep timer tick event
    Private Sub BeepTimer_Tick(sender As Object, e As EventArgs) Handles BeepTimer.Tick
        ' Play the system beep sound
        SystemSounds.Beep.Play()
        ' The timer remains enabled and will tick again after BeepIntervalMs if motion persists
    End Sub
#End Region

#Region "Helper Subroutines"
    ' Subroutine to stop the camera and reset UI elements
    Private Sub StopCamera()
        ' Check if video source is not null and is currently running
        If videoSource IsNot Nothing AndAlso videoSource.IsRunning Then
            Try
                ' Remove the event handler for the new frame event
                RemoveHandler videoSource.NewFrame, AddressOf VideoSource_NewFrame
                ' Signal the video source to stop capturing frames
                videoSource.SignalToStop()
                ' Wait for the video source to stop
                videoSource.WaitForStop()
                ' Set the video source to null after stopping
                videoSource = Nothing

                ' Dispose the image in the picture box if it exists and set it to null
                If pbCameraFeed.Image IsNot Nothing Then
                    pbCameraFeed.Image.Dispose()
                    pbCameraFeed.Image = Nothing
                End If

                ' Set motion detector to null after stopping the camera
                motionDetector = Nothing

                ' Stop the beep timer
                BeepTimer.Stop()
                ' Enable the start button
                btnStart.Enabled = True
                ' Disable the stop button
                btnStop.Enabled = False
                ' Enable the camera combo box
                cboCameras.Enabled = True
                ' Update the status label to indicate that the camera has been stopped
                UpdateStatusLabel("Camera stopped.", SystemColors.ControlText)
            Catch ex As Exception
                ' Handle any exceptions that occur during stopping the camera
                MessageBox.Show("Error stopping camera: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
                ' Enable the start button in case of an error
                btnStart.Enabled = True
                ' Disable the stop button
                btnStop.Enabled = False
                ' Enable the camera combo box for user to make a selection
                cboCameras.Enabled = True
                ' Update the status label to indicate an error during stopping
                UpdateStatusLabel("Error stopping camera.", Color.Red)
            End Try
        End If
    End Sub

    ' Subroutine to update the status label text and color
    Private Sub UpdateStatusLabel(text As String, color As Color)
        ' Ensure the UI update is performed on the main thread using Invoke
        Me.Invoke(Sub()
                      ' Set the text of the status label
                      lblStatus.Text = text
                      ' Set the color of the status label text
                      lblStatus.ForeColor = color
                  End Sub)
    End Sub
#End Region

End Class
 
Last edited:
Back
Top