gpt4 book ai didi

c++ - 无法使用 OpenCV 打开两个摄像头 - 多线程摄像头读取

转载 作者:太空狗 更新时间:2023-10-29 21:12:33 24 4
gpt4 key购买 nike

我正在尝试使用 OpenCV 通过单独的线程连续流式传输来自 2 个摄像头的视频。以下代码显示 Segmentation fault (core dumped)

这是什么原因,我该如何解决这个问题?

主要.cpp

#include <iostream>
#include <pthread.h>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>

using namespace std;

struct thread_data {
string path;
int thread_id;
};

void *capture(void *threadarg)
{
struct thread_data *data;
data = (struct thread_data *) threadarg;

cv::VideoCapture cap(data->path);

if( !cap.isOpened())
{
std::cout<<"Not good, open camera failed"<<std::endl;
}
std::cout<< "Opened IP camera successfully!"<<std::endl;
cv::Mat frame;
string ext = ".jpg";
string result;
while (true) {
cap >> frame;
cv::imshow("Frame",frame);
cv::waitKey(1);
}
pthread_exit(NULL);
}

int main(void) {
pthread_t threads[2];
struct thread_data td[2];
int rc=0;
for( int i = 0; i < 2; i++ ) {
cout <<"main() : creating thread, " << i << endl;
td[i].thread_id = i;
td[0].path = "rtsp://admin:opencv123@192.168.1.23:554/Streaming/Channels/101/";
td[1].path = "rtsp://admin:opencv123@192.168.1.24:554/Streaming/Channels/101/";
rc = pthread_create(&threads[i], NULL, capture, (void *)&td[i]);

if (rc) {
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
}
pthread_exit(NULL);
return 0;
}

日志:

main() : creating thread, 0    main() : creating thread, 1    
Segmentation fault (core dumped)

当我尝试多次运行它时,我只能打开一个摄像头,而且它也没有连续流式传输。它会在几秒钟内启动和停止。

有时我会收到一条错误消息

OpenCV Error: Insufficient memory (Failed to allocate 140703464366800 bytes) in OutOfMemoryError

我在 StackOverflow 上进行了各种问答,但没有任何帮助。

最佳答案

这里的问题是代码面临竞争条件。我能够在我的系统上重现该问题并确定了以下问题:

  1. OpenCV 窗口标题不是唯一的。
  2. 生成的线程未加入
  3. 打开视频流时出现竞争条件。

让我们详细研究这些问题。

1.

OpenCV 窗口由它们的标题唯一标识。在当前代码中,标题是一个硬编码字符串"Frame"。所以基本上,两个线程都以未知顺序创建/更新/销毁同一个窗口。这是一种竞争条件,可以通过向 struct thread_data 添加一个字符串字段来解决,该字段将用作唯一的窗口标识符。

2.

在主线程中,子线程是异步创建的,因此 for 循环会在创建线程后立即退出,程序会提前退出,而不会等待生成的线程完成执行。这个问题可以通过在程序退出之前添加函数调用来等待线程来解决。此过程称为加入,可以通过为每个生成的线程调用pthread_join 来实现。

3.

追踪这个问题有点棘手。由于某种原因,OpenCV 使用的视频流捕获后端库未以线程安全方式运行。貌似视频采集打开过程容易出现race-condition,需要同步锁。通过在打开 VideoCapture 对象之前和之后调用函数 pthread_mutex_lockpthread_mutex_unlock 可以轻松实现锁定。

这是修改后的代码,展示了上述所有问题的解决方案

#include <iostream>
#include <pthread.h>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>

using namespace std;

//Mutex for thread synchronization
static pthread_mutex_t foo_mutex = PTHREAD_MUTEX_INITIALIZER;


struct thread_data
{
string path;
int thread_id;
string window_title; //Unique window title for each thread
};

void *capture(void *threadarg)
{
struct thread_data *data;
data = (struct thread_data *) threadarg;

cv::VideoCapture cap;


//Safely open video stream
pthread_mutex_lock(&foo_mutex);
cap.open(data->path);
pthread_mutex_unlock(&foo_mutex);

if( !cap.isOpened())
{
std::cout<<"Not good, open camera failed"<<std::endl;
}
std::cout<< "Opened IP camera successfully!"<<std::endl;
cv::Mat frame;
string ext = ".jpg";
string result;

//Create window with unique title
cv::namedWindow(data->window_title);

while (true)
{
cap >> frame;
cv::imshow(data->window_title,frame);
cv::waitKey(10);
}

//Release VideoCapture object
cap.release();
//Destroy previously created window
cv::destroyWindow(data->window_title);

//Exit thread
pthread_exit(NULL);
}

int main(void)
{
const int thread_count = 2;

pthread_t threads[thread_count];
struct thread_data td[thread_count];


//Initialize thread data beforehand
td[0].path = "rtsp://admin:opencv123@192.168.1.23:554/Streaming/Channels/101/";
td[0].window_title = "First Window";
td[1].path = "rtsp://admin:opencv123@192.168.1.24:554/Streaming/Channels/101/";
td[1].window_title = "Second Window";


int rc=0;
for( int i = 0; i < thread_count; i++ )
{
cout <<"main() : creating thread, " << i << endl;
td[i].thread_id = i;

rc = pthread_create(&(threads[i]), NULL, capture, (void *)& (td[i]) );

if (rc)
{
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
}

//Wait for the previously spawned threads to complete execution
for( int i = 0; i < thread_count; i++ )
pthread_join(threads[i], NULL);

pthread_exit(NULL);

return 0;
}

关于c++ - 无法使用 OpenCV 打开两个摄像头 - 多线程摄像头读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47032382/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com