I have same the problem like this topic BackgroundSubtractorMOG2 & OpenCV
Before i use opencv 2.4.9, i have deleted opencv 3.0.0. And now when i use class BackgroundSubtractorMOG2 then i have this prolem.
How can i resolve it. I'm using eclipse. Please, help me.
My source code:
int main(int argc, char *argv[]) {
cv::Mat frame;
cv::Mat back;
cv::Mat fore;
cv::VideoCapture cap(0);
cv::BackgroundSubtractorMOG2 bg;
bg.set("nmixtures", 3);
//bg.bShadowDetection = false;
std::vector<std::vector<cv::Point> > contours;
cv::namedWindow("Frame");
cv::namedWindow("Background");
for (;;) {
cap >> frame;
bg.operator()(frame, fore);
bg.getBackgroundImage(back);
cv::erode(fore, fore, cv::Mat());
cv::dilate(fore, fore, cv::Mat());
cv::findContours(fore, contours, CV_RETR_EXTERNAL,
CV_CHAIN_APPROX_NONE);
cv::drawContours(frame, contours, -1, cv::Scalar(0, 0, 255), 2);
cv::imshow("Frame", frame);
cv::imshow("Background", back);
if (cv::waitKey(30) >= 0)
break;
}
return 0;}
const int nmixtures =3;
const bool bShadowDetection = false;
cv::BackgroundSubtractorMOG2 bg(nmixtures,bShadowDetection);
Change the code like this . It will work .
Related
I'm working on a project to detect motion on a camera.
I need to start recording video when motion is detected for example:
Record while motion is being detected
Continue recording for 10 seconds after the motion detection is stopped
I have a working example that only detects the motion and draw rectangles on the moving parts.
I searched for examples on how to record when motion is detected but no good results.
Here is my working code:
#include <iostream>
#include <sstream>
#include <opencv4/opencv2/imgproc.hpp>
#include <opencv4/opencv2/videoio.hpp>
#include <opencv4/opencv2/highgui.hpp>
#include <opencv4/opencv2/video.hpp>
#include <unistd.h>
using namespace cv;
using namespace std;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
int main(int argc, char* argv[])
{
//create Background Subtractor objects
Ptr<BackgroundSubtractor> pBackSub;
pBackSub = createBackgroundSubtractorMOG2();
VideoCapture capture(0);
if (!capture.isOpened()){
//error in opening the video input
cerr << "Unable to open: " << endl;
return 0;
}
Mat frame, fgMask;
sleep(3);
while (true) {
capture >> frame;
if (frame.empty())
break;
//update the background model
pBackSub->apply(frame, fgMask);
imshow("FG Mask", fgMask);
RNG rng(12345);
findContours(fgMask, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE,Point(0, 0));
vector<Rect>boundRect (contours.size());
vector<vector<Point> > contours_poly( contours.size() );
for (int i = 0; i < contours.size();i++) {
if( contourArea(contours[i])< 500)
{
continue;
}
putText(frame, "Motion Detected", Point(10,20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0,0,255),2);
approxPolyDP( contours[i], contours_poly[i], 3, true );
boundRect[i] = boundingRect( contours_poly[i] );
Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
rectangle( frame, boundRect[i].tl(), boundRect[i].br(), color, 2 );
}
imshow("Frame", frame);
int keyboard = waitKey(30);
if (keyboard == 'q' || keyboard == 27)
break;
}
return 0;
}
I tried adding this to the code:
int frameWidth = 320;
int frameHeight = 240;
cv::Size frameSize = cv::Size(frameWidth, frameHeight);
/* Output file */
int codec = cv::VideoWriter::fourcc('M', 'P', '4', 'V');
cv::VideoWriter outputVideo;
outputVideo.open("rr.mp4", codec, capture.get(cv::CAP_PROP_FPS), frameSize, true);
and after drawing the rectangle I write the frame to the video:
outputVideo.write(frame);
but after that, the video is empty and crashes.
I already took a look at Motion but I didn't find an example.
How can I achieve this?
Thanks,
Talel
I resolved the issue,
I was opening the output video with a specific dimensions (320,240) and I was saving the captured frame which is bigger.
So the solution is to resize the captured frame to fit into the output video.
Here is the final solution if anyone is interesting:
Turn the laptop camera into an IP camera with: cam2ip
Here is the source code:
#include <iostream>
#include <sstream>
#include <opencv4/opencv2/imgproc.hpp>
#include <opencv4/opencv2/videoio.hpp>
#include <opencv4/opencv2/highgui.hpp>
#include <opencv4/opencv2/video.hpp>
#include <unistd.h>
using namespace cv;
using namespace std;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
int main(int argc, char* argv[])
{
//create Background Subtractor objects
Ptr<BackgroundSubtractor> pBackSub;
pBackSub = createBackgroundSubtractorMOG2();
const std::string videoStreamAddress = "http://192.168.20.100:56000/mjpeg";
cv::VideoCapture vcap;
if(!vcap.open(videoStreamAddress)) {
std::cout << "Error opening video stream or file" << std::endl;
return -1;
}
Mat frame, fgMask;
int frameWidth = 320;
int frameHeight = 240;
cv::Size frameSize = cv::Size(frameWidth, frameHeight);
/* Output file */
int codec = cv::VideoWriter::fourcc('M', 'P', '4', 'V');
cv::VideoWriter outputVideo;
outputVideo.open("rr.mp4", codec, vcap.get(cv::CAP_PROP_FPS), frameSize, true);
sleep(3);
while (true) {
vcap >> frame;
if (frame.empty())
break;
//update the background model
pBackSub->apply(frame, fgMask);
imshow("FG Mask", fgMask);
RNG rng(12345);
findContours(fgMask, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE,Point(0, 0));
vector<Rect>boundRect (contours.size());
vector<vector<Point> > contours_poly( contours.size() );
for (int i = 0; i < contours.size();i++) {
if( contourArea(contours[i])< 500)
{
continue;
}
putText(frame, "Motion Detected", Point(10,20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0,0,255),2);
approxPolyDP( contours[i], contours_poly[i], 3, true );
boundRect[i] = boundingRect( contours_poly[i] );
Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
rectangle( frame, boundRect[i].tl(), boundRect[i].br(), color, 2 );
resize(frame, frame, frameSize);
outputVideo.write(frame);
}
imshow("Frame", frame);
int keyboard = waitKey(30);
if (keyboard == 'q' || keyboard == 27)
break;
}
outputVideo.release();
return 0;
}
Further enhancement suggestions:
Make sure that the light is not part of the motion detection
Open an output video with the same capture's dimensions
I am working with visual-studio and opencv lib and I have been trying to use findContours() but no matter what parameters I give the function it always triggers a break-point,
I have tried to make the image binary (b&w), reinstalling the library in different versions, messing with the linker preferences and anything I'v found on the web.
(this code is one of many i found on the web - they all crush one they get to findContours)
Does anyone know how to solve this problem ?
#include <iostream>
#include <vector>
#include "opencv2/opencv.hpp"
using namespace cv;
using std::vector;
int main()
{
vector<vector<cv::Point>> contours = vector<vector<cv::Point>>();
vector<Vec4i> hierarchy;
Mat frame, cont, threshold_;
VideoCapture capture = VideoCapture(0);
if (!capture.isOpened())
{
return -1;
}
while (true)
{
capture >> frame;
if (frame.empty()) break;
cont = frame.clone();
cvtColor(cont, cont, COLOR_BGR2GRAY);
cv::threshold(cont, cont, 128, 255, THRESH_BINARY);
threshold_ = cont.clone();
findContours(cont, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
for (unsigned int i = 0; i < contours.size(); i++)
{
drawContours(frame, contours, i, Scalar(0, 0, 255), 2);
}
imshow("Contour", threshold_);
imshow("Video", frame);
if (cv::waitKey(30) == 'q')
{
break;
}
}
return 0;
}
Seems that the findContours function has been returning some assertion fails with Visual Studios C++ 2012. I've made sure that all my include directories were fine.
void track (Mat input_video, Mat &output_video)
{
Mat temp;
input_video.copyTo(temp);
vector<vector<cv::Point> > contours;
vector<Vec4i> hierarchy;
findContours(temp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
//Only search through the most external layer.
for (int i=0; i>=0; i=hierarchy[i][0])
{
Moments moment = moments((Mat) contours[i]);
double area= moment.m00;
double xmc= moment.m10;
double ymc= moment.m01;
double x= xmc/area;
double y= ymc/area;
circle(output_video, Point(x,y), 3, Scalar(0,255,255));
}
}
EDIT:
The rest of my code if you may need it:
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
//This function threshold the HSV image and create a binary image
Mat GetThresholdedImage(Mat imgHSV, int huemin, int satmin, int valmin, int huemax, int satmax, int valmax)
{
//Size s= imgHSV->size();
Mat imgThresh(imgHSV.size().height, imgHSV.size().width, CV_8U);
//returns matrix that contains all values within the given HSV range.
inRange(imgHSV, Scalar(huemin,satmin,valmin), Scalar(huemax,satmax,valmax), imgThresh);
return imgThresh;
}
Mat morph(Mat imgThresh)
{
Mat erode_element= getStructuringElement(MORPH_RECT, Size(3,3));
Mat dilate_element= getStructuringElement(MORPH_RECT, Size(8,8));
erode(imgThresh, imgThresh, erode_element);
erode(imgThresh, imgThresh, erode_element);
dilate(imgThresh, imgThresh, dilate_element);
return imgThresh;
}
void track (Mat input_video, Mat &output_video)
{
Mat temp;
input_video.copyTo(temp);
vector< vector<Point> > contours;
cerr<< contours.size();
vector<Vec4i> hierarchy;
findContours(temp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
cerr<<contours.size();
//Only search through the most external layer.
for (int i=0; i>=0; i=hierarchy[i][0])
{
Moments moment = moments((Mat) contours[i]);
double area= moment.m00;
double xmc= moment.m10;
double ymc= moment.m01;
double x= xmc/area;
double y= ymc/area;
circle(output_video, Point(x,y), 3, Scalar(0,255,255));
}
}
int main()
{
VideoCapture capture(0);
if(!capture.isOpened()){
cerr<< "Capture failed";
return -1;
}
Mat frame;
namedWindow("Original");
namedWindow("Binary");
//Create slider for adjustments...
namedWindow("Adjustments");
int huemin= 0, satmin= 0, valmin= 0;
int huemax= 256, satmax= 256, valmax= 256;
createTrackbar("Min Hue", "Adjustments", &huemin, 256);
createTrackbar("Max Hue", "Adjustments", &huemax, 256);
createTrackbar("Min Saturation", "Adjustments", &satmin, 256);
createTrackbar("Max Saturation", "Adjustments", &satmax, 256);
createTrackbar("Min Value", "Adjustments", &valmin, 256);
createTrackbar("Max Value", "Adjustments", &valmax, 256);
//iterate through each frames of the video
while(true)
{
//Grabs each frame from video to be processed.
capture>> frame;
//Error checks and breaks if the grab failed.
if(!frame.data)
{
cerr<< "Failed to grab frame\n";
break;
}
//Apply a Gaussian Blur kernel.
//GaussianBlur(frame, frame, Size(3,3), 3, 3, 4);
Mat imgHSV(frame.size(), CV_8UC3);
cvtColor(frame, imgHSV, CV_BGR2HSV, 0); //Change the color format from BGR to HSV
Mat imgThresh = GetThresholdedImage(imgHSV, huemin, satmin, valmin, huemax, satmax, valmax);
//GaussianBlur(imgThresh, imgThresh, Size(5,5), 3, 3, 4); //smooth the binary image using Gaussian kernel
imgThresh= morph(imgThresh);
track(imgThresh, frame);
imshow("Binary", imgThresh);
imshow("Original", frame);
int key = waitKey(30);
//If 'ESC' is pressed, break the loop
if(key==27 ) break;
}
destroyAllWindows();
//cvReleaseCapture(&capture);
return 0;
}
Eugene, I encountered the same problem. try to add "cv::imshow("im", output_video);"
as mentioned in - OpenCV findContours causes Debug Assertion Failed at return
I have this code that basically does a "dumb" background subtraction on two frames.
void FrameDifferenceBGS::operator()(cv::InputArray _image, cv::OutputArray _fgmask, double learningRate)
{
cv::Mat img_input = _image.getMat();
if(img_input.empty())
return;
_fgmask.create(img_input.size(), CV_8U);
cv::Mat img_foreground = _fgmask.getMat();
if(img_input_prev.empty())
{
img_input.copyTo(img_input_prev);
return;
}
cv::absdiff(img_input_prev, img_input, img_foreground);
if(img_foreground.channels() == 3)
cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY);
if(enableThreshold)
cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY);
if(showOutput)
cv::imshow("Frame Difference", img_foreground);
img_input.copyTo(img_input_prev);
img_foreground.copyTo(_fgmask);
firstTime = false;
}
If I don't add img_foreground.copyTo(_fgmask) in the end, the output array isn't updated with the result of img_foreground, resulting on a black image when this is called.
What am I doing wrong / should be doing here?
I reviewed your code again. It looks like you are creating new object for _fgmask.
_fgmask.create(img_input.size(), CV_8U);
I think this is why you have the problem. Because of this reference in the argument is different from the one after this statement. Why don't you call the line before calling the function.
fix
change _fgmask.create(img_input.size(), CV_8U); to _fgmask.create(img_input.size(), CV_8UC3); or _fgmask.create(img_input.size(), img_input.type());
why
this is because cv::absdiff(img_input_prev, img_input, img_foreground); recreate a new array everytime internally. and it does update the img_foreground structure but after the allocation, the memory address data inside _fgmask fail to change since the headers are passed by value.
you can seemlingly fix this(but still incurs creation cost) by doing cv::Mat& img_foreground = _fgmask.getMatRef();
and that is because CV_8U is not the same as CV_8UC3 and therefore the check # Mat::create() in mat.hpp always end up allocating a new array due to type difference
opinion
i think...maybe use Mat instead?
#include "opencv2/opencv.hpp"
using namespace cv;
class FrameDifferenceBGS
{
public:
Mat prev;
Mat diff;
bool enableThreshold;
bool showOutput;
bool firstTime;
uchar threshold;
FrameDifferenceBGS():firstTime(false),enableThreshold(false),showOutput(false),threshold(0)
{
}
void FrameDifferenceBGS::operator()(cv::Mat& _in, cv::Mat &_fg, double _lr)
{
if(_in.empty())
return;
if(prev.empty())
{
prev=_in.clone();
_fg=cv::Mat::zeros(_in.size(),CV_8UC1);
return;
}
cv::absdiff(prev, _in, diff);
if(diff.channels() == 3)
cv::cvtColor(diff, _fg, CV_BGR2GRAY);
else
_fg=diff;
if(enableThreshold)
cv::threshold(_fg, _fg, threshold, 255, cv::THRESH_BINARY);
if(showOutput)
cv::imshow("Frame Difference", _fg);
prev=_in.clone();
firstTime = false;
}
};
int main()
{
VideoCapture cap(0);
FrameDifferenceBGS bgs;
Mat frame,fg;
for(;;)
{
cap >> frame;
bgs(frame,fg,0);
imshow("frame", frame);
imshow("fg", fg);
if(waitKey(1) ==27) exit(0);
}
return 0;
}
edit 2(modified original)
#include "opencv2/opencv.hpp"
class FrameDifferenceBGS
{
public:
cv::Mat img_input_prev;
cv::Mat diff;
cv::Mat img_foreground;//put this in class in stead of inside the function
bool enableThreshold;
bool showOutput;
bool firstTime;
uchar threshold;
FrameDifferenceBGS():firstTime(false),enableThreshold(false),showOutput(false),threshold(0)
{
}
void FrameDifferenceBGS::operator()(cv::InputArray _image, cv::OutputArray _fgmask, double learningRate)
{
cv::Mat img_input = _image.getMat();
if(img_input.empty())
return;
if(_fgmask.empty())
_fgmask.create(img_input.size(), CV_8UC1);
if(img_input_prev.empty())
{
img_input.copyTo(img_input_prev);
return;
}
cv::absdiff(img_input_prev, img_input, img_foreground);
if(img_foreground.channels() == 3)
cv::cvtColor(img_foreground, _fgmask, CV_BGR2GRAY);
if(enableThreshold)
cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY);
if(showOutput)
cv::imshow("Frame Difference", img_foreground);
img_input.copyTo(img_input_prev);
//img_foreground.copyTo(_fgmask);
firstTime = false;
}
};
int main()
{
cv::VideoCapture cap(0);
FrameDifferenceBGS bgs;
cv::Mat frame,fg;
for(;;)
{
cap >> frame;
bgs(frame,fg,0);
cv::imshow("frame", frame);
cv::imshow("fg", fg);
if(cv::waitKey(1) ==27) exit(0);
}
return 0;
}
I wrote a short routine in openCV and C++ to track objects with a webcam. The webcam formulation was speedy with no lag, but before leaving work for the weekend, I recorded a typical sequence to use as a test template while I work until Monday. This and the corresponding change in code somehow make the video play back in really slow motion. Here is the code, opening "Test.avi", ~20 seconds long instead of running a constant stream off of the webcam:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
Mat drawBoundingBoxes (Mat canvasImage, vector<vector<Point>> contours);
int main(int argc, char** argv[])
{
Mat frame;
Mat back;
Mat fGround;
BackgroundSubtractorMOG2 bGround;
bGround.nmixtures = 3;
//bGround.nShadowDetection = 0;
bGround.fTau = .5;
VideoCapture cap;
cap.open("Test.avi");
if (!cap.isOpened())
{
cout << "Can't open video" << endl;
return -1;
}
vector<vector<Point>> contours;
namedWindow("video", CV_WINDOW_AUTOSIZE);
while (true)
{
static int count = 1;
cap >> frame;
if (frame.empty())
break;
bGround.operator()(frame, fGround);
bGround.getBackgroundImage(back);
erode(fGround, fGround, Mat(), Point(-1,-1), 2, BORDER_DEFAULT);
dilate(fGround, fGround, Mat(), Point(-1,-1), 10, BORDER_DEFAULT);
if (count > 50)
{
findContours(fGround, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
drawContours(frame, contours, -1, Scalar(239,255,0), 2);
drawBoundingBoxes(frame, contours);
}
imshow("video", frame);
if(waitKey(30) >= 0)
break;
count++;
}
return 0;
}
Mat drawBoundingBoxes (Mat canvasImage, vector<vector<Point>> contours)
{
vector<Rect> boundRect(contours.size());
for (int i=0; i<contours.size(); i++)
{
boundRect[i] = boundingRect(contours[i]);
rectangle(canvasImage, boundRect[i], Scalar(153,0,76), 2, 8, 0);
}
return canvasImage;
}
Any ideas? Memory Leak somewhere? Thanks,
-Tony
I believe your recorded video has a higher framerate than that your PC can process real time. It's not a problem with a webcam as it just drops the frames. You could try to decrease the delay in the waitKey() procedure and see if that helps.