Can't cat image from the videostream opencv - c++

Other questions did't help me, so i ask mine
Can't get any image from my videocam using the latest opencv library.
void ShowCam(int CameraToBeOpened)
{
int i = 0;
cv::Mat frame;
cv::VideoCapture cap(CameraToBeOpened);
cvNamedWindow("Camera", CV_WINDOW_NORMAL);
while (true) {
if (cap.read(frame))
imshow("Camera", frame);
char c = cvWaitKey(50);
if (c == 27)
break;
if (c == 32) {
char filename[200];
sprintf_s(filename, "\Test pictures\test_%d.jpg", i);
i++;
cv::imwrite(filename, frame);
std::cout << "Image has been captured" << std::endl;
}
}
It doesn't generate mistakes, just can't find images in the folder.

Related

Playing video by long key press using open cv

I need to make small video player with OpenCV, which have to support the following functionality. Key 'p' on keyboard - pause/unpause, 'q' - exit, left and right arrow keys - play video frame by frame straight and reverse when it is paused. So the problem is when I try to show video with high quality and I hold arrow key for several seconds it does not run, but freeze and then jump to current frame after I release key. I tried to fix this with adding this_thread::sleep after cv::imshow() to give time to draw, but it did not help at all. So here is the code. Also, I have some reasons to use boost instead of C++11, so it is ok.
main.cpp
#include "VideoPlayer.hpp"
#include <iostream>
int main(int argc, char *argv[])
{
if (argc < 2) {
std::cerr << "Video file full name required as argument." << std::endl;
}
VideoPlayer vp(argv[1]);
if (!vp.play())
return 1;
return 0;
}
VideoPlayer.hpp
#pragma once
#include <opencv/cxcore.hpp>
#include <opencv/highgui.h>
#include <string>
class VideoPlayer
{
public:
VideoPlayer(const std::string &video, const std::string &windowName = "Output window",
unsigned int delay = 30);
bool play();
private:
cv::VideoCapture videoCapture_;
std::string windowName_;
unsigned int delay_;
private:
bool processKey(int key);
void setFrame(int frameNum);
};
VideoPlayer.cpp
#include "VideoPlayer.hpp"
#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>
VideoPlayer::VideoPlayer(const std::string &video, const std::string &windowName,
unsigned int delay)
: videoCapture_(video)
, windowName_(windowName)
, delay_(delay)
{}
bool VideoPlayer::play()
{
if (!videoCapture_.isOpened()) {
std::cerr << "Unable to open video." << std::endl;
return false;
}
cv::namedWindow(windowName_);
for (;;) {
cv::Mat frame;
videoCapture_ >> frame;
cv::imshow(windowName_, frame);
int key = cv::waitKey(delay_);
if (processKey(key))
break;
}
return true;
}
bool VideoPlayer::processKey(int key)
{
if (key == 'p') {
for (;;) {
int pausedKey = cv::waitKey(0);
if (pausedKey == 'p') {
break;
} else if (pausedKey == 'q') {
return true;
} else if (pausedKey == 65363) {
int frameNum = videoCapture_.get(CV_CAP_PROP_POS_FRAMES);
setFrame(frameNum);
} else if (pausedKey == 65361) {
int frameNum = videoCapture_.get(CV_CAP_PROP_POS_FRAMES);
setFrame(frameNum - 2);
}
}
} else if (key == 'q') {
return true;
}
return false;
}
void VideoPlayer::setFrame(int frameNum)
{
if (frameNum > 0 && frameNum < videoCapture_.get(CV_CAP_PROP_FRAME_COUNT)) {
std::cerr << frameNum << std::endl;
videoCapture_.set(CV_CAP_PROP_POS_FRAMES, frameNum);
cv::Mat frame;
videoCapture_ >> frame;
cv::imshow(windowName_, frame);
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
}
}
I also created a multithreading implementation with buffer based on std::queue with lock, but it didn't solve the problem. And I tried to use boost::lockfree::queue, but I could not manage to finish it because of some strange behavior. I will share this code later, if it is necessary.
So, if somebody knows some good practice, how to avoid this problem, help me please.
EDIT:
Replacing boost::this_thread::sleep(boost::posix_time::milliseconds(10)); with cv::waitKey(0) is bad, because is makes me to do two short presses on arrow key to change one frame, and it does not help, because holding key skips it very fast. So the following code helped, but it is too strange and it is necessary to select times each for each video.
void VideoPlayer::setFrame(int frameNum)
{
if (frameNum > 0 && frameNum < videoCapture_.get(CV_CAP_PROP_FRAME_COUNT)) {
std::cerr << frameNum << std::endl;
videoCapture_.set(CV_CAP_PROP_POS_FRAMES, frameNum);
cv::Mat frame;
videoCapture_ >> frame;
cv::imshow(windowName_, frame);
int times = 7;
for (int i = 0; i < times; i++)
cv::waitKey(10);
}
}
Also, I'm unable to use Qt or something else, only C++03 with boost and OpenCV.
I think I need some trick to make cv::waitKey(time) wait fortime whether any key pressed or not.

How can I know if a image is RGB in OpenCV?

I've made a program in c++ using OpenCV library. The program record video from webcam and then split it in frames. I want to know if the frames are in RGB beacuse i want to access the RGB properties of every pixel. The codec for capture is CV_FOURCC('M','J','P','G'). How can i get the frames in RGB colorspace?
int main() {
Mat image;
VideoCapture cap(0);
cap.set(CV_CAP_PROP_FPS, 10);
if ( !cap.isOpened() ) {
cout << "ERROR : Cannot open the video file"<<endl;
return -1;
}
namedWindow("MyWindow", CV_WINDOW_AUTOSIZE);
double dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH);
double dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
cout << "Frame size :" << dWidth << "x" << dHeight << endl;
Size frameSize(static_cast<int>(dWidth), static_cast<int>(dHeight));
VideoWriter oVideoWriter("E:/myVideo.avi", CV_FOURCC('M', 'J', 'P', 'G'), 10, frameSize, true);
if (!oVideoWriter.isOpened()) {
cout << "ERROR : Failed to write the video"<<endl;
return - 1;
}
while (1) {
Mat image;
bool bSuccess = cap.read(image);
if (!bSuccess) {
cout << "ERROR : Cannot read a frame from video file" << endl;
break;
}
oVideoWriter.write(image);
imshow("MyWindow", image);
if (waitKey(10) == 27) {
saveImages();
cout << "ESC key is pressed by user" << endl;
break
}
}
return 0;
}
int saveImages() {
CvCapture *capture = cvCaptureFromFile("E:/myVideo.avi");
if(!capture)
{
cout<<"!!! cvCaptureFromAVI failed (file not found?)"<<endl;
return -1;
}
int fps = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FPS);
IplImage* frame = NULL;
int frame_number = 0;
char key = 0;
while (key != 'q')
{
frame = cvQueryFrame(capture);
if (!frame)
{
cout<<"!!! cvQueryFrame failed: no frame"<<endl;
break;
}
char filename[100];
strcpy(filename, "frame_");
char frame_id[30];
_itoa(frame_number, frame_id, 10);
strcat(filename, frame_id);
strcat(filename, ".jpg");
printf("* Saving: %s\n", filename);
if (!cvSaveImage(filename, frame))
{
cout<<"!!! cvSaveImage failed"<<endl;
break;
}
frame_number++;
key = cvWaitKey(1000 / fps);
}
cvReleaseCapture(&capture);
return 0;
}
When OpenCV loads colored images (i.e. 3 channel) from the disk, camera, or a video file, the image data will be stored in the BGR format. This is a simple test that you can do:
/* Code using the C++ API */
cv::VideoCapture cap(0);
if (!cap.isOpened()) {
std::cout << "!!! Failed to open webcam" << std::endl;
return -1;
}
if (!cap.read(frame)) {
std::cout << "!!! Failed to read a frame from the camera" << std::endl;
return -1;
}
bool is_colored = false;
if (frame.channels() == 3) {
is_colored = true;
}
// Do something with is_colored
// ...
Unless you have a weird camera, the frames will always be colored (and as result, stored as BGR).
When cv::imwrite() (C++ API) or cvSaveImage() (C API) are called, OpenCV does the proper magic tricks to ensure the data is saved in a compatible way with requested output format (JPG, PNG, AVI, etc) and during this process it automatically converts the data to RGB if it needs to.
Nevertheless, if for some reason you need to convert the image to RGB you can call:
cv::Mat img_rgb;
cv::cvtColor(frame, img_rgb, CV_BGR2RGB);
Please note that OpenCV has a C API and also a C++ API, and they shouldn't be mixed:
If you use IplImage then stick with the rest of the C API.
If you decide to go with cv::Mat, then keep using the C++ API.
There are different ways to access the pixels of a cv::Mat, here is one of them:
unsigned char* pixels = (unsigned char*)(frame.data);
for (int i = 0; i < frame.rows; i++)
{
for (int j = 0; j < frame.cols; j++)
{
char b = pixels[frame.step * j + i] ;
char g = pixels[frame.step * j + i + 1];
char r = pixels[frame.step * j + i + 2];
}
}

