Why can't I get 3 webcam to run in parallel with pthreads?

asked 2020-06-05 21:09:43 -0600

JeffTheMess gravatar image

updated 2020-06-06 04:23:23 -0600

supra56 gravatar image

Hey all, I need some help with OpenCV with threading using C++. I am using a raspberry pi 3B. Which is a quad core. There are 4 USB 2.0 devices, 3 USB 2.0 webcam and USB 2.0 Arduino. The webcam’s cable has been spliced out to provide voltage on its own, so only data wires are going into the pi. The Arduino is being powered by the pi. Now to the issue. I have 4 threads going, 3 for the webcams and 1 for the Arduino. The webcams wait for the Arduino to send a signal to the webcams in parallel. The issue is, I cannot get the 3 cameras to work simultaneously. I can get any combination of 2 cameras to work but not 3. When I try 3 webcams, I get an error of empty frames.

Link To Webcam Used

Error:

[ WARN:2] global /home/pi/opencv/modules/videoio/src/cap_v4l.cpp (1004) tryIoctl VIDEOIO(V4L2:/dev/video0): select() timeout.
Empty Frame
terminate called after throwing an instance of 'cv::Exception'
  what():  OpenCV(4.3.0) /home/pi/opencv/modules/imgcodecs/src/loadsave.cpp:738: error: (-215:Assertion failed) !_img.empty() in function 'imwrite'

Aborted

Code: 

#include<stdio.h>
#include<stdlib.h>
#include<thread>
#include<iostream>
#include<fstream>

#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/core/core.hpp>
#include"pthread.h"
#include<stdlib.h>
#include<string>
#include<boost/date_time/posix_time/posix_time.hpp>

#include<mutex>
#include<condition_variable>
#include<atomic>


std::mutex m;
std::condition_variable suspend_cv;
std::atomic<bool> enabled (false);

struct args {
    int camNum;
    char* camName;
    int x;
    int y;
    };


void* camSetup(void *inputs){
    cv::VideoCapture stream(((struct args*)inputs)->camNum);
    cv::Mat Frame;
    //cv::Mat resizeFrame;
    if(!stream.isOpened()){
        std::cout << "Cannot Open Camera: " + ((struct args*) inputs)->camNum + '\n';
    }
    else{
        std::cout << "Camera Open: " << ((struct args*) inputs)->camNum + '\n';
    }
    std::unique_lock<std::mutex> lock(m);
    while (true){
        stream >> Frame;
        //cv::resize(Frame, resizeFrame, cv::Size(25, 25));
        while (enabled){
            // Get current time from the clock, using microseconds resolution
            const boost::posix_time::ptime now = 
                boost::posix_time::microsec_clock::local_time();

            // Get the time offset in current day
            const boost::posix_time::time_duration td = now.time_of_day();
            const long year         = now.date().year();
            const long month        = now.date().month();
            const long day          = now.date().day();
            const long hours        = td.hours();
            const long minutes      = td.minutes();
            const long seconds      = td.seconds();
            const long milliseconds = td.total_milliseconds() -
                                      ((hours * 3600 + minutes * 60 + seconds) * 1000);

            char buf[80];
            sprintf(buf, "%02ld%02ld%02ld_%02ld%02ld%02ld__%03ld", 
                year, month, day, hours, minutes, seconds, milliseconds);
                std::string sBuf = buf;
                std::string PATH = std::string("/home/pi/Desktop/") +
                                ((struct args*)inputs)->camName + 
                                    '/' +
                                    std::string(((struct args*)inputs)->camName) +
                                    '_' +
                                    sBuf +
                                    ".jpeg";
            if (Frame.empty())
            {
                std::cout << "Empty Frame" <<std::endl;
                stream >> Frame;
                //cv::resize(Frame, resizeFrame, cv::Size(25, 25));

            }
            cv::imwrite(PATH, Frame);
            if (cv::waitKey(30) >= 0){
                break;
            }
            suspend_cv.wait(lock);
        }
    }
    return NULL;
    }


void* ardReader(void*){
    ARDUINO STUFF HAPPENS…
}

int main(){
    struct args *cameraA = (struct args *)malloc(sizeof(struct args));
    struct args *cameraB = (struct args *)malloc(sizeof(struct ...
(more)
edit retag flag offensive close merge delete

Comments

are those usb cams ? you're probably saturating the bus. can you try with smaller resolution ?

berak gravatar imageberak ( 2020-06-06 02:12:59 -0600 )edit
1

also, please keep all gui code (imshow, waitKey, etc) on the main thread

berak gravatar imageberak ( 2020-06-06 02:14:02 -0600 )edit
1

Hey @berak, I tried using cap.set(CV_CAP_PROP_FRAME_WIDTH,640); cap.set(CV_CAP_PROP_FRAME_HEIGHT,480); but this did not work.

Also I am not sure what gui parts would need to be in the main thread. I don't really display anything. the only reason I have waitKey, is because I thought I would need it.

Yes, these are usb cams.

JeffTheMess gravatar imageJeffTheMess ( 2020-06-06 14:47:12 -0600 )edit

Didn't you install Arduino on Raspberry Pi?

supra56 gravatar imagesupra56 ( 2020-06-07 20:06:43 -0600 )edit

Yes, but I don't think there is anything inherently wrong with that. Its getting opencv to save 3 usb webcams to save at the same time.

JeffTheMess gravatar imageJeffTheMess ( 2020-06-07 20:31:40 -0600 )edit