前言
之前搜到一篇,使用无误。后来需用到此方法,又搜了一下,发现了一个小细节不同,导致最终 QImage 转 cv::Mat 失败。同时对两个函数稍微看了一下。
Qt 隐式数据共享
在这之前有必要了解一下Qt 中的数据储存模式。
Qt中使用隐式数据共享:为优化执行速度和节约内存设计的,详情见Qt 的文档中的
Implicit Sharing
。这里仅摘要他的简述,文档下面详细介绍了运行机制。
- Many C++ classes in Qt use implicit data sharing to maximize resource usage and minimize copying. Implicitly shared classes are both safe and efficient when passed as arguments, because only a pointer to the data is passed around, and the data is copied only if and when a function writes to it, i.e., copy-on-write
重要的就是最后一句说明,数据的完全拷贝仅仅在指向数据的指针将数据发生了改变进行。下面进行说明。
操作不进行深层拷贝
QImage img;
Qimag a,b,c,d;
a=img;
b=img;
c=img,
d=img;
在内存中始终只存在一个img 的数据,其他都只是获得引用,也就是保存一个数据的指针。(此时img引用计数变成5个)
同时需要注意,a,b,c,d 的 bit() 数据是指向了一个新的地址,与img 的bits() 不同。但是a,b,c,d的 constBits() 与 img保持相同(即获得引用)
调用 bits() 函数就进行深层拷贝,此时a,b,c,d的 constBits() 与 bits() 相同,与img的地址不同。这时已经不是隐式数据共享,而是进行了深层拷贝(通过观察任务管理器的内存跟想象一样)。
操作进行深层拷贝
QPainter p(&d);
p.drawRect(10,10,50,50);
//或者下面的操作
d.setPixelColor(10,20,QColor(Qt::red));
//或者
uchar *pdata=d.bits();
for (int i=0;i<1920*3*100;++i){
pdata[i]=0;
}
//只要进行了像素的修改就进行深层拷贝
此时d进行了数据的更改,d的数据进行了深层拷贝,img的引用计数减一(此时img的引用计数变为4),d与img无任何关系。内存中含有两张图片的内存。
此时d 的 bits() 和 constBits() 地址一样。
实验
目的,通过修改隐式共享的图像,让其进行深度拷贝,脱离原对象