OpenCV does not free camera

I'm trying to release the camera in OpenCV and reinitialize it another time, but the problem is, I cannot properly release the camera. Asking OpenCV, the cv::VideoCapture, whether the camer is open or not, it says closed, but the little LED is still glowing and I cannot create another VideoCapture object around the same camera.
This is the include I use:
#include <opencv2/opencv.hpp>
This is a little sample of code showing the problem:
cv::VideoCapture cap(0);
for(int i = 0; i < 20; i++) {
cv::Mat frame;
cap >> frame;
cv::imshow("Test", frame);
if (cv::waitKey(30) >= 0) { break; }
}
cap.release();
std::cout << "Camera is closed is : " << !cap.isOpened() << std::endl;
while(true) {
if (cv::waitKey(30) >= 0) { break; }
}
As already mentioned, the output says the camera is closed, but the LED is glowing. When I try to create a new VideoCapture around the camera it fails and says the camera is busy.
Any ideas?
This might be a bug of OpenCV 2.4.8 with some devices, you should check their bug tracker and post this issue there.
A fix for this problem might could be accomplished by putting the variable cap inside another scope:
{
cv::VideoCapture cap(0);
for(int i = 0; i < 20; i++) {
cv::Mat frame;
cap >> frame;
cv::imshow("Test", frame);
if (cv::waitKey(30) >= 0)
break;
}
}
/* At this point, cap was destroyed and your camera should be operational again */
{
cv::VideoCapture cap(0);
for(int i = 0; i < 20; i++) {
cv::Mat frame;
cap >> frame;
cv::imshow("AnotherTest", frame);
if (cv::waitKey(30) >= 0)
break;
}
}
The documentation says that the camera will be deinitialized automatically in VideoCapture destructor.
The code should be enough to fix the problem. But as you noticed, the problem remains, so could be 1 of 2 things:
This is really an issue inside OpenCV;
There's a bug in driver of the camera, so updating it might solve the problem.

