Вот небольшая программа тестирования, демонстрирующая свойства совместного использования данных объектов cv :: Mat (которые являются заголовками матрицы) специальными!
int main()
{
// create input of size 512x512
cv::Mat input = cv::imread("../inputData/Lenna.png");
// create a second input of size 256x256
cv::Mat modifiedInput;
cv::resize(input, modifiedInput, cv::Size(256,256));
std::vector<cv::Mat> images;
// first element will be a "deep copy" where the matrix elements will be copied to a new memory location and a new header will be created, referecing those matrix elements.
images.push_back(input.clone());
// 6 times copy the "input" to "images".
// All the copies will (deep) copy the matrix header but they will share the matrix elements (because their memory LOCATION will be copied)
for(unsigned int i=0; i<6; ++i)
images.push_back(input);
// now some experiments:
// draw a circle to input variable. At this point it should share it's matrix elements with images[1-5]
cv::circle(input, cv::Point(100,100), 30, cv::Scalar(0,0,0), -1);
// draw a circle to a vector element:
cv::circle(images[5], cv::Point(300,100), 30, cv::Scalar(0,0,0), -1);
// use a openCV function that will allocate new memory, if the destination dimensions don't fit:
// to a mat whose dimensions fit:
// remember that input.size() == vector[0..5].size
// compute median blur and target one of the matrices that share their data at the moment:
cv::medianBlur(input, images[3], 11);
cv::imshow("0", images[0]);
cv::imshow("1", images[1]);
cv::imshow("2", images[2]);
cv::imshow("3", images[3]);
cv::imshow("4", images[4]);
cv::imshow("5", images[5]);
cv::waitKey(0);
В это время выглядит следующим образом: Все матрицы обмена данными их элементов, за исключением первой матрицы, потому что глубоко копия была вынуждена с .clone()
.
сейчас продолжают с этим:
// to a mat whose dimensions don't fit (new memory will be allocated, not shared by the other matrix headers anymore):
// images[3] will not share the data with other matrix headers afterwards
cv::medianBlur(modifiedInput, images[3], 11);
// now images[3] and images[4] will share matrix elements
images[4] = images[3];
cv::circle(images[4], cv::Point(128,128), 20, cv::Scalar(255,255,255), 3);
// create a deep-copy of 256x256 input to overwrite images[5] (not modifying any other image's matrix elements)
images[5] = modifiedInput.clone();
cv::circle(images[5], cv::Point(0,0), 30, cv::Scalar(0,255,0), -1);
cv::imshow("0", images[0]);
cv::imshow("1", images[1]);
cv::imshow("2", images[2]);
cv::imshow("3", images[3]);
cv::imshow("4", images[4]);
cv::imshow("5", images[5]);
//cv::imshow("input", input);
//cv::imwrite("../outputData/MainBase.png", input);
cv::waitKey(0);
return 0;
}
выглядит следующим образом:
На этот раз вызов medianBlur
не разделяет данные со всеми другими матрицами, так как размеры целевого изображения НЕ УСТАНАВЛИВАЮТСЯ, поэтому в рамках метода medianBlur необходимо было выделить новую память для images[3]
. Таким образом, изображения [3] ссылаются на разные элементы данных аферу!
Все это может показаться немного сложным, поскольку пользователь может не видеть напрямую, какие вызовы функций будут выделять новые данные, а какие нет, поэтому, если вы хотите быть уверенными в распределении новых данных, вы должны сделать это в начиная с каждого мата, или использовать пустой циферблат в качестве адресата (или не передавать данные в начале). более
одно:
cv::Mat emptyMat;
std::vector<cv::Mat> images(n, emptyMat); // insert n copies of emptyMat header
// or
for(unsigned int i=0; i<n; ++i)
images.push_back(emptyMat) // same result
это и сохранить, чтобы использовать таким образом, чтобы не данные совместно, потому что все emptyMat не имеет каких-либо данных в начале, так что никакие данные не могут быть разделены.Всякий раз, когда любые данные привязаны к любому из элементов вектора, другие не знают об этом, и поэтому они не будут делиться этими данными.
// BUT:
cv::Mat notEmptyMat = cv::Mat::zeros(height, width, type);
std::vector<cv::Mat> images(n, notEmptyMat); // insert n copies of emptyMat header which references the assigned zeroes data of size width x height
// or
for(unsigned int i=0; i<n; ++i)
images.push_back(notEmptyMat) // same result
Здесь данные совместно и каждый раз при изменении данных одной из этих матриц, остальные будут изменены, тоже. Но, очевидно, если вы назначили новую память данных одной из этих матриц, другие все еще ссылаются на другую память данных.
'.push_back' скопирует объект. Но здесь объект представляет собой объект 'cv :: Mat', который сам является заголовком матрицы, что является чем-то вроде« умного указателя ». Таким образом, вы копируете умный указатель, но не значения матричных данных! И «изображение», и копия «изображения» будут разделять одни и те же элементы матрицы, пока одна из них не переназначит новую память (что может случиться, если для функции openCV требуется больше данных). Таким образом, здесь нет глубокой копии (матричных элементов), но вы не можете точно сказать, что обе ссылки на одни и те же данные навсегда. – Micka
Тогда я смущен. Так как я всегда .push_back (изображение), т. Е. Та же матрица с разными значениями, как векторные изображения по-прежнему содержат разные матрицы (что я проверил). –
можете ли вы предоставить некоторый минимальный код для проверки этого поведения? – Micka