从线程中捕获 OpenCV 相机
OpenCV camera capture from within a thread
这是我尝试工作的代码的一小部分。这也是我第一次与C++合作。我习惯了更高级的语言,如Java或C#。
主版本应作为共享对象或 DLL 运行。这个想法是外部程序(在 C# 中)将启动主循环。来自相机的帧将在线程中捕获。信息将在该线程内部处理并复制到数组("dataArray")。此复制过程将在类互斥锁锁定时完成。然后,外部调用的另一个函数会将保存的数组("dataArray")复制到第二个数组("outArray")并返回指向第二个数组的指针。外部程序将使用指针从第二个 Array 复制数据,在再次调用该函数之前不会修改该数组。
但要使所有这些工作,我需要不断捕获帧。我意识到我需要一些东西来保持我的main
功能,所以我在那里保持无限循环。在"真实"版本中,keepRunning
变量将由运行库的外部程序更改。
我最近在 StackOverflow 上讲授了不创建全局变量,所以我将我的类的一个实例保留在静态成员中。这在Java中是非常标准的。我不知道这是否是C++的不良做法。我也惊讶于C++线程在创建后如何立即启动,而没有明确的"启动"说明。这就是为什么我将我唯一的线程放在向量中的原因。这似乎是大多数人的建议。
我知道,如果没有keepRunning
永远不会真正改变,线程将永远不会连接起来,但我稍后会珍惜这一点。我在Mac上运行它,但我最终需要它才能在Windows,Mac和Linux上运行。
这是我的标题:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <thread>
#include <vector>
using namespace cv;
using namespace std;
class MyCap {
public:
MyCap();
VideoCapture cap;
static MyCap * instance;
void run();
static void RunThreads(MyCap * cap);
bool keepRunning = true; // Will be changed by the external program.
vector<thread> capThreads;
private:
Mat frame;
};
这是我的代码:
#include "theheader.h"
MyCap * MyCap::instance = NULL;
int main(int argc, char** argv) {
MyCap::instance = new MyCap();
MyCap::instance->capThreads.push_back(thread(MyCap::RunThreads, MyCap::instance));
// Outside loop.
while(MyCap::instance->keepRunning) {
}
for (int i = 0; i < MyCap::instance->capThreads.size(); i++) {
MyCap::instance->capThreads[i].join();
}
}
MyCap::MyCap() {
namedWindow("flow", 1);
cap.open(0);
}
void MyCap::RunThreads(MyCap * cap) {
cap->run();
}
void MyCap::run() {
// Inside loop.
while(keepRunning) {
cap >> frame;
imshow("flow", frame);
if (waitKey(30) >= 0) {
break;
}
}
}
使用此代码,我得到一个黑屏。如果我从run
方法中运行cap.open(0)
,我什至不明白。我显然做错了什么。但真正让我困惑的是:为什么从哪里调用相同的代码会有所不同?如果我在main
内部运行现在run
的东西,它将起作用。如果我将cap.open(0)
的调用从构造函数更改为run
,则会更改方法的作用。此外,waitKey
条件从线程内停止工作。我错过了什么大东西?
版本 2
根据@darien-pardibas的建议,我制作了第二个版本:
页眉:
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <thread>
#include <vector>
using namespace cv;
using namespace std;
class MyCap {
public:
MyCap();
void run();
bool keepRunning = true; // Will be changed by the external program.
static void RunThreads(MyCap * cap);
static vector<thread> capThreads;
static MyCap * getInstance();
private:
static MyCap * instance;
};
主文件:
#include "theprogram.h" // I'll admit that, even for a placeholder, it was a bad name.
MyCap * MyCap::instance = NULL;
vector<thread> MyCap::capThreads;
MyCap::MyCap() {
cout << "Instantiate" << endl;
}
MyCap * MyCap::getInstance() {
if (MyCap::instance == NULL) {
MyCap::instance = new MyCap;
}
return MyCap::instance;
}
void MyCap::RunThreads(MyCap * cap) {
cap->run();
}
void MyCap::run() {
cout << "Run" << endl;
namedWindow("flow", 1);
cout << "Window created." << endl;
VideoCapture cap(0); // HANGS HERE!
cout << "Camera open." << endl; // This never gets printed.
// Inside loop.
Mat frame;
while(keepRunning) {
cap >> frame;
imshow("flow", frame);
if (waitKey(30) >= 0) {
break;
}
}
}
int main(int argc, char** argv) {
MyCap::capThreads.push_back(thread(&MyCap::RunThreads, MyCap::getInstance()));
for (int i = 0; i < MyCap::capThreads.size(); i++) {
MyCap::capThreads[i].join();
}
}
这将打印:
Instantiate
Run
Window created.
并挂在那里。
但是,如果我将代码从run
移动到main
并将keepRunning
更改为true
,那么它就可以按预期工作。我想我错过了别的东西,我猜这与C++的工作方式有关。
好的,在不查看解决我在您的代码中看到的所有设计模式问题的情况下,我可以确认下面的代码有效。我认为主要问题是您需要在捕获图像的同一线程中创建namedWindow
并删除main
方法中的while
循环。
"theheader.h"
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <thread>
#include <vector>
class MyCap {
public:
void run();
static void RunThreads(MyCap * cap);
bool keepRunning = true; // Will be changed by the external program.
std::vector<std::thread> capThreads;
private:
cv::Mat frame;
cv::VideoCapture cap;
MyCap() { }
static MyCap * s_instance;
public:
static MyCap *instance();
};
"标题.cpp"
#include "theheader.h"
#pragma comment(lib, "opencv_core248d")
#pragma comment(lib, "opencv_highgui248d")
using namespace std;
using namespace cv;
MyCap * MyCap::s_instance = NULL;
MyCap* MyCap::instance() {
if (s_instance == NULL)
s_instance = new MyCap();
return s_instance;
}
void MyCap::RunThreads(MyCap * cap) {
cap->run();
}
void MyCap::run() {
namedWindow("flow", 1);
cap.open(0);
// Inside loop.
while (keepRunning) {
cap >> frame;
imshow("flow", frame);
if (waitKey(30) >= 0) {
break;
}
}
}
int main(int argc, char** argv) {
MyCap::instance()->capThreads.push_back(thread(&MyCap::RunThreads, MyCap::instance()));
for (int i = 0; i < MyCap::instance()->capThreads.size(); i++) {
MyCap::instance()->capThreads[i].join();
}
}
- OpenCV - Python 断言错误:SAD 算法 - 立体相机视差图计算
- Opencv 如何从相机读取单帧
- OpenCV - 来自相机的实时馈送不流畅
- OpenCV 错误:相机校准:断言在matrix_wrap.cpp失败
- 我无法在 OpenCV 中从相机捕获帧
- 从iPhone相机拍摄的视频似乎被OpenCV旋转了90度?我该如何解决这个问题?
- 使用OpenCV为使用GENICAM API和C++的各种相机创建程序
- C++ 不同分辨率的相机的Opencv校准
- 使用OpenCV延迟捕获相机框架
- OpenCV 将相机中的图像与相同图像进行匹配不会产生 100% 匹配
- OpenCV C++相机图像未保存到矩阵中
- OpenCV相机错误
- 如何区分OpenCV相机
- 使用C++进行 OpenCv 相机校准(不支持的格式或格式组合错误)
- OpenCV相机内在矩阵到用于增强现实的食人魔投影矩阵
- 从线程中捕获 OpenCV 相机
- cvCreateCameraCapture无法访问OpenCV 3.0相机
- OpenCV相机问题:
- OpenCV相机校准
- OpenCV>>相机相对姿态估计