openCV Mat 中的值在自定义类构造函数中设置后不会保留

Values in openCV Mat are not retained after being set in a custom class constructor

本文关键字:设置 保留 构造函数 自定义 Mat openCV      更新时间:2023-10-16

我正在C++Visual Studio中编写一个OpenCV应用程序,并且在使用包含Mat作为其成员的自定义类时遇到问题。我已经将有问题的代码简化为下面的示例,该示例仍然表现出问题。

有问题的 Mat 被定义为私有成员,并使用类构造函数中的正确值进行初始化。使用 std::cout 进行测试表明这些值确实是正确的。当我尝试在成员函数中使用此 Mat 时,它的值是乱七八糟的废话。当然,我需要它们与构造函数中定义的相同。

我假设这与 Mat 类的工作方式有关,因为这不会发生在常规类型(如 int、float(上,...我已经用谷歌搜索过,但找不到任何迹象表明为什么会发生这种情况。显然,我在构造函数中保存 Mat 的方式有问题,但我找不到有用的替代方案。这些值由 std::cout 显示看起来是随机的,但 *.at 显示所有值都相同(或相似(,这似乎更像是某种溢出。无论哪种方式,都是错误的。

谢谢你的时间!

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
class test {
Mat stayStill;
int number;
public:
test(double value, int someNumber) {
number = someNumber;
double data[] = {
0,  value,      0,
value,      0,  value,
0,  value,      0
};
stayStill = Mat(3, 3, CV_64FC1, data);
cout << endl << "number: " << number;
cout << endl << "stayStill as defined on init" << endl << stayStill;
}
void show() {
cout << endl << "stayStill as experienced in member function" << endl << stayStill << endl;    
cout << endl << "and once more just to be sure:" << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cout << stayStill.at<double>(i, j) << " ";
}
cout << endl;
}
cout << endl << "size: " << stayStill.size();
cout << endl << "type: " << stayStill.type();
cout << endl << "number: " << number << endl;
}
};
int main() {
test a(3, 5);
a.show();
return 0;
}

和输出:

number: 5
stayStill as defined on init
[0, 3, 0;
3, 0, 3;
0, 3, 0]
stayStill as experienced in member function
[-9.255963134931783e+61, 1.253977097799596e-311, 1.253977098748202e-311;
-9.255963134931783e+61, -9.255963134931783e+61, -9.255963134931783e+61;
-9.255963134931783e+61, -nan, -9.255963134931783e+61]
and once more just to be sure if it's wrong:
-9.25596e+61 -9.25596e+61 -9.25596e+61
-9.25596e+61 -9.25596e+61 -9.25596e+61
-9.25596e+61 -9.25596e+61 -9.25596e+61
size: [3 x 3]
type: 6
number: 5

Mat的赋值运算符执行浅拷贝;因此您的成员变量stayStill将包含对临时对象的引用(稍后调用show时,该对象将超出范围(。这会产生未定义的行为。

您可以使用Mat::copyTo()制作深度副本。

Mat temp(3, 3, CV_64FC1, data);
temp.copyTo(stayStill);

OpenCV中的矩阵使用引用计数器技术工作。调用复制操作时,它们仅复制指向源矩阵数据的指针,而不是整个基础数据。

stayStill = Mat(3, 3, CV_64FC1, data);
^^^

在上面的行中创建了临时子 - 它持有data,然后staySill获取指向此临时垫的指针,最后这个指针悬空,因为在完整表达式结束时临时被破坏。

您可以引入新的命名Mat实例:

Mat m(3, 3, CV_64FC1, data);

并通过copyTo制作深度副本:

m.copyTo(stayStill);