[英]Deep Copy of OpenCV cv::Mat
復制cv::Mat
的行為讓我很困惑。
我從文檔中了解到Mat::copyTo()
是深拷貝,而賦值運算符不是。 我的問題:
我應該怎么做才能從函數返回cv::Mat
,例如: cv::Mat func()
?
根據文檔,如果我返回一個cv::Mat
它將沒有用,因為在函數返回該函數中cv::Mat
的本地副本后將被銷毀,因此接受外部返回值的那個函數應該指向某個隨機地址。 奇怪的是(大多數時候)它可以正常工作。 例如,以下工作:
cv::Mat CopyOneImage(const cv::Mat& orgImage) { cv::Mat image; orgImage.copyTo(image); return image; } int main() { std::string orgImgName("a.jpg"); cv::Mat orgImage; orgImage = cv::imread(orgImgName); cv::Mat aCopy; aCopy = CopyOneImage(orgImage); return 1; }
但為什么? 這不是深拷貝。
問題 3. 有時賦值運算符似乎也是深拷貝:
int main()
{
std::string orgImgName("a.jpg");
cv::Mat orgImage;
orgImage = cv::imread(orgImgName);
cv::Mat aCopy;
orgImage.copyTo(aCopy);
cv::Mat copyCopy1;
copyCopy1 = aCopy;
cv::namedWindow("smallTest", 1);
cv::imshow("smallTest", copyCopy1);
uchar key = (uchar)cv::waitKey();
cv::Mat orgImage2 = cv::imread("b.jpg");
orgImage2.copyTo(aCopy);
cv::imshow("smallTest", copyCopy1);
return 1;
}
然后兩個顯示器顯示相同的圖像,a.jpg。 為什么? 有時它不起作用。 (原代碼太長但也可以簡化為上述情況)。 在那些時候,賦值運算符似乎實際上是“淺”復制。 為什么?
非常感謝!
我認為,使用賦值並不是矩陣復制的最佳方式。 如果您想要矩陣的新完整副本,請使用:
Mat a=b.clone();
如果您想要復制矩陣來替換另一個矩陣中的數據(以避免內存重新分配),請使用:
Mat a(b.size(),b.type());
b.copyTo(a);
當您將一個矩陣分配給另一個矩陣時,指向矩陣數據的智能指針的引用計數器增加一,當您釋放矩陣時(可以在離開代碼塊時隱式完成)它減少一。 當它變為零時,分配的內存被釋放。
如果你想從函數使用引用中得到結果,它會更快:
void Func(Mat& input,Mat& output)
{
somefunc(input,output);
}
int main(void)
{
...
Mat a=Mat(.....);
Mat b=Mat(.....);
Func(a,b);
...
}
我已經使用 OpenCV 一段時間了, cv::Mat
也讓我感到困惑,所以我做了一些閱讀。
cv::Mat
是一個標頭,指向一個*data
指針,該指針包含實際的圖像數據。 它還實現了引用計數。 它保存當前指向該*data
指針的cv::Mat
標頭的數量。 因此,當您進行常規復制時,例如:
cv::Mat b;
cv::Mat a = b;
a
將指向b
的數據,並且它的引用計數將增加。 同時, b
之前指向的數據的引用計數會遞減(遞減后為0則釋放內存)。
問題 1:這取決於您的程序。 有關更多詳細信息,請參閱此問題: is-cvmat-class-flawed-by-design
問題2:函數按值返回。 這意味着return image
將復制 Mat 並增加引用計數(現在ref_count = 2
)並返回新的 Mat。 當函數結束時,圖像將被銷毀並且 ref_count 將減一。 但是內存不會被釋放,因為ref_count
不是 0。所以返回的cv::Mat
沒有指向隨機內存位置。
問題3:類似的事情發生了。 當你說orgImage2.copyTo(aCopy);
aCopy 指向的數據的aCopy
將減少。 然后分配新的內存來存儲將要復制的新數據。 這就是為什么在您執行此操作時copyCopy1
原因。
看看 c++11 std::shared_ptr以同樣的方式有效地工作,通過使用引用計數器 cv::Mat 巧妙地記住每次引用指針時,一旦計數達到 0,它就會自動釋放,即內存被釋放並且 cv::Mat 不再可用。 這實際上是一個“淺拷貝”,並在分配/取消分配大量內存時節省了資源。
另一方面, cv::Mat::clone 將提供一個“深拷貝”,為矩陣分配一個全新的內存塊,如果您正在對您可能想要的圖像進行轉換,這可能很有用然而,撤消更多的內存分配/解除分配會增加所需的資源量。
希望這可以幫助某人。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.