将一行 cv::Mat 转换为 std::vector

Posted

技术标签:

【中文标题】将一行 cv::Mat 转换为 std::vector【英文标题】:Converting a row of cv::Mat to std::vector 【发布时间】:2012-03-20 15:47:06 【问题描述】:

我有一个相当简单的问题:如何取出cv::Mat 的一行并获取std::vector 中的所有数据? cv::Mat 包含 doubles(就问题而言,它可以是任何简单的数据类型)。

浏览 OpenCV 文档非常令人困惑,除非我将页面添加为书签

我找到了cv::Mat::at(..) 来访问 Matrix 元素,但我记得 C OpenCV 至少有 3 种不同的方式来访问元素,它们都用于不同的目的......不记得是什么用于哪个:/

因此,虽然逐个元素复制 Matrix 肯定会奏效,但我正在寻找一种更高效并且如果可能的话更优雅的方法> 而不是每行的 for 循环。

【问题讨论】:

我认为这是一个重复的问题:***.com/questions/5405070/… @piokuc 我看到了那个,但那是特定于平台的(Visual Studio),对于 OpenCV 2.0(比今天更旧的版本)涉及特定的 cv::Mat 包装器@ 987654329@ 【参考方案1】:

应该很简单:

m.row(row_idx).copyTo(v);

其中mcv::Mat,具有CV_64F 深度,vstd::vector<double>

【讨论】:

哇,这太棒了。但是,因为我实际上需要创建一个新向量并用数据填充它,所以我认为在这种情况下,只提供指向向量构造函数的指针会更好。 这应该是答案。如此简单!【参考方案2】:

OpenCV 矩阵中的数据以行优先顺序排列,因此保证每一行都是连续的。这意味着您可以将一行中的数据解释为纯 C 数组。下面的例子直接来自the documentation:

// compute sum of positive matrix elements
// (assuming that M is double-precision matrix)
double sum=0;
for(int i = 0; i < M.rows; i++)

    const double* Mi = M.ptr<double>(i);
    for(int j = 0; j < M.cols; j++)
        sum += std::max(Mi[j], 0.);

因此,最有效的方法是将纯指针传递给std::vector

// Pointer to the i-th row
const double* p = mat.ptr<double>(i);

// Copy data to a vector.  Note that (p + mat.cols) points to the
// end of the row.
std::vector<double> vec(p, p + mat.cols);

这肯定比使用begin()end() 返回的迭代器要快,因为它们需要额外的计算来支持行之间的间隙。

【讨论】:

【参考方案3】:

从here 的文档中,您可以通过cv::Mat::row 获取特定行,这将返回一个新的cv::Mat,您可以在其上使用cv::Mat::begincv::Mat::end 进行迭代。因此,以下应该有效:

cv::Mat m/*= initialize */;
// ... do whatever...
cv::Mat first_row(m.row(0));
std::vector<double> v(first_row.begin<double>(), first_row.end<double>());

请注意,我不知道任何 OpenCV,但谷歌搜索“OpenCV mat”直接导致基本类型文档,据此,这应该可以正常工作。

矩阵迭代器是随机访问迭代器,因此它们可以传递给任何 STL 算法,包括 std::sort()。

这也来自文档,因此您实际上可以在没有副本的情况下执行此操作:

cv::Mat m/*= initialize */;
// ... do whatever...
// first row          begin              end
std::vector<double> v(m.begin<double>(), m.begin<double>() + m.size().width);

要访问第一行以外的内容,我建议使用第一个 sn-p,因为这样会更干净,而且似乎没有任何繁重的复制,因为数据类型似乎是引用 -计数。

【讨论】:

您在第二个示例中是指m.size().width 吗?请注意,OpenCV 矩阵以行为主存储,并且您正在添加 rows 的数量,而您可能应该添加 columns 的数量。 @Ferdinand:糟糕,是的,这确实是我的本意。感谢您的提示。 可以直接用m.cols代替m.size().width【参考方案4】:

你也可以使用cv::Rect

m(cv::Rect(0, 0, 1, m.cols)) 

会给你第一行。

matrix(cv::Rect(x0, y0, len_x, len_y);

表示你会从matrix得到sub_matrix,它的左上角是(x0,y0),大小是(len_x, len_y)(row,col)

【讨论】:

应该是m(cv::Rect(0, 0, m.cols, 1)),而不是1, m.cols【参考方案5】:

我认为这可行,

一个例子:

Mat Input(480, 720, CV_64F, Scalar(100));

裁剪矩阵的第一行:

Rect roi(Point(0, 0), Size(720, 1));

然后:

std::vector<std::vector<double> > vector_of_rows;

vector_of_rows.push_back(Input(roi));

【讨论】:

以上是关于将一行 cv::Mat 转换为 std::vector的主要内容,如果未能解决你的问题,请参考以下文章

将 Magick::Image 转换为 cv::Mat

将 cv::Mat 转换为 vector<int>

使用原始数据将 QImage 转换为 cv::Mat

如何正确将 cv::Mat 转换为 CV_8UC1?

将 cv::mat 转换为 QImage

如何将 cv::Mat 类型从 CV_16UC1 转换为 CV_8UC1