为什么我不能将 3 个网络摄像头与 pthreads 并行地设置为 运行?
Why can't I get 3 webcam to run in parallel with pthreads?
我需要一些 OpenCV 的帮助,使用 C++ 进行线程化。我正在使用 raspberry pi 3B。这是一个四核。有 4 个 USB 2.0 设备、3 个 USB 2.0 网络摄像头和 USB 2.0 Arduino。网络摄像头的电缆已被拼接出来以自行提供电压,因此只有数据线进入 pi。 Arduino 由 pi 供电。
现在到这个问题。我有 4 个线程,3 个用于网络摄像头,1 个用于 Arduino。网络摄像头等待 Arduino 并行向网络摄像头发送信号。问题是,我无法让 3 个摄像头同时工作。我可以让 2 个摄像头的任意组合工作,但不能让 3 个摄像头工作。当我尝试使用 3 个网络摄像头时,出现空帧错误。
我试过没有成功:
sudo modprobe uvcvideo nodrop=1 timeout=5000 quirks=0x80
[ 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
#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 args));
struct args *cameraC = (struct args *)malloc(sizeof(struct args));
cameraA->camNum = 0;
char camA[] = "camA";
cameraA->camName = camA;
cameraA->x = 100;
cameraA->y =100;
cameraB->camNum = 2;
char camB[] = "camB";
cameraB->camName = camB;
cameraB->x = 100;
cameraB->y = 300;
cameraC->camNum = 4;
char camC[] = "camC";
cameraC->camName = camC;
cameraC->x = 100;
cameraC->y = 500;
pthread_t t1, t2, t3, t4;
pthread_create(&t1, NULL, camSetup, (void *) cameraA);
pthread_create(&t2, NULL, camSetup, (void *) cameraB);
pthread_create(&t3, NULL, camSetup, (void *) cameraC);
pthread_create(&t4, NULL, ardReader, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
pthread_join(t4, NULL);
return 0;
}
似乎 20 毫秒的差异对 threading/opencv 产生了足够大的差异。要回答我自己的问题以防有人再次遇到此问题,请将 waitkey 时间更改为以下...
在这种情况下线程不正确
if (cv::waitKey(30) >= 0){
break;
}
在这种情况下线程正确
if (cv::waitKey(10) == 27){
break;
}
我也将 cv::waitKey
移动到主线程。
虽然我仍然有错误,但这有时确实有效。
我做的最后一件事是每次需要抓取图像时打开和关闭相机。这让我每次都能保证帧数,虽然速度较慢,但始终有效。
我需要一些 OpenCV 的帮助,使用 C++ 进行线程化。我正在使用 raspberry pi 3B。这是一个四核。有 4 个 USB 2.0 设备、3 个 USB 2.0 网络摄像头和 USB 2.0 Arduino。网络摄像头的电缆已被拼接出来以自行提供电压,因此只有数据线进入 pi。 Arduino 由 pi 供电。
现在到这个问题。我有 4 个线程,3 个用于网络摄像头,1 个用于 Arduino。网络摄像头等待 Arduino 并行向网络摄像头发送信号。问题是,我无法让 3 个摄像头同时工作。我可以让 2 个摄像头的任意组合工作,但不能让 3 个摄像头工作。当我尝试使用 3 个网络摄像头时,出现空帧错误。
我试过没有成功:
sudo modprobe uvcvideo nodrop=1 timeout=5000 quirks=0x80
[ 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
#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 args));
struct args *cameraC = (struct args *)malloc(sizeof(struct args));
cameraA->camNum = 0;
char camA[] = "camA";
cameraA->camName = camA;
cameraA->x = 100;
cameraA->y =100;
cameraB->camNum = 2;
char camB[] = "camB";
cameraB->camName = camB;
cameraB->x = 100;
cameraB->y = 300;
cameraC->camNum = 4;
char camC[] = "camC";
cameraC->camName = camC;
cameraC->x = 100;
cameraC->y = 500;
pthread_t t1, t2, t3, t4;
pthread_create(&t1, NULL, camSetup, (void *) cameraA);
pthread_create(&t2, NULL, camSetup, (void *) cameraB);
pthread_create(&t3, NULL, camSetup, (void *) cameraC);
pthread_create(&t4, NULL, ardReader, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
pthread_join(t4, NULL);
return 0;
}
似乎 20 毫秒的差异对 threading/opencv 产生了足够大的差异。要回答我自己的问题以防有人再次遇到此问题,请将 waitkey 时间更改为以下...
在这种情况下线程不正确
if (cv::waitKey(30) >= 0){
break;
}
在这种情况下线程正确
if (cv::waitKey(10) == 27){
break;
}
我也将 cv::waitKey
移动到主线程。
虽然我仍然有错误,但这有时确实有效。
我做的最后一件事是每次需要抓取图像时打开和关闭相机。这让我每次都能保证帧数,虽然速度较慢,但始终有效。