opencv Mat 浅拷贝 引用计数 与 写时复制

首先让我们熟悉两个概念:

1 浅拷贝

复制指针时只复制指针指向内存的地址 而不复制指针指向内存的内容

举例:

Mat a1;

Mat a2=a1;

则无论修改 a1还是a2的内容 a1 a2都会被一同修改 因为他们指向同一块内存

举例:

当一个容器 vector<Mat> v 有新的 元素被 push_back

则容器中的 所有元素 都会被更新成最后一个元素的内容  因为始终只有一个Mat对象 被引用了多次

他们都指向了相同的内存区域

2 引用计数

引用计数是一种内存管理技术,用于追踪每个对象(或内存块)被引用的次数。当一个对象的引用次数降至零时,表明没有任何引用指向该对象,此时可以安全地回收其占用的内存。

3写时复制

无法触发写实复制的情况:

当你将 frame 添加到如 vector<Mat> v 容器中时,如果仅使用赋值(v.push_back(frame);),实际上并没有修改数据,只是增加了一个新的引用。这时,写时复制不会触发,因为没有进行修改操作。容器中的每个元素仍然只是指向同一个数据块的引用。如果 frame 在循环的下一次迭代中被 vc.read() 修改,这些修改会影响到容器中所有之前添加的 Mat 对象,因为它们都共享同一数据块。

可以触发写时复制的情况:

如果你尝试修改 B 的内容(如 B.at<int>(0,0) = 255;),并且 A 和 B 是数据共享的,这时候写时复制会触发,B 会先复制一份数据进行修改,保证 A 的数据不被更改。

所以当如下代码被执行:

不会触发写时复制 也就是说不会单独拷贝对象的副本

容器中所有的元素都是同一个Mat对象指向最后一帧的内容

引用计数器的大小就是v.size

#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QStringList>
#include <opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    VideoCapture vc;
    vc.open("C:/Users/wang/Desktop/ft.mp4");
    Mat frame;
    vector<Mat> v;
    while (1) {
        vc.read(frame);
        if (frame.empty()) {
            break;
        }
        v.push_back(frame);
    }
    qDebug() << v.size() << "-----------";
    for (int var = 0; var < v.size(); ++var) {
        imshow("frame", v[var]);
        waitKey(1);
    }
    // Mat frame;
    // while (1) {
    //     vc.read(frame);
    //     if (frame.empty()) {
    //         break;
    //     }
    //     imshow("frame", frame);
    //     waitKey(1);
    // }
    vc.release();
    destroyAllWindows();
    return a.exec();
}

解决方案:

v.push_back(frame.clone()); 在压入容器时 明确指出压入的是一个副本 而不是引用

为什么在读取后立即显示不会出现这种情况?

大概是因为读取后 立即显示 没有做复制多个对象的操作 frame只是一个临时中转变量

#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QStringList>
#include <opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    VideoCapture vc;
    vc.open("C:/Users/wang/Desktop/ft.mp4");
    // Mat frame;
    // vector<Mat> v;
    // while (1) {
    //     vc.read(frame);
    //     if (frame.empty()) {
    //         break;
    //     }
    //     v.push_back(frame.clone());
    // }
    // qDebug() << v.size() << "-----------";
    // for (int var = 0; var < v.size(); ++var) {
    //     imshow("frame", v[var]);
    //     waitKey(1);
    // }
    Mat frame;
    while (1) {
        //读取
        vc.read(frame);
        if (frame.empty()) {
            break;
        }
        //立即显示
        imshow("frame", frame);
        waitKey(1);
    }
    vc.release();
    destroyAllWindows();
    return a.exec();
}


全剧终

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值