Write/save videostream if detection true

I want to write a videostream after detection is found true.
I use this link as Videowrite example
My code implementation looks like that:
int main(int argc, const char** argv) {
bool detection = false;
VideoCapture cap(-1);
if (!cap.isOpened())
{
printf("ERROR: Cannot open the video file");
}
namedWindow("MyVideo", CV_WINDOW_AUTOSIZE);
double dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH);
double dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
cout << "Frame Size = " << dWidth << "x" << dHeight << endl;
Size frameSize (static_cast<int>(dWidth), static_cast<int>(dHeight));
VideoWriter record ("/home/hacker/MyVideo.avi", CV_FOURCC('P','I','M','1'),
30, frameSize, true);
if (!record.isOpened())
{
printf("Error: Failed to write the video");
return -1;
}
while (true)
{
Mat frame;
if (!frame.empty())
{
detectAndDisplay(frame);
}
else
{
printf(" --(!) No captured frame -- Break!"); break;
}
if (detection == true)
{
record.write(frame);
}
char c = cvWaitKey(33);
if (c == 27) { break; }
}
return 0;
}
In my home directory I can see the Myvideo.avi but it's empty.
I got the following errors on command line:
VIDIOC_QUERMENU: Invalid argument
VIDIOC_QUERMENU: Invalid argument
Frame size: 640x480 Output #0, avi, to '/home/hacker/MyVideo.avi":
Stream #0.0: Video: mpeg1video (hq), yvu420p, 640x480, q=2-31, 19660
kb/s, 9ok tbn, 23,98 tbc
--(!) No captured frame -- Break! Process returned 0 (0x0) execution time: 0,75 s
You should release videowriter ( record.Release(); ). It closes file.
I try to solve it like this:
But i have 2 problems:
I want to save the MyVideo.avi if detecAndDisplay(frame) == true. But he saves it anyway(with an empty video record). And if that save the video recording is running faster.
int main( int argc, const char** argv ) {
Mat frame;
VideoCapture capture(-1); // open the default camera
if( !capture.isOpened() )
{
printf("Camera failed to open!\n");
return -1;
}
capture >> frame; // get first frame for size
for(;;)
{
// get a new frame from camera
capture >> frame;
//-- 3. Apply the classifier to the frame
if( !frame.empty() )
{
detectAndDisplay( frame );
}
if(detectAndDisplay(frame)==true)
{
// record video
VideoWriter record("MyVideo.avi", CV_FOURCC('D','I','V','X'), 30, frame.size(), true);
if( !record.isOpened() )
{
printf("VideoWriter failed to open!\n");
return -1;
}
// add frame to recorded
record << frame;
}
if(waitKey(30) >= 0) break;
}
return 0;
}
/** #function detectAndDisplay */
/** this function detect face draw a rectangle around and detect eye & mouth and draw a circle around */
bool detectAndDisplay( Mat frame ) {
...
...
return true;
}
This might be why your video file was empty.
bool detection = false;
...
if (detection == true)
{
record.write(frame);
}

