X''*_*X'' 16 c++ oop resources opencv
我使用OpenCV C++接口工作了很多,并设计了许多使用Mat作为私有资源的类.
最近,我关注Mat类,因为它总是使用图像数据作为共享资源,除非我明确地调用clone.即使我写了,const Mat
我也不能确定imagedata以后不会从外面改变.
所以我需要克隆以确保封装.但是需要明确克隆Mat的问题在于它通常是不必要且昂贵的.另一方面,我理解共享图像数据的需求源于roi选择器,并且能够编写如下内容:
Mat m_small = m_big(my_roi)
.
我的问题是:
1.)cv :: Mat类不应该被懒得克隆吗?因此,用户不会将Mat视为来自外部的共享资源处理程序.用户是否应该显式实例化一个类似于SharedMat
需要真正的共享图像数据的类?
2.)如果cv :: Mat作为一个类的私有资源,你有没有比克隆更好的策略?
更新:" Mat::clone()
除非您计划修改数据,否则不要使用." (作者:Vadim Pisarevsky)
这个想法存在问题.
考虑一下这个类的情况:
class Res_handler{
public:
const Mat emit_mat(){ return m_treasure; } // I argue you are compelled to clone here.
private:
Mat m_treasure;
};
Run Code Online (Sandbox Code Playgroud)
如果你不在clone
这种情况下你可以写
Mat m_pirate = res_handler.emit_mat(); m_pirate = Scalar(0,0,0);
Run Code Online (Sandbox Code Playgroud)
通过和之间的共享图像数据导致m_treasure
内部完全黑屏.:)所以为了避免意外修改内部,你需要它.res_handler
m_pirate
m_treasure
m_treasure
clone
另一方面,这个解决方案也存在缺陷:
const Mat m_pirate = res_handler.emit_mat();
Run Code Online (Sandbox Code Playgroud)
因为m_treasure
也可以修改,所以内容m_pirate
在后台变化,给海盗的程序员带来了极大的麻烦.:)
Jon*_*rdy 12
是的,这是一个糟糕的设计.因为在Mat
内部实现共享所有权,所以它与选择所有权策略的标准方式不兼容,即智能指针.基本问题是数据和所有权是正交的,应该是分开的.
因为它是可变的,即使a const Mat
更像是a const shared_ptr<Mat>
,也无法描述所包含的Mat
应该是可变的,即shared_ptr<const Mat>
.final
如果您熟悉的话,这与Java中的问题非常相似.
我相信你可以通过包装Mat
暴露相同接口的类来解决这些问题Mat
,但是它在默认的共享实现上实现了写时复制行为.
小智 11
[无耻的广告]我们现在有answers.opencv.org,这是针对OpenCV特定问题的StackOverflow.
现在问题:
不,我们没有看到实现这一目标的有效方法.如果你这样做,我们来讨论吧.
是.Mat::clone()
除非您计划修改数据,否则请勿使用.当不再使用数据时,引用计数负责正确地重新分配数据.
回答OP问题:
是的,绝对是!正如一些人所指出的那样:OpenCV使您无法描述对图像的const引用.这确实是一个缺陷."const cv :: Mat&"并不是c ++程序员所期望的那样,而且我经常发现自己在我的代码中遍布clone()调用,以至于我开始失去数据共享的好处.
要回答Vadims有关如何有效地做到这一点的问题:
尽管不是没有API更改,但绝对有可能有效地执行此操作.看看Qt如何放弃它在Qt 4(类似于OpenCV的当前模型)之前的显式共享模型,以及它当前的隐式共享(写入时复制)并取得了巨大的成功.基本上所有改变对象的函数调用,或者返回一个稍后可以改变对象的引用都必须"deref"它.如果有多个引用,那就是复制.
与图像操作的平均成本相比,这是微不足道的.如果必须按像素执行,则变得禁止.这就是为什么这个班需要分成两个.很像cv :: Mat和cv :: Mat_.一个负责隐式共享和复制,一个只是IplImage的模板包装器.这里的API是什么一个例子可能看起来像(我已经选择了清晰明确的过度名):
// The following makes no unnecessary copies. Only a
// couple of atomic increments and decrements.
const cv::Image img = cv::Image("lenna.bmp").toGray().brighter(0.3).inverted();
cv::Image copy(img);// Still no deep copy.
cv::ConstImageRef<char> src = img.constRef<char>();// Still no deep copy.
// This is where the copy(detach) happens.
// "img" is left untouched
cv::MutableImageRef<char> dst = copy.ref<char>();
// The following is as efficient as it has ever been.
for(int y = 0; y<dst.height(); y++)
for(int x = 0; x<dst.width(); x++)
dst.at(x, y) += src.at(x, y);
Run Code Online (Sandbox Code Playgroud)
我意识到有太多的OpenCV代码浮动进行任何根本性的改变,并且用OpenCV 3进行API更改的窗口已关闭,但我不明白为什么不应该添加新的改进接口.
归档时间: |
|
查看次数: |
2775 次 |
最近记录: |