【问题标题】:(OpenCV 2.4.6) Copy header of a Mat's roi to another Mat's roi(OpenCV 2.4.6) 将 Mat 的 roi 的标头复制到另一个 Mat 的 roi
【发布时间】:2014-05-26 08:39:51
【问题描述】:

我的问题是关于如何仅将 Mat 的 roi 的标头复制到 Mat 的另一个 roi 以避免复制整个 Mat 的数据以节省计算时间。

例如,我有一个源 Mat 的 roi 作为

Mat src(cv::Size(4,3),CV_32FC1);
for(int i=0;i<src.rows;i++){
  for(int j=0;j<src.cols;j++){
    src.ptr<float>(i)[j] = i*src.cols+j;
  }
}
Mat src_roi = src(Rect(1,1,src.cols-2,src.rows-1));
cout << src << endl;
cout << src_roi << endl;

// = = = OUTPUT = = =
[0, 1, 2, 3;
 4, 5, 6, 7;
 8, 9, 10, 11]
[5, 6;
 9, 10]

接下来,我希望结果如下所示,关键函数 (func()) 为

Mat dst(cv::Size(src.cols*src.rows,1),CV_32FC1);
dst.setTo(-1);
Mat dst_roi = dst.colRange(2,2+src_roi.cols*src_roi.rows);
func(src_roi,dst_roi);
cout << dst << endl;
cout << dst_roi << endl;

// = = = OUTPUT = = =
[-1, -1, 5, 6, 9, 10, -1, -1, -1, -1, -1, -1]
[5, 6, 9, 10]

基本上,func() 可以通过以下方式实现,以简单地达到我的预期输出(计算时间在发布模式下评估),

// A01 = = =
void func(const Mat &src,Mat &dst){
  Mat ma = src.clone();
  ma = ma.reshape(0,1);
  ma.copyTo(dst);
}
// = = = Computation time = = =
0.414 seconds // when src's size is changed to 15000*15000

// A02 = = =
void func(const Mat &src,Mat &dst){
  MatConstIterator_<float> it1 = src.begin<float>(), it1_end = src.end<float>();
  MatIterator_<float> dst_it = dst.begin<float>();
  for( ; it1 != it1_end; ++it1, ++dst_it ){
    *dst_it = *it1; 
  }
}
// = = = Computation time = = =
0.508 seconds // when src's size is changed to 15000*15000

// A03 = = =
void func(const Mat &src,Mat &dst){
  int count=0;
  for(int i=0;i<src.rows;i++){
    for(int j=0;j<src.cols;j++){
      ((float*)dst.data)[count++] = src.ptr<float>(i)[j];
    }
  }
}
// = = = Computation time = = =
0.269 seconds // when src's size is changed to 15000*15000

但是,它们都复制整个矩阵,因此只要 roi 很大,它们就会花费很多时间。

因此,我希望有一种方法可以仅复制标头或指针以达到相同的效果并节省所需的计算。 或者其他可以满足我期望的方式或想法。

【问题讨论】:

    标签: python c++ c opencv memory


    【解决方案1】:

    因为在您的 func() 中,您将每个元素复制了两次(首先是 src.clone() 和 copyTo())所以
    我想到的是通过直接将 elems 从 src 复制到 dst 来摆脱它们:

    void func(const Mat &src,Mat &dst){
        MatConstIterator_<float> it1 = src.begin<float>(), it1_end = src.end<float>();
        MatIterator_<float> dst_it = dst.begin<float>();
    
        for( ; it1 != it1_end; ++it1, ++dst_it )
            *dst_it = *it1; 
    }
    

    您不必关心 src 和 dst 的大小,但它们必须具有相同数量的元素。

    但坦率地说,我认为您无法避免该副本,因为 src 和 dst 具有不同的大小格式。你不能直接在 src_roi 上做 reshape() 因为它不是连续的。这就是您所期望的,因为您无法重塑一个矩阵,该矩阵是较大矩阵的一部分,在某些 roi 上改变其格式形状,而不是在整个矩阵中改变。我的意思是如果标题的大小格式不同,你不能告诉 opencv 只复制标题 roi。

    【讨论】:

    • 感谢您的回答。此外,我已将您的建议添加到我的问题中,并且我还评估了计算时间以进行比较。
    • 根据我从官方 API 中了解到的情况,在我们的案例中无法避免复制,因为关键是当您想要将矩阵格式(即从二维变为一维)更改时。在这种情况下,opencv 不允许在 func() 中的 src 变量上调用 reshape() 因为 reshape() 会影响对象本身(而不是它返回其他对象的副本),而且在我们的 func() 中 src 它已经是roi 从更大的矩阵中裁剪。如果您的案例不包含不断变化的矩阵形状,您可以分配 dst = src;在函数()中
    • - 并且复制无效。但是您仍然可以访问 Mat::data 指针,因此可能存在一些 hack。如果您得到答案,请告诉我们。
    • 确实如此。但我看到了一些潜在的技术可能性,因为它可能被视为现有的 roi 实现Mat::Mat(const Mat&amp; m, const Rect&amp; roi),可能有一些位置安排。然而,我并没有完全理解它,因此希望得到一些帮助:(
    猜你喜欢
    • 2012-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多