opencv c++ based on the median and mean frame difference method moving object detection

Table of Contents

    • main function
    • Cgraphic_math.h file
    • Cgraphic_math.cpp file
    • GitHub download link

Main function

#include <opencv2/opencv.hpp>
#include <iostream>
#include "Cgraphic_math.h"


using namespace std;
using namespace cv;


#define num 19
#define type 1 //0: in the mean way
//1: in the way of median value



int main()
{<!-- -->
VideoCapture test_video;
int count = 0;

// read video
test_video.open("C:\Users\Tiam\Desktop\Moving_Object_Detection\video\test.avi");
\t
//Read frame number and frame rate
int FrameCount = test_video.get(cv::CAP_PROP_FRAME_COUNT);
int fps = test_video.get(cv::CAP_PROP_FPS);

//Single frame image
Mat frame;
Mat frame_gray;
C graphic_math graphic;
graphic.setAverage_num(INT_MAX);

// image array
Mat image[num];
Mat img;
Mat img_gray;
//Fill in the number of frames processed by the median
graphic.setMedian_num(num);
//initialization
for (int i = 0; i < num; i ++ )
{<!-- -->
test_video.read(img);
cvtColor(img, img_gray, CV_BGR2GRAY);
\t\t
image[i] = img_gray. clone();
}
//The median value processing gets the background
graphic.images_median(image);


while (count < (FrameCount-num)) //The num frames read before need to be subtracted
{<!-- -->
test_video.read(frame);
cvtColor(frame, frame_gray, CV_BGR2GRAY);

if (type == 0)
{<!-- -->
//Average processing to get the background
graphic.images_average(frame_gray);
graphic.setDifImage(frame_gray);
}
else
{<!-- -->
//The median value processing gets the background
graphic.setDifImage(frame_gray);
}
\t\t\t

\t\t//Binarization
threshold(graphic.getDifImage(), graphic.getDifImage(), 50, 255, THRESH_BINARY);
vector<vector<Point>> contours;
// find the center
findContours(graphic.getDifImage(), contours, RETR_TREE, CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours. size(); i ++ )
{<!-- -->
if ((contours[i]. size() > 75) & (contours[i]. size() < 150))
{<!-- -->
// find area
Rect roi = boundingRect(Mat(contours[i]));
rectangle(frame, roi, Vec3b(0, 0, 255), 2);
}

}


cv::imshow("video", frame); //display
\t\t
cv::waitKey(fps);

count + + ;
}

destroyAllWindows();
}

Cgraphic_math.h file

#ifndef _CGRAPHIC_MATH_H
#define _CGRAPHIC_MATH_H

#include <opencv2/opencv.hpp>
#include <iostream>
#include <string.h>

using namespace std;
using namespace cv;


/**************************************************** *************************
* @abstract Cgraphic_math class, which realizes mean or median processing of multi-frame images,
Get the background image, and finally calculate the frame difference to realize the detection of moving objects
* @author [email protected]
* @since opencv3.4.4
***************************************************** *************************/
class Graphic_math
{<!-- -->
private:
Mat image_back; //background image
Mat image_dif; //detection image
int average_num; // how many frames to take an average

int median_num; // how many frames to take the median

public:
Cgraphic_math(); //constructor
~Cgraphic_math(); //destructor

Mat getImage_back(void); //Get the background image
Mat getDifImage(void); //Get frame difference
void setDifImage(Mat image); // frame difference calculation

void images_average(Mat image); //Average processing
void setAverage_num(int num); //Set average processing frame number

void images_median(Mat image[]);//median processing
void setMedian_num(int num); //Set the median processing frame number
};



#endif

Cgraphic_math.cpp file

#include "Cgraphic_math.h"



Cgraphic_math::Cgraphic_math()
{<!-- -->
average_num = 13;
median_num = 13;
}

Cgraphic_math::~Cgraphic_math()
{<!-- -->
//delete img;
}

/**************************************************** *******************************
 * @Function: // Get the background image
 * @Description: // Get the background image after mean or median processing
 * @Input: // void
 * @Output: // background image
 * @Return: // background image
***************************************************** *******************************/
Mat Graphic_math::getImage_back(void)
{<!-- -->
return image_back;
}