OpenCV frame capture from AVI

I am working on a project with openCV 2.2. I need to do processing on each frame of an AVI file but when I run my code it only grabs the first frame of the file. The CV_CAP_PROP_POS_FRAMES does not seem to be working. Any ideas why not?
CvCapture* capture = cvCaptureFromAVI("test1.avi");
IplImage *img = 0;
if (!cvGrabFrame(capture)) {
printf("Error: Couldn't open the image file.\n");
return 1;
}
int numFrames = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT);
int posFrame = 1;
for(int i =0; i <= numFrames; i++){
cvSetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES, i);
posFrame = cvGetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES);
img = cvGrabFrame(capture);
cvNamedWindow("Image:", CV_WINDOW_AUTOSIZE);
cvShowImage("Image:", img);
printf("%i\n",posFrame);
cvWaitKey(0);
cvDestroyWindow("Image:");
}
Why don't you try this way using OpenCV 2.3? I think it is more direct and efficient, and more clear to your eyes:
VideoCapture _videoSource;
if(!_videoSource.open("test1.avi"))
{
exit(1); // Exit if fail
}
_videoSource.set(CV_CAP_PROP_CONVERT_RGB, 1);
Mat frame;
namedWindow("Image");
int posFrame;
while(1)
{
_videoSource >> frame;
posFrame=_videoSource.get(CV_CAP_PROP_POS_FRAMES);
imshow("output", frame);
return 0;
}
Something like this should work.