How can I add a small video sequence to another video using OpenCV?
To elaborate, let's say I have a video playing which is to be interactive where let's say the user viewing the video gestures something and a short sequence plays at the bottom or at the corner of the existing video.
For each frame, you need to copy an image with the content you need inside the video frame. The steps are:
Define the size of the overlay frame
Define where to show the overlay frame
For each frame
Fill the overlay frame with some content
Copy the overlay frame in the defined position in the original frame.
This small snippet will show a random noise overlay window on bottom right of the camera feed:
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
// Video capture frame
Mat3b frame;
// Overlay frame
Mat3b overlayFrame(100, 200);
// Init VideoCapture
VideoCapture cap(0);
// check if we succeeded
if (!cap.isOpened()) {
cerr << "ERROR! Unable to open camera\n";
return -1;
}
// Get video size
int w = cap.get(CAP_PROP_FRAME_WIDTH);
int h = cap.get(CAP_PROP_FRAME_HEIGHT);
// Define where the show the overlay frame
Rect roi(w - overlayFrame.cols, h - overlayFrame.rows, overlayFrame.cols, overlayFrame.rows);
//--- GRAB AND WRITE LOOP
cout << "Start grabbing" << endl
<< "Press any key to terminate" << endl;
for (;;)
{
// wait for a new frame from camera and store it into 'frame'
cap.read(frame);
// Fill overlayFrame with something meaningful (here random noise)
randu(overlayFrame, Scalar(0, 0, 0), Scalar(256, 256, 256));
// Overlay
overlayFrame.copyTo(frame(roi));
// check if we succeeded
if (frame.empty()) {
cerr << "ERROR! blank frame grabbed\n";
break;
}
// show live and wait for a key with timeout long enough to show images
imshow("Live", frame);
if (waitKey(5) >= 0)
break;
}
// the camera will be deinitialized automatically in VideoCapture destructor
return 0;
}
Related
I'm using OpenCV 3.1, I try to run a simple code as the following one (main function):
cv::VideoCapture cam;
cv::Mat matTestingNumbers;
cam.open(0);
if (!cam.isOpened()) { printf("--(!)Error opening video capture\n"); return -1; }
while (cam.read(matTestingNumbers))
{
cv::imshow("matTestingNumbers", matTestingNumbers);
cv::waitKey(5000);
}
When I move the camera it seems that the code does not capture and show the current frame but shows all the captured frames from the previous position and only then from the new one.
So when I capture the wall it shows the correct frames (the wall itself) in the correct delay, but, when I twist the camera to my computer, I first see about 3 frames of the wall and only then the computer, it seems that the frames are stuck.
I've tried to use videoCapture.set() functions and set the FPS to 1, and I tried to switch the method of capturing to cam >> matTestingNumbers (and the rest of the main function according to this change) but nothing helped, I still got "stuck" frames.
BTW, These are the solutions I found on web.
What can I do to fix this problem?
Thank you, Dan.
EDIT:
I tried to retrieve frames as the following:
#include "opencv2/opencv.hpp"
using namespace cv;
int main(int, char**)
{
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
return -1;
Mat frame;
namedWindow("edges",1);
for(;;)
{
cap.grab();
if (waitKey(11) >= 0)
{
cap.retrieve(frame);
imshow("edges", frame);
}
}
return 0;
}
But, it gave the result (when I pointed the camera on one spot and pressed a key it showed one more of the previous frames that were captured of the other point).
It is just like you're trying to picture one person then another but when you picture the second you get the photo of the first person what doesn't make sense.
Then, I tried the following:
#include "opencv2/opencv.hpp"
using namespace cv;
int main(int, char**)
{
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
return -1;
Mat frame;
namedWindow("edges",1);
for(;;)
{
cap >> frame;
if (waitKey(33) >= 0)
imshow("edges", frame);
}
return 0;
}
And it worked as expected.
One of the problems is that you are not calling cv::waitKey(X) to properly freeze the window for X amount of milliseconds. Get rid of usleep()!
I want to subtract the two successive images taken from the webcam.
as you can see I am doing this inside a while loop. In the last line of the while loop I am setting frame2 = frame and so I can subtract them from the next iteration. But the function cv::subtract returns the above error in the terminal.
what am I doing wrong?
#include <iostream>
#include "core.hpp"
#include "highgui.hpp"
#include "imgcodecs.hpp"
#include "cv.h"
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
VideoCapture cap(0); ///open the video camera no. 0 (laptop's default camera)
///make a writer object:
cv::VideoWriter writer;
if (!cap.isOpened()) /// if not success, exit program
{
cout << "ERROR INITIALIZING VIDEO CAPTURE" << endl;
return -1;
}
char* windowName = "Webcam Feed(diff image)";
namedWindow(windowName,WINDOW_NORMAL); ///create a window to display our webcam feed
///we need to define 4 arguments for initializing the writer object:
//filename string:
string filename = "C:\\Users\\PEYMAN\\Desktop\\ForegroundExtraction\\openCV_tutorial\\2.writing from video to file\\Payman.avi";
//fourcc integer:
int fcc = CV_FOURCC('D','I','V','3');
//frame per sec integer:
int fps = 10;
//frame size:
cv::Size framesize(cap.get(CV_CAP_PROP_FRAME_WIDTH),cap.get(CV_CAP_PROP_FRAME_HEIGHT));
///initialize the writet object:
writer = VideoWriter(filename,fcc,fps,framesize);
if(!writer.isOpened()){
cout << "Error opening the file" << endl;
getchar();
return -1;
}
int counter = 0;
while (1) {
Mat frame,frame2,diff_frame;
///read a new frame from camera feed and save it to the variable frame:
bool bSuccess = cap.read(frame);
if (!bSuccess) ///test if frame successfully read
{
cout << "ERROR READING FRAME FROM CAMERA FEED" << endl;
break;
}
/// now the last read frame is stored in the variable frame and here it is written to the file:
writer.write(frame);
if (counter > 0){
cv::subtract(frame2,frame,diff_frame);
imshow(windowName, diff_frame ); ///show the frame in "MyVideo" window
}
///wait for 10ms for a key to be pressed
switch(waitKey(1)){
///the writing from webcam feed will go on until the user presses "esc":
case 27:
///'esc' has been pressed (ASCII value for 'esc' is 27)
///exit program.
return 0;
}
frame2 = frame;
counter++;
}
return 0;
}
Every time you execute the while loop frame2 is created and default initialized. When you call
cv::subtract(frame2,frame,diff_frame);
You are trying to subtract a default constructed Mat from a Mat that has an image in it. These two Mats will not be the same size so you get the error.
You need to move the declaration of frame and frame2 outside of the while loop if you want them to retain their values after each execution of the while loop. You also need to initialize frame2 to the same size or capture a second image into it so you can use subtract the first time through.
You need to declare frame2 outside the scope of the while loop like you did with counter. Right now, you get a fresh, empty frame2 with each iteration of the loop.
You might as well move all the Mats outside the while loop so that memory doesn't have to be de-allocated at the end of each iteration and re-allocated the next, although this isn't an error and you likely won't see the performance penalty in this case.
Also, #rhcpfan is right in that you need to be careful about shallow vs deep copies. Use cv::swap(frame, fram2).
I am using opencv to show frames from camera. I want to show that frames in to two separation windows. I want show real frame from camera into first window (show frames after every 30 mili-seconds) and show the frames in second window with some delay (that means it will show frames after every 1 seconds). Is it possible to do that task. I tried to do it with my code but it is does not work well. Please give me one solution to do that task using opencv and visual studio 2012. Thanks in advance
This is my code
VideoCapture cap(0);
if (!cap.isOpened())
{
cout << "exit" << endl;
return -1;
}
namedWindow("Window 1", 1);
namedWindow("Window 2", 2);
long count = 0;
Mat face_algin;
while (true)
{
Mat frame;
Mat original;
cap >> frame;
if (!frame.empty()){
original = frame.clone();
cv::imshow("Window 1", original);
}
if (waitKey(30) >= 0) break;// Delay 30ms for first window
}
You could write the loop to display frames in a single function with the video file name as the argument and call them simultaneously by multi-threading.
The pseudo code would look like,
void* play_video(void* frame_rate)
{
// play at specified frame rate
}
main()
{
create_thread(thread1, play_video, normal_frame_rate);
create_thread(thread2, play_video, delayed_frame_rate);
join_thread(thread1);
join_thread(thread2);
}
I have the code below. Is a open realtime edge detection, but i had an error on line: pProcessedFrame = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 1);
"Unhandled exception at 0x00007FF6CAF1284C in opencv2.exe: 0xC0000005: Access violation reading location 0x000000000000002C."
Anybody can resolve this insue?
My configuration is Visual Studio 2013 and Opencv 2.4.10
#include <iostream>
#include "opencv/cv.h"
#include "opencv/highgui.h"
using namespace std;
// Define the IplImage pointers we're going to use as globals
IplImage* pFrame;
IplImage* pProcessedFrame;
IplImage* tempFrame;
// Slider for the low threshold value of our edge detection
int maxLowThreshold = 1024;
int lowSliderPosition = 150;
// Slider for the high threshold value of our edge detection
int maxHighThreshold = 1024;
int highSliderPosition = 250;
// Function to find the edges of a given IplImage object
IplImage* findEdges(IplImage* sourceFrame, double thelowThreshold, double theHighThreshold, double theAperture)
{
// Convert source frame to greyscale version (tempFrame has already been initialised to use greyscale colour settings)
cvCvtColor(sourceFrame, tempFrame, CV_RGB2GRAY);
// Perform canny edge finding on tempframe, and push the result back into itself!
cvCanny(tempFrame, tempFrame, thelowThreshold, theHighThreshold, theAperture);
// Pass back our now processed frame!
return tempFrame;
}
// Callback function to adjust the low threshold on slider movement
void onLowThresholdSlide(int theSliderValue)
{
lowSliderPosition = theSliderValue;
}
// Callback function to adjust the high threshold on slider movement
void onHighThresholdSlide(int theSliderValue)
{
highSliderPosition = theSliderValue;
}
int main(int argc, char** argv)
{
// Create two windows
cvNamedWindow("WebCam", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Processed WebCam", CV_WINDOW_AUTOSIZE);
// Create the low threshold slider
// Format: Slider name, window name, reference to variable for slider, max value of slider, callback function
cvCreateTrackbar("Low Threshold", "Processed WebCam", &lowSliderPosition, maxLowThreshold, onLowThresholdSlide);
// Create the high threshold slider
cvCreateTrackbar("High Threshold", "Processed WebCam", &highSliderPosition, maxHighThreshold, onHighThresholdSlide);
// Create CvCapture object to grab data from the webcam
CvCapture* pCapture;
// Start capturing data from the webcam
pCapture = cvCaptureFromCAM(CV_CAP_V4L2);
// Display image properties
cout << "Width of frame: " << cvGetCaptureProperty(pCapture, CV_CAP_PROP_FRAME_WIDTH) << endl; // Width of the frames in the video stream
cout << "Height of frame: " << cvGetCaptureProperty(pCapture, CV_CAP_PROP_FRAME_HEIGHT) << endl; // Height of the frames in the video stream
cout << "Image brightness: " << cvGetCaptureProperty(pCapture, CV_CAP_PROP_BRIGHTNESS) << endl; // Brightness of the image (only for cameras)
cout << "Image contrast: " << cvGetCaptureProperty(pCapture, CV_CAP_PROP_CONTRAST) << endl; // Contrast of the image (only for cameras)
cout << "Image saturation: " << cvGetCaptureProperty(pCapture, CV_CAP_PROP_SATURATION) << endl; // Saturation of the image (only for cameras)
cout << "Image hue: " << cvGetCaptureProperty(pCapture, CV_CAP_PROP_HUE) << endl; // Hue of the image (only for cameras)
// Create an image from the frame capture
pFrame = cvQueryFrame(pCapture);
// Create a greyscale image which is the size of our captured image
pProcessedFrame = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 1);
// Create a frame to use as our temporary copy of the current frame but in grayscale mode
tempFrame = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 1);
// Loop controling vars
char keypress;
bool quit = false;
while (quit == false)
{
// Make an image from the raw capture data
// Note: cvQueryFrame is a combination of cvGrabFrame and cvRetrieveFrame
pFrame = cvQueryFrame(pCapture);
// Draw the original frame in our window
cvShowImage("WebCam", pFrame);
// Process the grame to find the edges
pProcessedFrame = findEdges(pFrame, lowSliderPosition, highSliderPosition, 3);
// Showed the processed output in our other window
cvShowImage("Processed WebCam", pProcessedFrame);
// Wait 20 milliseconds
keypress = cvWaitKey(20);
// Set the flag to quit if escape was pressed
if (keypress == 27)
{
quit = true;
}
} // End of while loop
// Release our stream capture object to free up any resources it has been using and release any file/device handles
cvReleaseCapture(&pCapture);
// Release our images
cvReleaseImage(&pFrame);
cvReleaseImage(&pProcessedFrame);
// This causes errors if you don't set it to NULL before releasing it. Maybe because we assign
// it to pProcessedFrame as the end result of the findEdges function, and we've already released pProcessedFrame!!
tempFrame = NULL;
cvReleaseImage(&tempFrame);
// Destory all windows
cvDestroyAllWindows();
}
Thank you all. I found solution, my cam not capturing image, I change to another camera and now the code is running fine.
I'm trying to modify and write some video using openCV 2.4.6.1 using the following code:
cv::VideoCapture capture( video_filename );
// Check if the capture object successfully initialized
if ( !capture.isOpened() )
{
printf( "Failed to load video, exiting.\n" );
return -1;
}
cv::Mat frame, cropped_img;
cv::Rect ROI( OFFSET_X, OFFSET_Y, WIDTH, HEIGHT );
int fourcc = static_cast<int>(capture.get(CV_CAP_PROP_FOURCC));
double fps = 30;
cv::Size frame_size( RADIUS, (int) 2*PI*RADIUS );
video_filename = "test.avi";
cv::VideoWriter writer( video_filename, fourcc, fps, frame_size );
if ( !writer.isOpened() && save )
{
printf("Failed to initialize video writer, unable to save video!\n");
}
while(true)
{
if ( !capture.read(frame) )
{
printf("Failed to read next frame, exiting.\n");
break;
}
// select the region of interest in the frame
cropped_img = frame( ROI );
// display the image and wait
imshow("cropped", cropped_img);
// if we are saving video, write the unwrapped image
if (save)
{
writer.write( cropped_img );
}
char key = cv::waitKey(30);
When I try to run the output video 'test.avi' with VLC I get the following error: avidemux error: no key frame set for track 0. I'm using Ubuntu 13.04, and I've tried using videos encoded with MPEG-4 and libx264. I think the fix should be straightforward but can't find any guidance. The actual code is available at https://github.com/benselby/robot_nav/tree/master/video_unwrap. Thanks in advance!
[PYTHON] Apart from the resolution mismatch, there can also be a frames-per-second mismatch. In my case, the resolution was correctly set, but the problem was with fps. Checking the frames per second at which VideoCapture object was reading, it showed to be 30.0, but if I set the fps of VideoWriter object to 30.0, the same error was being thrown in VLC. Instead of setting it to 30.0, you can get by with the error by setting it to 30.
P.S. You can check the resolution and the fps at which you are recording by using the cap.get(3) for width, cap.get(4) for height and cap.get(5) for fps inside the capturing while/for loop.
The full code is as follows:
import numpy as np
import cv2 as cv2
cap = cv2.VideoCapture(0)
#Define Codec and create a VideoWriter Object
fourcc = cv2.VideoWriter_fourcc('X','V','I','D')
#30.0 in the below line doesn't work while 30 does work.
out = cv2.VideoWriter('output.mp4', fourcc, 30, (640, 480))
while(True):
ret, frame = cap.read()
colored_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2BGRA)
print('Width = ', cap.get(3),' Height = ', cap.get(4),' fps = ', cap.get(5))
out.write(colored_frame)
cv2.imshow('frame', colored_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
The full documentation (C++) for what all properties can be checked is available here : propId OpenCV Documentation
This appears to be an issue of size mismatch between the frames written and the VideoWriter object opened. I was running into this issue when trying to write a series of resized images from my webcam into a video output. When I removed the resizing step and just grabbed the size from an initial test frame, everything worked perfectly.
To fix my resizing code, I essentially ran a single test frame through my processing and then pulled its size when creating the VideoWriter object:
#include <cassert>
#include <iostream>
#include <time.h>
#include "opencv2/opencv.hpp"
using namespace cv;
int main()
{
VideoCapture cap(0);
assert(cap.isOpened());
Mat testFrame;
cap >> testFrame;
Mat testDown;
resize(testFrame, testDown, Size(), 0.5, 0.5, INTER_NEAREST);
bool ret = imwrite("test.png", testDown);
assert(ret);
Size outSize = Size(testDown.cols, testDown.rows);
VideoWriter outVid("test.avi", CV_FOURCC('M','P','4','2'),1,outSize,true);
assert(outVid.isOpened());
for (int i = 0; i < 10; ++i) {
Mat frame;
cap >> frame;
std::cout << "Grabbed frame" << std::endl;
Mat down;
resize(frame, down, Size(), 0.5, 0.5, INTER_NEAREST);
//bool ret = imwrite("test.png", down);
//assert(ret);
outVid << down;
std::cout << "Wrote frame" << std::endl;
struct timespec tim, tim2;
tim.tv_sec = 1;
tim.tv_nsec = 0;
nanosleep(&tim, &tim2);
}
}
My guess is that your problem is in the size calculation:
cv::Size frame_size( RADIUS, (int) 2*PI*RADIUS );
I'm not sure where your frames are coming from (i.e. how the capture is set up), but likely in rounding or somewhere else your size gets messed up. I would suggest doing something similar to my solution above.