Я пишу приложение OpenCV в C ++ Visual Studio и у меня возникают проблемы с пользовательским классом, который содержит Mat в качестве члена. Я упростил проблемный код до приведенного ниже примера, который все еще демонстрирует проблему.

Проблемный Mat определяется как закрытый член и инициализируется с правильными значениями в конструкторе класса. Тест с std :: cout показывает, что значения действительно верны. Когда я тогда пытаюсь использовать этот Mat в функции-члене, его значения - бессмысленная ерунда. Конечно, мне нужно, чтобы они были такими же, как были определены в конструкторе.

Я предполагаю, что это как-то связано с тем, как работает класс Mat, так как это не происходит с обычными типами, такими как int, float, ... Я погуглил, но не могу найти никаких признаков того, почему это может бывает. Ясно, что что-то не так в том, как я сохраняю Мат в конструкторе, но я не могу найти полезную альтернативу. Значения, показанные в 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
1
SimonFencing 18 Авг 2019 в 23:09

2 ответа

Лучший ответ

Матрицы в OpenCV работают с использованием метода счетчика ссылок. Когда вызываются операции копирования, они копируют только указатель на данные исходной матрицы, а не все базовые данные.

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

В строке выше создается временный Mat - он содержит data, затем staySill получает указатель на этот временный объект, и, наконец, этот указатель свисает, потому что в конце полного выражения временный Мат уничтожен.

Вы можете ввести новый именованный экземпляр Mat:

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

И сделайте глубокие копии copyTo:

m.copyTo(stayStill);
0
rafix07 18 Авг 2019 в 20:20

Оператор присваивания Mat выполняет поверхностное копирование; поэтому ваша переменная-член stayStill будет содержать ссылки на временный объект (который выйдет из области видимости, когда вы вызовете show позже). Это приводит к неопределенному поведению.

Вы можете сделать глубокую копию с Mat::copyTo(). например

Mat temp(3, 3, CV_64FC1, data);
temp.copyTo(stayStill);
1
amo-ej1 18 Авг 2019 в 20:33