Ask Your Question
1

Capture from two webcam

asked 2016-05-30 07:56:11 -0600

updated 2016-05-31 08:24:02 -0600

i have two web cams ( Laptop's cam and an USB webcam )

i tried to capture from two cams at the same time with the code below.

it is working but one of the cams is lagging.

when i make two exe file ( one exe capturing from cam 0 other from cam 1 ) and run two exe at the same time, both cam streaming without lagging.

any advice to this problem ?

EDIT: i edited the code according to @pklab 's comment.

yes! i get better result with this modification.

but still not good as two running exe :(

Note:

running on Windows 10

Video I/O: DirectShow

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, const char * argv[])
{
    VideoCapture cap0(0);
    VideoCapture cap1(1);

    cap0.set(CV_CAP_PROP_FPS, 15);
    cap1.set(CV_CAP_PROP_FPS, 15);

    Mat frame0, frame1;

    for (;;)
    {

        if (!(cap0.grab() && cap0.grab())) {
            std::cerr << "Unable to grab from one or both cameras";
            break;
        }

        cap0.retrieve(frame0);
        cap1.retrieve(frame1);

        if (!frame0.empty())
        {
            imshow("cap0", frame0);
        }

        if (!frame1.empty())
        {
            imshow("cap1", frame1);
        }

        int key = waitKey(10);
        if (key == 27)
            break;
    }
}
edit retag flag offensive close merge delete

Comments

I think that grabbing with grab() and retrieve() sequence instead of >> or read() would help. See this my answer :)

pklab gravatar imagepklab ( 2016-05-30 08:56:11 -0600 )edit

@pklab thanks. i will try it. i tried to find some information before asking but missed it.

sturkmen gravatar imagesturkmen ( 2016-05-30 09:06:34 -0600 )edit
1

@sturkmen don't worry... because of bad tagging and poor docs organization it's hard to find thinks also for experienced people...we already know :)

pklab gravatar imagepklab ( 2016-05-30 09:25:12 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
4

answered 2016-05-31 06:17:54 -0600

pklab gravatar image

updated 2016-05-31 13:10:43 -0600

Try using 2 threads. Here is a simple GrabberThread class. Below you can find an example

#include <queue>
#include <thread>
#include <mutex>
#include <atomic>
#include <string>


/** @brief Example Class that grabs from cv::VideoCapture into a queue.

It can be used as worker thread. 

Even if you grab N frames and create N x Mat in the queue
only few blocks will be really allocated thanks to @c std::vector 
and @c cv::Mat memory recycling. Look at @c matMemoryCounter to 
know how many memory blocks has been allocated
@author PkLab answer to question:
@see http://answers.opencv.org/question/95193/capture-from-two-webcam/
@note It can be done much better but it's better than nothing :)
@note It requires C++11 or later
*/
class GrabberThread{
private:
    int device;
    std::mutex mtx;
    std::queue<cv::Mat > buffer;
    std::atomic<bool> grabOn;
    VideoCapture cap;
    size_t bufSizeMax; 
    std::map<unsigned char*, int> matMemoryCounter;
public:
    GrabberThread() : grabOn(false), device(0), bufSizeMax(0){};
    ~GrabberThread()
    {
        grabOn.store(false);
        cap.release();
        while (!buffer.empty())
            buffer.pop();
        matMemoryCounter.clear();

    }
    /* @brief initialize members and open the capture device
    @return true if the device has successfully opened
    */
    bool Init(int dev = 0)
    {
        device = dev;
        cap.open(device);
        return cap.isOpened();
    }

    /* @brief Disable the grabbing loop control var. 
    This will stop the grabbing thread
    */
    void StopGrabing()
    {
        grabOn.store(false);
    }

    /** @brief This is the thread that grabs into a queue
    @note In real application locks and multiple copyTo can be avoided 
     using better queue/circular buffer!
    */
    void GrabThread() 
    {
        matMemoryCounter.clear();
        uchar * frameMemoryAddr;

        if (!cap.isOpened()) cap.open(device);
        if (!cap.isOpened()) return;

        cv::Mat tmp;
        grabOn.store(true);
        while (grabOn.load() == true) //this is lock free
        {
            //read() will wait for cam FPS. 
            //keep grab out of lock so that
            //idle time can be used by other threads
            if (!cap.read(tmp))
                continue;
            //get lock only when we have a frame
            mtx.lock();
            /** @warning Avoid @c buffer.push_back(tmp) because it stores items by reference.
            We have to create a new cv::Mat for each frame
            STL and cv::Mat will recycle memory
            */
            buffer.push(cv::Mat(tmp.size(), tmp.type()));
            tmp.copyTo(buffer.back());
            //count how many times this memory block has been used
            frameMemoryAddr = buffer.front().data;
            matMemoryCounter[frameMemoryAddr]++;
            bufSizeMax = max(bufSizeMax, buffer.size());

            mtx.unlock();
            /* SHOW THE FRAME if do you want
            string winName = "Live Thread Dev: " + std::to_string(device);
            int font = CV_FONT_HERSHEY_PLAIN;
            cv::putText(tmp, winName, cv::Point(10, 10), font, 1, cv::Scalar(0, 255, 0));
            imshow(winName, tmp);
            cv::waitKey(1);    //just for imshow
            */
        } // while
    } // func

    /** @brief Get the oldest grabbed frame if available

    The frame is copied from the buffer than it can used freely

    @Param [out]frame the the oldest grabbed frame. if not available it will be empty
    @Param [out]pBufSize a pointer where returns current buffer size. If 0 it will be ignored
    @Param [out]pBufSizeMax a pointer where returns maximum buffer size. If 0 it will be ignored
    @return true if a frame is available
    */
    bool PopFrame(Mat &frame, size_t *pBufSize = 0, size_t ...
(more)
edit flag offensive delete link more

Comments

Thank you very much. i will try it later but i guess it will solve the problem.

sturkmen gravatar imagesturkmen ( 2016-05-31 07:06:14 -0600 )edit

It's nice to see an accepted answer but I hope it works ;) PS: Maybe you can retag your question with multiple_camera ...

pklab gravatar imagepklab ( 2016-05-31 07:35:46 -0600 )edit

@pklab thanks again. it works perfectly.

sturkmen gravatar imagesturkmen ( 2016-05-31 12:15:25 -0600 )edit

nice to see :) even if I can't understand why you edited my answer. std::to_string() is standard C++ but requires #include <string>

pklab gravatar imagepklab ( 2016-05-31 13:05:03 -0600 )edit

i am using code::blocks ( maybe i missed something on configuration but ) it gives me even #include <string> added.

error: 'to_string' is not a member of 'std'
sturkmen gravatar imagesturkmen ( 2016-05-31 13:27:01 -0600 )edit
1

@sturkmen just compiled with code::blocks tdm-gcc-64 (gcc 5.1). BTW to_string()is member of the Standard Library since C++11 (http://en.cppreference.com/w/cpp/stri.... try the gcc flag -std=c++11

pklab gravatar imagepklab ( 2016-05-31 13:33:45 -0600 )edit

OK. thanks again.

sturkmen gravatar imagesturkmen ( 2016-05-31 13:40:24 -0600 )edit

you are welcome :=)

pklab gravatar imagepklab ( 2016-05-31 13:41:13 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2016-05-30 07:56:11 -0600

Seen: 4,014 times

Last updated: May 31 '16