基于范围的 for 循环和 std::transform with input/output 迭代器在应用于 opencv Mat(rix) 行时不等效

range-based for loop and std::transform with input/output iterators not equivalent when applied to rows of opencv Mat(rix)

在一个较大的程序中,我遇到了以下问题,我不明白。

基本上,我正在处理一个 float (cv::Mat1f) 类型的 opencv 矩阵(文档 here)。 OpenCV 提供迭代器来迭代矩阵。当我使用基于范围的迭代器和对矩阵成员的引用遍历矩阵时,代码有效(下面示例中的test1)。

当我使用 std::transform 并将其应用于 整个 矩阵时,下面的代码 (test3) 也有效。

但是,当我按行进行迭代时,带有 std::transform 的版本失败(它永远不会(?)终止)。

(我处理行的原因是在实际应用程序中,行是在不同的并行线程中处理的,但这在这里无关紧要)

#include <iostream>
#include "opencv2/imgproc.hpp"

void test1(cv::Mat1f& img) {
    for (int r = 0; r < img.rows; r++)
        for (auto& v : img.row(r))
            v = v+1;
}

void test2(cv::Mat1f& img) {
    for (int r = 0; r < img.rows; r++)
        std::transform(
            img.row(r).begin(),
            img.row(r).end(),
            img.row(r).begin(),
            [](float v)->float { return v+1; });
}

void test3(cv::Mat1f& img) {
        std::transform(
            img.begin(),
            img.end(),
            img.begin(),
            [](float v)->float { return v+1; });
}

int main() {
    auto img = cv::Mat1f(5, 5, 0.0);

    int i = 0;
    for (auto &v : img)
        v = i++;

    std::cerr << img << "\n";

    test1(img);

    std::cerr << img << "\n";

    // test2(img); does not work
    test3(img); // works !

    std::cerr << img << "\n";
}

在我的系统上(在 /usr/local 中安装了 opencv)我 运行 上面的示例代码

g++ -std=c++17 -I/usr/local/include/opencv4 mwe.cpp -L/usr/local/lib  -lopencv_core && ./a.out

test2 中的代码有什么问题?

每次调用 row 都会创建一个新对象,并且这些对象具有不同的迭代器。
所以,row(r).begin() 永远不会等于 row(r).end().

改为从同一对象获取迭代器:

void test2(cv::Mat1f& img) {
    for (int r = 0; r < img.rows; r++)
        auto row = img.row(r);
        std::transform(
            row.begin(),
            row.end(),
            row.begin(),
            [](float v)->float { return v+1; });
}