Capturing the frame when the Object is detected - c++

i have the following code :
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
String object_cascade_name = "haarcascade_frontalface_alt.xml";
CascadeClassifier object_cascade;
string window_name = "Capture - detector";
int main( void )
{
VideoCapture capture;
Mat frame;
std::vector<Rect> objects;
Mat frame_gray;
if( !object_cascade.load( object_cascade_name ) ){ std::cout << "ERROR: Cascade not loaded!\n" ; return -1; };
capture.open( 0 );
if( capture.isOpened() ){
for(;;){
capture >> frame;
capture.retrieve(frame);
//-- 3. Apply the classifier to the frame
if( !frame.empty() ){
// Start
cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
//-- Detect Object
object_cascade.detectMultiScale( frame_gray, objects, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
for( size_t i = 0; i < objects.size(); i++ ){
Point pt1 = Point( objects[i].x, objects[i].y );
Point pt2 = Point( objects[i].x + objects[i].width, objects[i].y + objects[i].height );
rectangle( frame, pt1, pt2, Scalar( 34, 92, 241 ), 2, 8, 0 );
Mat faceROI = frame_gray( objects[i] );
}
//-- Show what you got
imshow( window_name, frame );
// End
}
else{ std::cout << "ERROR: frame.empty returns 1!"; break; }
int c = waitKey(10);
if( (char)c == 'c' ) { break; }
}
}
return 0;
}
which plays a video from the build-in webcam and detect faces, my idea is that i want the video to stop when an object -face- is detected, then display a window contains the detected object only from the last frame.

Related

[OpenCV][C++] Record only the detected motion

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

segmentation fault error in Opencv c++

I am trying to code a program on opencv to decide whether a human has approached ahead the camera. After I run the execution file, I get the captured video for few seconds and encounter the segmentation fault error.
The code is like this
Here are headers:
#include "opencv2/objdetect.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
//define static variable
static int cApp = 0;//number of approached frame
static double last = 0;
//define functions
void detectAndDisplay( Mat frame );
bool computeArea( double width, double height, double lastArea);
double runningAverage(int M);
//define opencv function and classifier
String upperbody_cascade_name = "home/pi/opencv- 3.0.0/data/haarcascades/haarcascade_upperbody.xml";
CascadeClassifier upper_cascade;
String window_name = "Capture - upper body detection";
Here is the main function:
int main( void )
{
//define variable
VideoCapture capture;
Mat frame;
//-- 1. Load the cascades
upper_cascade.load("/home/pi/opencv-3.0.0/data/haarcascades/haarcascade_upperbody.xml");
//-- 2. Read the video stream
capture.open( -1 );
if ( ! capture.isOpened() ) { printf("--(!)Error opening video capture\n"); return -1; }
while ( capture.read(frame) )
{
if( frame.empty() )
{
printf(" --(!) No captured frame -- Break!");
break;
}
//-- 3. Apply the classifier to the frame
detectAndDisplay( frame );
char c = (char)waitKey(10);
if( c == 27 ) { break; } // escape
}
capture.release();
return 0;
}
Here is the detectAndDisplay function:
void detectAndDisplay( Mat frame )
{
std::vector<Rect> upperbodys;
Mat frame_gray;
cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
//-- Detect upperbodys
upper_cascade.detectMultiScale( frame_gray, upperbodys, 1.05, 3, 0|CASCADE_SCALE_IMAGE, Size(30, 30) );
Point center( upperbodys[0].x + upperbodys[0].width/2, upperbodys[0].y + upperbodys[0].height/2 );
ellipse( frame, center, Size( upperbodys[0].width/2, upperbodys[0].height/2 ), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
bool ifApproached = computeArea(upperbodys[0].width/2, upperbodys[0].height/2, last);
if (ifApproached == true) {
cApp++;
}
if (cApp == 3) {
cout << "have approached" << endl;
cApp = cApp - 3;
}
//-- Show what you got
imshow( window_name, frame );
}
Here is the computeArea function:
bool computeArea( double width, double height, double lastArea) {
double newArea = width * height;
bool ifApproached = false;
//double presentArea = newArea;
double presentArea = runningAverage(newArea);
double DifferenceBewteenAreas = presentArea - lastArea;
if (DifferenceBewteenAreas > 1) {//threshold
ifApproached = true;
}
last = presentArea;
return ifApproached;
}
Here is runningAverage function:
double runningAverage(int M) {
//M is measurement
//#define LM_SIZE 5
static int LM[5];
static int index =0;
static long sum = 0;
static int count =0;
//keep sum updated to improve speed
sum = sum - LM[index];
LM[index] = M;
sum = sum + LM[index];
index++;
index = index % 5;
if (count < 5) {
count++;
}
return (double)(sum / (double)count);
}
I have searched many opencv segmentation fault questions, some said this segmentation fault was caused by wrong array used, but my case has little use of array. Others said misused of function characters could also cause this kind of errors, I agree with this, some of my characters could be wrong here.
Actually I found that I should not use upperbodys[0] in the code, because sometimes there are no object being detected at all,so there could be some memory read error happens, I used upperbodys[i] instead and it works well then.
void detectAndDisplay( Mat frame )
{
std::vector<Rect> upperbodys;
Mat frame_gray;
cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
//-- Detect upperbodys
upper_cascade.detectMultiScale( frame_gray, upperbodys, 1.05, 3, 0|CASCADE_SCALE_IMAGE, Size(30, 30) );
int size = upperbodys.size();
double newArea = -1;
for (int i = 0 ; i < size; i++) {
Point center( upperbodys[i].x + upperbodys[i].width/2, upperbodys[i].y + upperbodys[i].height/2 );
ellipse( frame, center, Size( upperbodys[i].width/2, upperbodys[i].height/2 ), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
//bool ifApproached = computeArea(upperbodys[i].width/2, upperbodys[i].height/2, last);
//////////////////////////////////////////
newArea = upperbodys[i].width/2 * upperbodys[i].height/2;
if (newArea != -1) {
cout << "UpperBodys has value, index = " << i << endl;
break;
}
}
bool ifApproached = false;
//double presentArea = runningAverage(newArea);
double presentArea = newArea;
double DifferenceBewteenAreas = presentArea - last;
if (DifferenceBewteenAreas > 1) {//threshold
ifApproached = true;
}
last = presentArea;
//////////////////////////////////////////
if (ifApproached == true) {
cApp++;
}
if (cApp == 3) {
cout << "have approached" << endl;
cApp = cApp - 3;
}
//-- Show what you got
imshow( window_name, frame );
}

cvQueryFrame returns null

i am trying to run this OpenCV tutorial code using CodeBlocks on windows :
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
// Function Headers
void detectAndDisplay( Mat frame );
// Global variables
String face_cascade_name = "haarcascade_frontalface_alt.xml";
String eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
string window_name = "Capture - Face detection";
RNG rng(12345);
// #function main
int main( int argc, const char** argv ){
CvCapture* capture;
Mat frame;
//-- 1. Load the cascades
if( !face_cascade.load( face_cascade_name ) ){ std::cout << "--(!)Error loading Face cascade\n"; return -1; };
if( !eyes_cascade.load( eyes_cascade_name ) ){ std::cout << "--(!)Error loading Eyes cascade\n"; return -1; };
//-- 2. Read the video stream
capture = cvCaptureFromCAM( 0 );
if( capture ){
while( true ){
frame = cvQueryFrame( capture );
//-- 3. Apply the classifier to the frame
if( !frame.empty() ){
detectAndDisplay( frame );
}
else{
std::cout << " --(!) No captured frame -- Break!"; break;
}
int c = waitKey(10);
if( (char)c == 'c' ) { break; }
}
}
return 0;
}
// #function detectAndDisplay
void detectAndDisplay( Mat frame ){
std::vector<Rect> faces;
Mat frame_gray;
cvtColor( frame, frame_gray, CV_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
//-- Detect faces
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
for( size_t i = 0; i < faces.size(); i++ ){
Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
Mat faceROI = frame_gray( faces[i] );
std::vector<Rect> eyes;
//-- In each face, detect eyes
eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CV_HAAR_SCALE_IMAGE, Size(30, 30) );
for( size_t j = 0; j < eyes.size(); j++ ){
Point center( faces[i].x + eyes[j].x + eyes[j].width*0.5, faces[i].y + eyes[j].y + eyes[j].height*0.5 );
int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
circle( frame, center, radius, Scalar( 255, 0, 0 ), 4, 8, 0 );
}
}
//-- Show what you got
imshow( window_name, frame );
}
But the Output is " --(!) No captured frame -- Break!"
During the execution the camera flash blinks then the output is displayed.

unable to write the output video in OpenCV, program is writing only single frame

Could anyone please help me write the output video file? I have read many similar questions on how to write the program and followed the exact steps to write the video file in .avi format, but I am not able to find out where I am wrong. The face_output.avi file is created but it only contains one frame. My program is not adding all the frames to the video file. Below is the complete code:
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
/** Function Headers */
void detectAndDisplay( Mat frame);
/** Global variables */
String face_cascade_name = "haarcascade_frontalface_alt.xml";
String eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
string window_name = "Capture - Face detection";
RNG rng(12345);
double fps;
/** #function main */
int main( int argc, const char** argv )
{
VideoCapture cap("/home/pradeep/Downloads/President Obama Lectures Romney.mp4"); // open the video file for reading
if ( !cap.isOpened() ) // if not success, exit program
{
cout << "Cannot open the video file" << endl;
return -1;
}
//-- 1. Load the cascades
if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading\n"); return -1; };
if( !eyes_cascade.load( eyes_cascade_name ) ){ printf("--(!)Error loading\n"); return -1; };
fps = cap.get(CV_CAP_PROP_FPS); //get the frames per seconds of the video
cout << "Frame per seconds : " << fps << endl;
double dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH);
double dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
Size S(dWidth,dHeight);
while(1)
{
Mat frame;
int skip_frame = 4;
while(skip_frame)
{
bool bSuccess = cap.read(frame); // read a new frame from video
skip_frame--;
if (!bSuccess) //if not success, break loop
{
cout << "Cannot read the frame from video file" << endl;
break;
}
}
//-- 3. Apply the classifier to the frame
if( frame.empty() )
{ printf(" --(!) No captured frame -- Break!"); break; }
std::vector<Rect> faces;
Mat frame_gray;
cvtColor( frame, frame_gray, CV_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
//-- Detect faces
face_cascade.detectMultiScale( frame_gray, faces, 1.3, 5, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
for( size_t i = 0; i < faces.size(); i++ )
{
Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
Mat faceROI = frame_gray( faces[i] );
std::vector<Rect> eyes;
//-- In each face, detect eyes
eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 0, 0 |CV_HAAR_SCALE_IMAGE, Size(30, 30) );
for( size_t j = 0; j < eyes.size(); j++ )
{
Point center( faces[i].x + eyes[j].x + eyes[j].width*0.5, faces[i].y + eyes[j].y + eyes[j].height*0.5 );
int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
circle( frame, center, radius, Scalar( 255, 0, 0 ), 4, 8, 0 );
}
}
VideoWriter Video("face_output.avi", CV_FOURCC('M','J','P','G'), fps, S, true);
if(!Video.isOpened())
{
printf("unable to write video file");
}
Video.write(frame);
//-- Show what you got
imshow( window_name, frame );
int c = waitKey(10);
if( (char)c == 'c' ) { break; }
}
return 0;
}
You are creating VideoWriter Video("face_output.avi", CV_FOURCC('M','J','P','G'), fps, S, true); inside the while(1), so you create a new Video in each iteration. Since you only write one frame per iteration, this is will be the only content of your face_output.avi file.
Try moving that line before the while(1):
// ...
Size S(dWidth,dHeight);
VideoWriter Video("face_output.avi", CV_FOURCC('M','J','P','G'), fps, S, true);
while(1)
{
// ...

Applying medianBlur as well as Laplacian and threshold filters

I have a function, with the following signature:
Mat cartoonifyImage( Mat, Mat );
I also have a VS2010 program as follows, where I apply to a webcam stream a number of filters, as taught in this book: Mastering OpenCV
int main( int argc, const char** argv )
{
VideoCapture camera;
camera.open(0);
if( !camera.isOpened() )
{
cerr << "Could not access the camera!" << endl;
return 1;
}
while( true )
{
Mat cameraFrame;
camera >> cameraFrame;
if( cameraFrame.empty() )
{
cerr << "Could not grab a camera frame!" << endl;
return 1;
}
// imshow( "Camera Test", cameraFrame );
Mat displayedFrame( cameraFrame.size(), CV_8UC3 );
cartoonifyImage( cameraFrame, displayedFrame );
imshow( "Cartoonifier!", displayedFrame );
int keypress = waitKey( 20 );
if( keypress == 27 ) break;
}
}
Here is my function definition:
Mat cartoonifyImage( Mat srcColor, Mat mask )
{
Mat gray, edges;
cvtColor( srcColor, gray, CV_BGR2GRAY );
const int MEDIAN_BLUR_FILTER_SIZE = 7;
const int LAPLACIAN_FILTER_SIZE = 5;
const int EDGES_THRESHOLD = 80;
medianBlur( gray, gray, MEDIAN_BLUR_FILTER_SIZE );
Laplacian( gray, edges, CV_8U, LAPLACIAN_FILTER_SIZE );
threshold( edges, mask, EDGES_THRESHOLD, 255, THRESH_BINARY_INV );
return( mask );
}
When I run the program, I get a blank (gray) window.
Where the first imshow is commented out, I made sure the webcam is working and I can see my own image in the window, so the problem must be elsewhere.
Can anyone help me understand where the problem is and what I am doing wrong?
Thank you,
your displayedFrame never got filled.
(you pass it into the func, it gets manipulated there, but since you gave it a copy, you don't get the result back)
either return a Mat from cartoonifyImage:
Mat displayed = cartoonifyImage( cameraFrame );
or pass references :
void cartoonifyImage( const Mat & cameraFrame, Mat & displayedFrame );
Mat cartoonifyImage( Mat srcColor )
{
Mat gray, edges, mask;
cvtColor( srcColor, gray, CV_BGR2GRAY );
const int MEDIAN_BLUR_FILTER_SIZE = 7;
const int LAPLACIAN_FILTER_SIZE = 5;
const int EDGES_THRESHOLD = 80;
medianBlur( gray, gray, MEDIAN_BLUR_FILTER_SIZE );
Laplacian( gray, edges, CV_8U, LAPLACIAN_FILTER_SIZE );
threshold( edges, mask, EDGES_THRESHOLD, 255, THRESH_BINARY_INV );
return ( mask );
}
int main( int argc, const char** argv )
{
VideoCapture camera;
camera.open(0);
if( !camera.isOpened() )
{
cerr << "Could not access the camera!" << endl;
return 1;
}
while( true )
{
Mat cameraFrame;
camera >> cameraFrame;
if( cameraFrame.empty() )
{
cerr << "Could not grab a camera frame!" << endl;
return 1;
}
//imshow( "Camera Test", cameraFrame );
Mat displayedFrame( cameraFrame.size(), CV_8UC3 );
displayedFrame = cartoonifyImage(cameraFrame);
imshow( "Cartoonifier!", displayedFrame );
int keypress = waitKey( 20 );
if( keypress == 27 ) break;
}
}