簡體   English   中英

OpenCV cv::Mat 的深拷貝

[英]Deep Copy of OpenCV cv::Mat

復制cv::Mat的行為讓我很困惑。

我從文檔中了解到Mat::copyTo()是深拷貝,而賦值運算符不是。 我的問題:

  1. 我應該怎么做才能從函數返回cv::Mat ,例如: cv::Mat func()

  2. 根據文檔,如果我返回一個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM