【问题标题】:Filling cv::Mat calling function row by row?逐行填充 cv::Mat 调用函数?
【发布时间】:2017-06-06 07:33:06
【问题描述】:

我有这个方法:

//codeSize previously defined
void generateRow(cv::Mat1f &row){
  if(row.cols != codeSize || !row.isContinous() || row.rows!=1)
    return;
  //fill row somehow
}

我想这样称呼它:

cv::Mat1f mat(rows,cols);
for(size_t i=0; i<rows; i++)
  generateRow(mat.row(i));

但我收到此错误消息:

../EncoderManager.cpp:100:37: error: invalid initialization of non-const reference of type ‘cv::Mat1f& {aka cv::Mat_<float>&}’ from an rvalue of type ‘cv::Mat_<float>’

我该如何解决这个问题?

可能的解决方案:

for(size_t i=0; i<rows; i++){
  cv::Mat1f row(1,cols);
  generateRow(row);
  row.row(1).copyTo(mat.row(i));
}

这是唯一的解决方案吗?如果是这样并且如果rows 很大,这将是超级低效的!

原始代码:

调用方法:

encoder->encode(imgDesc,code);

调用的方法:

void Encoder::encode(cv::Mat1f &descriptors, cv::Mat1f &code){
    if(!checkCode(code) || !checkRows(code,1) || !checkDescriptors(descriptors)){
        throw std::runtime_error("wrong descriptors");
        return;
    }
    encode_(descriptors, code);
}

错误:

../EncoderManager.cpp: In member function ‘void EncoderManager::GenerateSampledCodes(cv::Mat1f&, int, const string&, const string&, const string&)’:
../EncoderManager.cpp:104:37: error: invalid initialization of non-const reference of type ‘cv::Mat1f& {aka cv::Mat_<float>&}’ from an rvalue of type ‘cv::Mat_<float>’
    encoder->encode(imgDesc,codes.row(i));
                                     ^
In file included from ../EncoderManager.hpp:11:0,
                 from ../EncoderManager.cpp:10:
../Encoder.hpp:21:7: note:   initializing argument 2 of ‘void Encoder::encode(cv::Mat1f&, cv::Mat1f&)’
  void encode(cv::Mat1f &descriptors, cv::Mat1f &code);

【问题讨论】:

  • 您可以将cv::Mat1f mat 的指针或引用连同行索引一起传递到generateRow 以避免不必要的复制。
  • @alexisrozhkov 你能写一个答案吗?我不确定我是否理解您的解决方案
  • 我尝试了您的代码,它对我来说可以正常工作。你能发一个minimal reproducible example吗? code 在哪里定义?是全局变量吗?
  • 对不起@Miki,我只是发布了一小部分代码,因为其余部分非常复杂,我不明白它怎么可能编译并为你工作..顺便说一句你同意我们不能用上面的代码逐行填充矩阵吗?
  • 实际上,我正在尝试了解您如何无法填充矩阵,因为这应该可以正常工作;)

标签: c++ opencv


【解决方案1】:

如果您想避免因复制而产生的开销,您可以在generateRow() 中传递分配的矩阵并在那里对其进行初始化(并且可能将其重命名为initRow() 以使其用途更清晰)。

那么你的代码可能会是这样的:

void initRow(cv::Mat1f &mat, const size_t rowIdx){
  if(mat.cols != codeSize || !code.isContinous() || mat.rows <= rowIdx)
      return;

  //fill row somehow
}

...

cv::Mat1f mat(rows,cols);

for(size_t i=0; i<rows; i++)
  initRow(mat, i);

【讨论】:

  • 我不明白这有什么帮助。无论如何,在initRow 内部,//fill row somehow 将涉及一个副本。阅读this了解更多
  • 您可能应该提供fill row somehow 的实现,因为这似乎与您的问题有关。但是我现在看到的方式不一定涉及副本-您可以直接写入mat条目而无需创建临时行。
  • 使用at&lt;&gt; 并直接逐个元素填充效率极低,正如here 所解释的那样。
  • 首先,这超出了你的问题的范围,它是逐行填充简历垫。其次 - 现在您可以选择每次分配一个临时行并复制或复制到相应的完整矩阵行中,或者按照我建议的方式逐元素填充它。考虑到分配的开销,我会惊讶地发现创建临时结构会更快。
  • 如果性能在您的应用程序中至关重要,您始终可以直接使用矩阵数据,但这在原始问题中不清楚
【解决方案2】:

如果您不介意丢失cv::Mat1f 接口,您可以通过指针直接访问该行。这样您就不需要为您的行创建 cv::Mat1f 包装器:

void generateRow(float * const row){
  // fill row[0], row[1], etc
}

generateRow(mat.ptr<float>(row_number));

另外,您是否尝试通过generateRow(cv::Mat1f(mat.row(i))) 调用您的原始函数?我认为它不会复制任何数据,只是为行矩阵创建一个新标题。

【讨论】:

  • 感谢您的回答。首先,我刚刚将所有内容从cv::Mat 迁移到cv::Mat1f,所以不,我不能将它改回cv::Mat :D 此外,使用指针会丢失Mat 中使用的整个Mat 结构@ .最后,如果您调用generateRow(cv::Mat1f(mat.row(i))),我认为您动态创建了一个传递给generateRowmat.row(i) 的对象不会被修改。
  • 我没有提到cv::Mat。然后,创建 cv::Mat1f 包装器是您的解决方案,因为您创建了函数所需的对象并且它不会创建副本(因此动态创建的 cv::Mat1f 对象实际上是您的行的别名) .
猜你喜欢
  • 1970-01-01
  • 2014-06-21
  • 1970-01-01
  • 1970-01-01
  • 2015-10-23
  • 2012-11-27
  • 1970-01-01
  • 2013-06-10
  • 1970-01-01
相关资源
最近更新 更多