Подтвердить что ты не робот

Простое прохождение матриц, т.е. cv:: Mat для функций в OpenCV2.4

Я новичок в opencv, и я сомневаюсь в одной из самых простых операций в кодировании: Передача значений в функции.

Вот что я хочу делать,

  • Инициализировать cv:Mat в основной функции, скажем, значения от 0 до 50.
  • Передайте эту матрицу в качестве аргумента функции foo(), которая, в свою очередь, просто выводит значения каждого элемента в матрице. Вот оно.

Теперь я прочитал в нескольких местах, что, когда эти матрицы переданы, передается только заголовок, а не фактические данные. Тогда как я все еще могу считывать значения этой матрицы в вызываемой функции, как если бы вся матрица была передана?

4b9b3361

Ответ 1

Чтобы понять, что происходит, вам нужно взглянуть на конструкторы С++, более конкретно конструктор копирования.

Когда вы создаете cv::Mat из другого cv::Mat, как в:

cv::Mat a = cv::imread("huge.png", 1);
cv::Mat b = a;

для выполнения копии объекта вызывается конструктор копирования (который является функцией) cv::Mat. Прежде чем говорить о том, что происходит в процедуре копирования, вы должны понимать, что, поскольку cv::Mat используется для хранения изображений, большие изображения могут занимать сотни мегабайт в памяти. Итак, что делает конструктор cv::Mat в приведенном выше примере, скопируйте весь заголовок (высота, ширина, информация о глубине и другие) a в b, но вместо копирования целые данные/пиксели a (которые могут быть сотнями МБ), он просто указывает (используя указатель) на исходные данные a.

Другими словами, не копирование всех данных изображения является решением оптимизации/производительности.

Теперь рассмотрим этот код, который вызывает функцию и передает cv::Mat в качестве параметра:

void do_something(cv::Mat src)
{
    // changing src pixels will be the same as changing orig pixels
}

int main()
{
    cv::Mat orig = cv::imread("huge.png", 1);
    do_something(orig);
    return 0;
}

Если вы изучили, как передавать параметры в функции, вы знаете, что вызов do_something(a); будет передать параметр по значению. Это означает, что он попытается скопировать содержимое orig в src, однако эта процедура активирует конструктор копирования cv::Mat, который не будет делать жесткую копию данных, как я только что объяснил.

Решение этой проблемы? Если вы пишете do_something() и хотите просто сделать реальную копию orig, просто создайте новый cv::Mat и вызовите метод copyTo():

void do_something(cv::Mat src)
{
    cv::Mat real_copy = src.copyTo();
    // operating on the data of real_copy will not affect orig
}

Но помните, если src составляет ~ 100 МБ, вызывая copyTo(), чтобы реальная копия занимала еще одну ~ 100 МБ памяти, а это означает, что в одной функции вы можете перейти от 100 МБ до 200 МБ. Помните об этом при разработке вашей системы. Удачи.