OpenCV Video Capture 作为 class 成员不起作用 (C++)
OpenCV Video Capture nonfunctional as class member (C++)
我的应用程序要求将 OpenCV VideoCapture 对象用作成员变量。没有办法绕过这个要求。
我在使用 cv::VideoCapture
作为用户定义的 class 的成员时遇到了奇怪的行为。我有 运行 以下代码:
#define int64 opencv_broken_int
#include <opencv2/opencv.hpp>
#undef int64
class Foo {
public:
Foo() = default;
void run(void) {
cv::VideoCapture* cap = new cv::VideoCapture();
cv::VideoCapture g_cap = *cap;
if (not g_cap.open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
exit(-1);
}
for (int i = 0; i < 10; i++) {
if (not g_cap.isOpened())
std::cerr << "Video capture is not open here!" << std::endl;
cv::Mat f;
g_cap >> f;
if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
std::string filename = "Foo_test_" + std::to_string(i) + ".tiff";
bool b = cv::imwrite(filename, f);
if (not b) std::cerr << "Error in writing image" << std::endl;
//cv::waitKey(25);
}
};
};
int main(void) {
cv::VideoCapture cap;
if (not cap.open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
return -1;
}
for (int i =0; i < 10; i++) {
cv::Mat frame;
cap >> frame;
if (frame.empty()) {
std::cerr << "frame is empty" << std::endl;
break;
}
// Else write the image to a file
std::string filename = "test_" + std::to_string(i) + ".tiff";
bool res = cv::imwrite(filename, frame);
if (not res)
std::cerr << "Error in writing image" << std::endl;
}
cap.release();
Foo f;
f.run();
return 0;
}
只为 N = [0,9] 生成了 test_N.tiff,即生成的唯一图像来自 main( )
和 中的 cv::VideoCapture
对象不是 来自 class Foo
.
我试图实例化一个 cv::VideoCapture
类型的全局变量 g_cap
,但我仍然只能 read/write 来自主函数中对象的图像。如上面的代码所示,我还尝试将 VideoCapture 对象实例化为一个指针(如果您愿意的话,这是一个冰雹玛丽),但这也不起作用。但是请注意,在 main( )
中声明的设置 cap
是对 g_cap
的引用(显然当 g_cap
在全局范围内时)给出了相同的输出 - 从 main( )
但不是根据需要来自 Foo::run( )
。
请注意另一个奇怪的行为是控制台中没有出现任何错误消息。这将表明 Foo
类型 VideoCapture
的成员实际上是打开的,并且将图像帧加载到 cv::Mat
类型的 f
中并没有 return空框。同样的,imwrite
函数不会 return false 表示操作成功。但是,如前所述,没有生成名为 Foo_test_N.tiff 的文件。
如何解释这种行为?是否有一些要求 cv::VideoCapture
可能在一些不同的范围内?如果图像没有保存或者视频流没有正确打开,这不会像上面的代码那样产生错误信息吗?
编辑20201110_1:
回应 Viktor Latypov 的以下评论:
我已经实施了建议的更改,但仍然观察到相同的行为。编辑:
class Foo {
public:
Foo() = default;
void run(void) {
cv::VideoCapture* cap = new cv::VideoCapture();
//cv::VideoCapture g_cap = *cap;
if (not cap -> open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
exit(-1);
}
for (int i = 0; i < 10; i++) {
if (not cap -> isOpened())
std::cerr << "Video capture is not open here!" << std::endl;
cv::Mat f;
*cap >> f;
if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
std::string filename = "Foo_test_" + std::to_string(i) + ".tiff";
bool b = cv::imwrite(filename, f);
if (not b) std::cerr << "Error in writing image" << std::endl;
//cv::waitKey(25);
}
cap -> release();
};
};
编辑20201110_2:
OpenCV 版本为 4.2.0
我尝试从 (a) 在一个函数中捕获图像帧,并且 (b) 将在 main( )
中实例化的 OpenCV VideoCapture 对象作为副本传递给参数化构造函数,并以相同的方式传递指针结果。完整代码如下:
#define int64 opencv_broken_int
#include <opencv2/opencv.hpp>
#undef int64
class Foo {
public:
Foo() = default;
void run(void) {
cv::VideoCapture* cap = new cv::VideoCapture();
//cv::VideoCapture g_cap = *cap;
if (not cap -> open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
exit(-1);
}
for (int i = 0; i < 10; i++) {
if (not cap -> isOpened())
std::cerr << "Video capture is not open here!" << std::endl;
cv::Mat f;
*cap >> f;
if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
std::string filename = "Foo_test_" + std::to_string(i) + ".tiff";
bool b = cv::imwrite(filename, f);
if (not b) std::cerr << "Error in writing image" << std::endl;
//cv::waitKey(25);
}
cap -> release();
};
};
class Bar {
public:
Bar(cv::VideoCapture* c) : cap(c) {};
void run(void) {
//cv::VideoCapture* cap = new cv::VideoCapture();
//cv::VideoCapture g_cap = *cap;
if (not cap -> open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
exit(-1);
}
for (int i = 0; i < 10; i++) {
if (not cap -> isOpened())
std::cerr << "Video capture is not open here!" << std::endl;
cv::Mat f;
*cap >> f;
if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
std::string filename = "Bar_test_" + std::to_string(i) + ".tiff";
bool b = cv::imwrite(filename, f);
if (not b) std::cerr << "Error in writing image" << std::endl;
//cv::waitKey(25);
}
cap -> release();
};
cv::VideoCapture* cap;
};
void test(void) {
cv::VideoCapture cap(0);
if (not cap.open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
exit(-1);
}
for (int i =0; i < 10; i++) {
cv::Mat frame;
cap >> frame;
if (frame.empty()) {
std::cerr << "frame is empty" << std::endl;
break;
}
// Else write the image to a file
std::string filename = "testFunc_test_" + std::to_string(i) + ".tiff";
bool res = cv::imwrite(filename, frame);
if (not res)
std::cerr << "Error in writing image" << std::endl;
}
cap.release();
}
int main(void) {
cv::VideoCapture cap;
if (not cap.open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
return -1;
}
for (int i =0; i < 10; i++) {
cv::Mat frame;
cap >> frame;
if (frame.empty()) {
std::cerr << "frame is empty" << std::endl;
break;
}
// Else write the image to a file
std::string filename = "main_test_" + std::to_string(i) + ".tiff";
bool res = cv::imwrite(filename, frame);
if (not res)
std::cerr << "Error in writing image" << std::endl;
}
cap.release();
Bar b(&cap); b.run();
Foo f; f.run();
test();
return 0;
}
此程序的输出如下所示:
请注意,Foo
或 Bar
!
的 class 成员函数中没有保存图像
编辑 1:
真正的问题出在这一行
if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
我忽略了这个明显的问题。 break
语句执行无论 f.empty()
检查 returns.
应该是
if (f.empty())
{
std::cerr << "Frame was empty" << std::endl;
break;
}
===================
原答案(N2题):
分配 cap
对象后
cv::VideoCapture* cap = new cv::VideoCapture();
你正在调用赋值运算符
cv::VideoCapture g_cap = *cap;
这可能会执行比您实际想要的更多的操作。
删除g_cap
变量,直接使用cap
。
例如,行
if (not g_cap.open(0)) {
应该是
if (not cap->open(0)) {
和行
g_cap >> f;
会变成
*cap >> f; // or cap->read(f);
经过这些简单的修改后,run()
方法生成带有抓取帧的图像文件。
我的应用程序要求将 OpenCV VideoCapture 对象用作成员变量。没有办法绕过这个要求。
我在使用 cv::VideoCapture
作为用户定义的 class 的成员时遇到了奇怪的行为。我有 运行 以下代码:
#define int64 opencv_broken_int
#include <opencv2/opencv.hpp>
#undef int64
class Foo {
public:
Foo() = default;
void run(void) {
cv::VideoCapture* cap = new cv::VideoCapture();
cv::VideoCapture g_cap = *cap;
if (not g_cap.open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
exit(-1);
}
for (int i = 0; i < 10; i++) {
if (not g_cap.isOpened())
std::cerr << "Video capture is not open here!" << std::endl;
cv::Mat f;
g_cap >> f;
if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
std::string filename = "Foo_test_" + std::to_string(i) + ".tiff";
bool b = cv::imwrite(filename, f);
if (not b) std::cerr << "Error in writing image" << std::endl;
//cv::waitKey(25);
}
};
};
int main(void) {
cv::VideoCapture cap;
if (not cap.open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
return -1;
}
for (int i =0; i < 10; i++) {
cv::Mat frame;
cap >> frame;
if (frame.empty()) {
std::cerr << "frame is empty" << std::endl;
break;
}
// Else write the image to a file
std::string filename = "test_" + std::to_string(i) + ".tiff";
bool res = cv::imwrite(filename, frame);
if (not res)
std::cerr << "Error in writing image" << std::endl;
}
cap.release();
Foo f;
f.run();
return 0;
}
只为 N = [0,9] 生成了 test_N.tiff,即生成的唯一图像来自 main( )
和 中的 cv::VideoCapture
对象不是 来自 class Foo
.
我试图实例化一个 cv::VideoCapture
类型的全局变量 g_cap
,但我仍然只能 read/write 来自主函数中对象的图像。如上面的代码所示,我还尝试将 VideoCapture 对象实例化为一个指针(如果您愿意的话,这是一个冰雹玛丽),但这也不起作用。但是请注意,在 main( )
中声明的设置 cap
是对 g_cap
的引用(显然当 g_cap
在全局范围内时)给出了相同的输出 - 从 main( )
但不是根据需要来自 Foo::run( )
。
请注意另一个奇怪的行为是控制台中没有出现任何错误消息。这将表明 Foo
类型 VideoCapture
的成员实际上是打开的,并且将图像帧加载到 cv::Mat
类型的 f
中并没有 return空框。同样的,imwrite
函数不会 return false 表示操作成功。但是,如前所述,没有生成名为 Foo_test_N.tiff 的文件。
如何解释这种行为?是否有一些要求 cv::VideoCapture
可能在一些不同的范围内?如果图像没有保存或者视频流没有正确打开,这不会像上面的代码那样产生错误信息吗?
编辑20201110_1: 回应 Viktor Latypov 的以下评论: 我已经实施了建议的更改,但仍然观察到相同的行为。编辑:
class Foo {
public:
Foo() = default;
void run(void) {
cv::VideoCapture* cap = new cv::VideoCapture();
//cv::VideoCapture g_cap = *cap;
if (not cap -> open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
exit(-1);
}
for (int i = 0; i < 10; i++) {
if (not cap -> isOpened())
std::cerr << "Video capture is not open here!" << std::endl;
cv::Mat f;
*cap >> f;
if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
std::string filename = "Foo_test_" + std::to_string(i) + ".tiff";
bool b = cv::imwrite(filename, f);
if (not b) std::cerr << "Error in writing image" << std::endl;
//cv::waitKey(25);
}
cap -> release();
};
};
编辑20201110_2: OpenCV 版本为 4.2.0
我尝试从 (a) 在一个函数中捕获图像帧,并且 (b) 将在 main( )
中实例化的 OpenCV VideoCapture 对象作为副本传递给参数化构造函数,并以相同的方式传递指针结果。完整代码如下:
#define int64 opencv_broken_int
#include <opencv2/opencv.hpp>
#undef int64
class Foo {
public:
Foo() = default;
void run(void) {
cv::VideoCapture* cap = new cv::VideoCapture();
//cv::VideoCapture g_cap = *cap;
if (not cap -> open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
exit(-1);
}
for (int i = 0; i < 10; i++) {
if (not cap -> isOpened())
std::cerr << "Video capture is not open here!" << std::endl;
cv::Mat f;
*cap >> f;
if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
std::string filename = "Foo_test_" + std::to_string(i) + ".tiff";
bool b = cv::imwrite(filename, f);
if (not b) std::cerr << "Error in writing image" << std::endl;
//cv::waitKey(25);
}
cap -> release();
};
};
class Bar {
public:
Bar(cv::VideoCapture* c) : cap(c) {};
void run(void) {
//cv::VideoCapture* cap = new cv::VideoCapture();
//cv::VideoCapture g_cap = *cap;
if (not cap -> open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
exit(-1);
}
for (int i = 0; i < 10; i++) {
if (not cap -> isOpened())
std::cerr << "Video capture is not open here!" << std::endl;
cv::Mat f;
*cap >> f;
if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
std::string filename = "Bar_test_" + std::to_string(i) + ".tiff";
bool b = cv::imwrite(filename, f);
if (not b) std::cerr << "Error in writing image" << std::endl;
//cv::waitKey(25);
}
cap -> release();
};
cv::VideoCapture* cap;
};
void test(void) {
cv::VideoCapture cap(0);
if (not cap.open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
exit(-1);
}
for (int i =0; i < 10; i++) {
cv::Mat frame;
cap >> frame;
if (frame.empty()) {
std::cerr << "frame is empty" << std::endl;
break;
}
// Else write the image to a file
std::string filename = "testFunc_test_" + std::to_string(i) + ".tiff";
bool res = cv::imwrite(filename, frame);
if (not res)
std::cerr << "Error in writing image" << std::endl;
}
cap.release();
}
int main(void) {
cv::VideoCapture cap;
if (not cap.open(0)) {
std::cerr << "Cannot open camera 0" << std::endl;
return -1;
}
for (int i =0; i < 10; i++) {
cv::Mat frame;
cap >> frame;
if (frame.empty()) {
std::cerr << "frame is empty" << std::endl;
break;
}
// Else write the image to a file
std::string filename = "main_test_" + std::to_string(i) + ".tiff";
bool res = cv::imwrite(filename, frame);
if (not res)
std::cerr << "Error in writing image" << std::endl;
}
cap.release();
Bar b(&cap); b.run();
Foo f; f.run();
test();
return 0;
}
此程序的输出如下所示:
Foo
或 Bar
!
编辑 1:
真正的问题出在这一行
if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
我忽略了这个明显的问题。 break
语句执行无论 f.empty()
检查 returns.
应该是
if (f.empty())
{
std::cerr << "Frame was empty" << std::endl;
break;
}
===================
原答案(N2题):
分配 cap
对象后
cv::VideoCapture* cap = new cv::VideoCapture();
你正在调用赋值运算符
cv::VideoCapture g_cap = *cap;
这可能会执行比您实际想要的更多的操作。
删除g_cap
变量,直接使用cap
。
例如,行
if (not g_cap.open(0)) {
应该是
if (not cap->open(0)) {
和行
g_cap >> f;
会变成
*cap >> f; // or cap->read(f);
经过这些简单的修改后,run()
方法生成带有抓取帧的图像文件。