Get device ID from current capture - c++

I'm using OpenCV to get some video frames. This is how the camera capture is initialised:
VideoCapture capture;
capture.open(0); //Read from camera #0
If I wanted to switch to different camera, I'd do this:
capture.release(); //Release the stream
capture.open(1); //Open different stream
Imagine you had a few cameras connected to your computer and you wanted to loop through them using two buttons Previous camera and Next camera. Without saving the current camera ID to a variable, I need to get the actual value from the VideoCapture object.
So is there a way how to find out the id of currently used device?
Pseudocode:
int current = capture.deviceId;
capture.release();
capture.open(current++);

So is there a way how to find out the id of currently used device?
There's no way to do this because class VideoCapture doesn't contain such variable or method. It actually contains protected pointer to CvCapture (take a look at highgui.h) so you could try to play with it but you don't have access to this field.

Related

using OpenCV to capture images, not video

I'm using OpenCV4 to read from a camera. Similar to a webcam. Works great, code is somewhat like this:
cv::VideoCapture cap(0);
cap.set(cv::CAP_PROP_FRAME_WIDTH , 1600);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, 1200);
while (true)
{
cv::Mat mat;
// wait for some external event here so I know it is time to take a picture...
cap >> mat;
process_image(mat);
}
Problem is, this gives many video frames, not a single image. This is important because in my case I don't want nor need to be processing 30 FPS. I actually have specific physical events that trigger reading the image from the camera at certain times. Because OpenCV is expecting the caller to want video -- not surprising considering the class is called cv::VideoCapture -- it has buffered many seconds of frames.
What I see in the image is always from several seconds ago.
So my questions:
Is there a way to flush the OpenCV buffer?
Or to tell OpenCV to discard the input until I tell it to take another image?
Or to get the most recent image instead of the oldest one?
The other option I'm thinking of investigating is using V4L2 directly instead of OpenCV. Will that let me take individual pictures or only stream video like OpenCV?

how to use cv::VideoCapture::waitAny() in opencv

