opencv playing video slow speed - c++

I have a problem with video speed, when I just run a video file in opencv it plays in normal speed.
The problem starts when I apply face and eye detection to the video it plays very slowly. I have tried to change waitKey() values , but the problem still exists.
Why is this happening?
#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
// Copy this file from opencv/data/haarscascades to target folder
string face_cascade_name = "haarcascade_frontalface_alt.xml";
string eye_cascade_name = "haarcascade_mcs_eyepair_big.xml";
CascadeClassifier face_cascade;
CascadeClassifier eye_cascade;
string window_name = "Capture - Face detection";
int filenumber; // Number of file to be saved
string filename;
int main(void)
{
VideoCapture capture("m.mp4");
if (!capture.isOpened()) // check if we succeeded
return -1;
// Load the cascade
if (!face_cascade.load(face_cascade_name))
{
printf("--(!)Error loading\n");
return (-1);
}
if (!eye_cascade.load(eye_cascade_name))
{
printf("--(!)Error loading\n eye ");
return (-1);
}
// Read the video stream
Mat frame;
for (;;)
{
capture >> frame;
// Apply the classifier to the frame
if (!frame.empty())
{
detectAndDisplay(frame);
}
else
{
printf(" --(!) No captured frame -- Break!");
break;
}
waitKey(40);
return 0;
}
}
void detectAndDisplay(Mat frame)
{
std::vector<Rect> faces;
std::vector<Rect> eyes;
Mat frame_gray;
Mat crop;
Mat res;
Mat gray;
string text;
stringstream sstm;
cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
equalizeHist(frame_gray, frame_gray);
// Detect faces
face_cascade.detectMultiScale(frame_gray, faces, 1.1, 4, CASCADE_SCALE_IMAGE, Size(20, 20));
// Set Region of Interest
size_t i = 0; // ic is index of current element
for (i = 0; i < faces.size(); i++) // Iterate through all current elements (detected faces)
{
Point pt1(faces[i].x, faces[i].y); // Display detected faces on main window - live stream from camera
Point pt2((faces[i].x + faces[i].height), (faces[i].y + faces[i].width));
rectangle(frame, pt1, pt2, Scalar(0, 255, 0), 2, 8, 0);
// set ROI for the eyes
Rect Roi = faces[i];
Roi.height = Roi.height / 4;
Roi.y = Roi.y + Roi.height;
cv::Mat crop = frame(Roi);
cvtColor(crop, gray, CV_BGR2GRAY);
imshow("ROI", gray);
eye_cascade.detectMultiScale(gray, eyes, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(20, 20));
for (size_t j = 0; j < eyes.size(); j++)
{
Rect r(Roi.x + eyes[j].x, Roi.y + eyes[j].y, eyes[j].width, eyes[j].height);
rectangle(frame, r, Scalar(255, 0, 0), 3, 1, 0);
// convert roi to ychannel
Mat eye_region = frame(eyes[j]).clone();
Mat eye_region_YCbCr;
cvtColor(eye_region, eye_region_YCbCr, CV_BGR2YCrCb);
vector<Mat> channels;
split(eye_region_YCbCr, channels);
Mat eye_region_Ychannel = channels[0].clone();
imshow("Y", eye_region_Ychannel);
// end of convert
}
}
// Show image
imshow("original", frame);
if (!crop.empty())
{
imshow("detected", crop);
}
else
{
destroyWindow("detected");
}
}

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

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)
{
// ...

Saving Images of Detected Faces in OpenCV

I have a code that detects faces and saves multiple cropped area images of them to a file path. My code doesn't stop saving images of detected faces until I physically close the program. For every one second a face is detected on a webcam, my code saves 6 images of the face.
Is it possible to have it save just one image per face detected? For example, if there is one face, only one image, if two faces, an image of both faces are saved etc. My code is below. Can anyone help me?
#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;
void detectAndDisplay(Mat frame);
string face_cascade_name = "C:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt2.xml";
CascadeClassifier face_cascade;
string window_name = "Window";
int filenumber;
string filename;
int main(void)
{
VideoCapture capture(0);
if (!capture.isOpened())
return -1;
if (!face_cascade.load(face_cascade_name))
{
cout << "error" << endl;
return (-1);
};
Mat frame;
for (;;)
{
capture >> frame;
if (!frame.empty())
{
detectAndDisplay(frame);
}
else
{
cout << "error2" << endl;
break;
}
int c = waitKey(10);
if (27 == char(c))
{
break;
}
}
return 0;
}
void detectAndDisplay(Mat frame)
{
std::vector<Rect> faces;
Mat frame_gray;
Mat crop;
Mat res;
Mat gray;
string text;
stringstream sstm;
cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
equalizeHist(frame_gray, frame_gray);
face_cascade.detectMultiScale(frame_gray, faces, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));
cv::Rect roi_b;
cv::Rect roi_c;
size_t ic = 0;
int ac = 0;
size_t ib = 0;
int ab = 0;
for (ic = 0; ic < faces.size(); ic++)
{
roi_c.x = faces[ic].x;
roi_c.y = faces[ic].y;
roi_c.width = (faces[ic].width);
roi_c.height = (faces[ic].height);
ac = roi_c.width * roi_c.height;
roi_b.x = faces[ib].x;
roi_b.y = faces[ib].y;
roi_b.width = (faces[ib].width);
roi_b.height = (faces[ib].height);
crop = frame(roi_b);
resize(crop, res, Size(128, 128), 0, 0, INTER_LINEAR);
cvtColor(crop, gray, CV_BGR2GRAY);
filename = "C:\\Users\\Desktop\\Faces\\face";
stringstream ssfn;
ssfn << filename.c_str() << filenumber << ".jpg";
filename = ssfn.str();
cv::imwrite(filename, res);
filenumber++;
Point pt1(faces[ic].x, faces[ic].y);
Point pt2((faces[ic].x + faces[ic].height), (faces[ic].y + faces[ic].width));
rectangle(frame, pt1, pt2, Scalar(0, 255, 0), 2, 8, 0);
}
sstm << "Crop area size: " << roi_b.width << "x" << roi_b.height << " Filename: " << filename;
text = sstm.str();
if (!crop.empty())
{
imshow("detected", crop);
}
else
destroyWindow("detected");
}

findContours returns assertion failed

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

Slow Video in Object Tracking Script using OpenCV

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.