从 C++ OpenCV 中的 findNonZero 函数仅复制 Mat 的行索引

Copy only row indices of Mat from findNonZero function in C++ OpenCV

我正在尝试将 MATLAB 代码转换为 C++。 在 MATLAB 中,我使用 find 函数获取向量的索引,然后将这些索引复制到其他变量。例如:

idx = find(A>s);
B = idx;
% A, idx, and B are vectors; s is a scalar

在 C++ OpenCV (C++14 / OpenCV 3.4.10) 中我知道我可以使用 findNonZero 函数,但它 returns 行和列索引:

double s;
Mat1d A;
Mat1i B;
Mat idx;
.
.
.
findNonZero(A>s, idx);

我不知道如何直接复制行索引(不使用 for 循环)。我认为可以通过定义 Mat2i idx 并像这样使用 mixChannels 来完成:

Mat2i idx;
findNonZero(A>s, idx);
B = Mat1i::zeros(idx.size());
int from_to[] = {1, 0};
mixChannels(&idx, 1, &B, 1, from_to, 1);

但是,在 运行 findNonZero 函数时出现以下错误:

OpenCV(3.4.10) Error: Assertion failed (!fixedType() || ((Mat*)obj)->type() == mtype) in cv::debug_build_guard::_OutputArray::create,

但是如果我设置 Mat idx,我会在 运行 mixChannel 函数时得到另一个错误:

OpenCV(3.4.10) Error: Assertion failed (j < nsrcs && src[j].depth() == depth) in cv::mixChannels,

我不确定我应该做什么。感谢任何帮助。

MATLAB 的 find 确定输入矩阵中非零值的 column-major 索引。如果您指定它的单个输出版本,则为真。如果您提供两个输出变量,则会生成输入中非零值的行和列位置。在您的示例中,您提供了 find 的单一输出版本,所以我将使用它。

OpenCV 的 cv::Matrow-major 中布置图像。我假设您想要 row-major 索引。如果是这样,由于 cv::findNonZero 输出行和列坐标,您必须自己循环输出坐标并创建 row-major 索引。你不应该害怕在这里使用循环。事实上,for 遍历 cv::Mat 的循环针对快速访问进行了优化。因此:

Mat2i idx;
Mat1d A; // Define somewhere else
double s; // Define somewhere else

findNonZero(A > s, idx);
B = Mat1i::zeros(idx.total());
for (int i = 0; i < idx.total(); ++i) {
    B.at<int>(i) = idx.at<Point>(i).y * A.cols + idx.at<Point>(i).x;
}

B 将在 cv::Mat1i 中包含 row-major 个索引。如果我误解了您的询问,只是想要非零值的行位置,那么它只是:

Mat2i idx;
Mat1d A; // Define somewhere else
double s; // Define somewhere else

findNonZero(A > s, idx);
B = Mat1i::zeros(idx.total());
for (int i = 0; i < idx.total(); ++i) {
    B.at<int>(i) = idx.at<Point>(i).y;
}

请记住,您只是迭代非零值,因此最坏情况下的复杂度是迭代非零值。