I've been trying to find a way to asynchronously check to see if the next frame of the camera that I get using videocapture is ready.
I came across waitAny() which is described to "Wait for ready frames from VideoCapture.".
in the OpenCV documentation, I didn't find any useful info on how to use this or what are the use cases.
I've been searching the net for two days now and the only thing I found is how to define the parameters this function needs(I'm new to c++) and I don't know how to fill them and what are their use cases.
here is the documentation: https://docs.opencv.org/master/d8/dfe/classcv_1_1VideoCapture.html#ade1c7b8d276fea4d000bc0af0f1017b3
An approach that IMO is fairly common is to have a pair of threads -- one that "produces" frames from VideoCapture (calls VideoCapture::read() in a loop), and another that actually uses these frames (a "consumer"). The producer pushes images onto a queue (that's shared across two threads), while the consumer pops them.
In this situation, checking whether a camera has produced an image amounts to checking whether the queue is empty.
By itself, VideoCapture does not provide such an async API.
That said, if you want to use waitAny, and if you have a single camera, you could do something like this:
VideoCapture cap = /* get the VideoCapture object from somewhere */
constexpr int64 kTimeoutNs = 1000;
std::vector<int> ready_index;
cv::Mat image;
if (VideoCapture::waitAny({cap}, ready_index, kTimeoutNs)) {
// Camera was ready; get image.
cap.retrieve(image);
} else {
// Camera was not ready; do something else.
}
Above, VideoCapture::waitAny will wait for the specified timeout (1 microsecond) for the camera to produce a frame, and will return after this period.
If the camera is ready, it will return true (and will also populate ready_index with the index of the ready camera. Since you only have a single camera, the vector will be either empty or non-empty).
That said, waitAny seems to only be supported by VideoCapture sources that use V4L in the backend.

Proper use of cv::VideoCapture

I've been having some issues regarding capturing video from a live stream.
I open up the video with the open function of the cv::VideoCapture. However I need to manually ask when a frame is ready in something like this:
while (true){
cv::Mat frame;
if (videoCapture.read(frame)){
// Do stuff ...
}
else{
// Video is done.
}
}
The problem with this code is that it will definitely process a single frame multiple times, the number of times depending on the camera's FPS. This is because the read() function will only return false if the camera is disconnected, according to the documentation.
So my question is, how can I know if there is a NEW frame available? That I'm not just getting the old one again?

OpenCV multiple cameras single image

I'm trying to access multiple usb-cameras in openCV with MacOS 10.11.
My goal is to connect up to 20 cameras to the pc via USB Quad-Channel extensions and take single images. I do not need to have live streaming.
I tried with the following code and I can take a single image from all cameras (currently only 3, via one usb controller).
The question is: does opencv stream a live video from the usb cameras all the time, or does grab() stores an image on the camera which can be retrieve with retrieve() ?
I couldn't find the information, wether opencv uses the grab() command on it's internal video buffer, or on the camera.
int main(int argument_number, char* argument[])
{
std::vector<int> cameraIDs{0,1,2};
std::vector<cv::VideoCapture> cameraCaptures;
std::vector<std::string> nameCaptures{"a","b","c"};
//Load all cameras
for (int i = 0;i<cameraIDs.size();i++)
{
cv::VideoCapture camera(cameraIDs[i]);
if(!camera.isOpened()) return 1;
camera.set(CV_CAP_PROP_FRAME_WIDTH, 640);
camera.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
cameraCaptures.push_back(camera);
}
cv::namedWindow("a");
while(true) {
int c = cvWaitKey(2);
if(27 == char(c)){ //if esc pressed. grab new image and display it.
for (std::vector<cv::VideoCapture>::iterator it=cameraCaptures.begin();it!=cameraCaptures.end();it++)
{
(*it).grab();
}
int i=0;
for (std::vector<cv::VideoCapture>::iterator it=cameraCaptures.begin();it!=cameraCaptures.end();it++)
{
cv::Mat3b frame;
(*it).retrieve(frame);
cv::imshow(nameCaptures[i++], frame);
}
}
}
return 0;
}
Could you please make the statement more clear. You only want the frame from the feed or you want the streams to be connected all the time.
Opencv camera capture is always in running mode unless you release the capture device. So if you say you want only one frame from a device then its better to release this device once you retrieve the frame.
Another point is instead of using grab or retrieve in a multi cam environment, its better to use read() which combines both the above methods and reduces the overhead in decoding streams. So if you want say frame # 2sec position from each of the cams then in time domain they are pretty closely captured as in say the frame x from cam1 captured # 2sec position then frame x at 2.00001sec and frame x from cam3 captured at 2.00015sec..(time multiplexing - multithreading - internal by ocv)
I hope I am clear in explanation.
Thanks

Showing a rectangle over a video from camera

Basically I need to capture the video from videocamera do some processing on frames and for each frame show a rectangle of detection.
Example: http://www.youtube.com/watch?v=aYd2kAN0Y20
How would you superimpose this rectangle on the output of videocamera (usb)? (c++)
I would use OpenCV, an open source imaging library to get input from a webcam/video file.
Here is a tutorial on how to install it:
http://opensourcecollection.blogspot.com.es/2011/04/how-to-setup-opencv-22-in-codeblocks.html
Then I would use this code:
CvCapture *capture = cvCreateCameraCapture(-1);
IplImage* frame = cvQueryFrame(capture);
To get the image, frame from the CvCapture, capture.
In this case, capture is taken directly from a video camera, but you can also create it from a video file with:
CvCapture *capture = cvCreateFileCapture("filename.avi");
Then, I would draw on the image with functions defined here: http://opencv.willowgarage.com/documentation/drawing_functions.html
By the way, the shape in the Youtube video is not a rectangle. It's a parallelogram.
If you want to do it live, then you can basically put this in a loop, getting a frame, processing it, drawing on it, and then outputting the image, like this:
You would include this before your loop:
cvNamedWindow("Capture", CV_WINDOW_AUTOSIZE);
And then, in your loop, you would say this:
cvShowImage("Capture", frame);
After the processing.
EDIT To do this in C++, open your webcam like this:
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
return -1;
To initialize it from a file, instead of putting in the camera index, put the file path.
Get a frame from the camera like this:
Mat frame;
cap >> frame; // get a new frame from camera
Then you can find drawing functions here:
http://opencv.willowgarage.com/documentation/cpp/core_drawing_functions.html
Cheers!