/**************************************************** *******************************
 * @Function: // Calculate the frame difference image
 * @Description: // Use the difference between the input image and the background image processed by the median or mean value to get the frame difference
 * @Input: // need to do poor image
 * @Output: // frame difference
 * @Return: // void
***************************************************** *******************************/
void Cgraphic_math::setDifImage(Mat image)
{<!-- -->
image_dif = abs(image - image_back);
}


/**************************************************** *******************************
 * @Function: // Average processing image
 * @Description: // Calculate the mean value of multiple frames of images to get the background image
 * @Input: // The image to be processed
 * @Output: // background image
 * @Return: // void
***************************************************** *******************************/
void Cgraphic_math::images_average(Mat image)
{<!-- -->
static int count = 0;
float q1 = count / (count + 1.0); //weight
float q2 = 1 / (count + 1.0);

//cvtColor(image, image, CV_BGR2GRAY); //Grayscale

//The first execution needs to initialize image_back
if (count == 0)
{<!-- -->
image_back = image. clone();
}

//calculate the mean
image_back = q1 * image_back + q2 * image;

count + + ;

// overflow
if (count >= average_num)
{<!-- -->
count = 0;
}
}

/**************************************************** *******************************
 * @Function: // Get the frame difference image
 * @Description: // Get the frame difference image
 * @Input: // void
 * @Output: // None
 * @Return: // frame difference image
***************************************************** *******************************/
Mat Graphic_math::getDifImage(void)
{<!-- -->
return image_dif;
}

/**************************************************** *******************************
 * @Function: // Set the number of frames that need mean processing
 * @Description: // Set the number of image frames that need to be averaged
 * @Input: // frame number
 * @Output: // average processing frame number
 * @Return: // None
***************************************************** *******************************/
void Cgraphic_math::setAverage_num(int num)
{<!-- -->
average_num = num;
}

/**************************************************** *******************************
 * @Function: // insertion sort algorithm
 * @Description: // Sort the input array
 * @Input: // arr: the array to be processed, n: the length of the array
 * @Output: // sorted array arr
 * @Return: // None
***************************************************** *******************************/
void InsertSort(int* arr, int n)
{<!-- -->
for (int i = 0; i < n - 1; + + i)
{<!-- -->
//Record the subscript of the last element of the ordered sequence
int end = i;
// element to be inserted
int tem = arr[end + 1];
//Single trip
while (end >= 0)
{<!-- -->
//Move backward if it is larger than the inserted number
if (tem < arr[end])
{<!-- -->
arr[end + 1] = arr[end];
end--;
}
// is smaller than the inserted number, jump out of the loop
else
{<!-- -->
break;
}
}
//tem is placed after the number smaller than the inserted number
arr[end + 1] = tem;
//There are two situations where the code executes to this position:
//1. The element to be inserted finds the position where it should be inserted (break jumps out of the loop to this point)
//2. The element to be inserted is smaller than all the elements in the current ordered sequence (here after the end of the while loop)
}
}

/**************************************************** *******************************
 * @Function: // image median processing
 * @Description: // Take the median value of the corresponding pixel points of various images to get the background image
 * @Input: // image[] image array that needs to be processed
 * @Output: // data_back background image
 * @Return: // None
***************************************************** *******************************/
void Cgraphic_math::images_median(Mat image[])
{<!-- -->
int* arr = new int[median_num];
\t
if (image_back.empty()) //Background image initialization
{<!-- -->
image_back = image[0]. clone();
}
for (int i = 0; i < image[0].rows; i ++ )
{<!-- -->
for (int j = 0; j < image[0].cols; j++ )
{<!-- -->
for (int n = 0; n < median_num; n ++ )
{<!-- -->
//Get the first address of the i-th line of the n-th image
          uchar* data = image[n].ptr<uchar>(i);
arr[n] = (int)data[j];
if (n >= (median_num - 1))
{<!-- -->
//The first address of the i line of the background image
uchar* data_back = image_back.ptr<uchar>(i);
InsertSort(arr, median_num);
data_back[j] = (uchar)(arr[(median_num / 2)]);

continue;
}
\t\t\t\t
}
}
}

delete[] arr;
}

/**************************************************** *******************************
 * @Function: // Set the number of frames that need median processing
 * @Description: // Set the number of image frames that need to be median
 * @Input: // frame number
 * @Output: // median processing frame number
 * @Return: // None
***************************************************** *******************************/
void Cgraphic_math::setMedian_num(int num)
{<!-- -->
median_num = num;
}

GitHub download link

download link