【问题标题】:Compare column by column逐列比较
【发布时间】:2017-08-07 21:41:52
【问题描述】:

在这种方法中,我想为cv::Mat 中的 each 列找到两个(相邻)点之间的最大距离。最后应该返回对应的点(彼此之间的距离最大)。

为了实现这一点,我已经研究了很多,现在我坚持使用这个代码 sn-p:

cv::Mat mat;
std::vector<cv::Point> pointVec, finalPointVec;
std::vector<float> allDist;
for (int i = 0; i < mat.rows; i++) {

    for (int j = 0; j < mat.cols; j++) {
        c = mat.col(j);

        if (c.at<Vec3b>(i, j)[0] == 0
            && c.at<Vec3b>(i, j)[1] == 0
            && c.at<Vec3b>(i, j)[2] == 255) {
            cv::Point diPoint(j, i);

            pointVec.push_back(diPoint);

            if (pointVec[j].x == pointVec[j + 1].x) {
                //std::cout << pointVec[j].y << "\n";

                float diffY = pointVec[j].y - pointVec[j + 1].y;
                float diffX = pointVec[j].x - pointVec[j + 1].x;
                float dist = sqrt((diffY * diffY) + (diffX * diffX));
                for (int d = 0; d < pointVec[j].x; d++) {

                    allDist.push_back(dist);
                }
        }
    }
}

所以我已经遍历了cv::Mat 并计算了距离。现在我想实现查找 each 列的最大距离。我在这里寻求您的帮助,我怎么能意识到这一点。虽然我认为if (pointVec[j].x == pointVec[j + 1].x) 应该可以找到相同的列,但它似乎是错误的实现。另外 - 我如何返回那些彼此距离最大的点?

也许我需要澄清一下,这里是一张图片,它应该是什么样子(圈出的点应该是那些,必须返回):

我很高兴任何答案!

【问题讨论】:

  • 首先,遍历列。为清楚起见,我建议在该循环内调用类似“find_greatest_distance”的函数。该函数应该遍历列中的行,使用“foreach first point, foreach second point calculate distance and remember it if it is greater than the current remembered distance”的算法。
  • @PaulHicks 我实际上已经循环遍历列和行?或者你是什么意思?
  • 您当前首先循环遍历行,然后遍历列。你需要反过来做。另外,您需要一个额外的循环:您需要在列循环内嵌套一个列循环。我建议使用函数,如果你在一个代码块中完成它会太混乱且难以理解。
  • 你的意思是距离应该只在同一列中的点之间进行比较? col[j]col[j+1] 是不同的列。
  • 你必须重写条件,因为现在还不清楚你想要实现什么。您是要计算每列中所有点之间的距离,还是只计算特定列中彼此相邻的点对之间的距离?

标签: c++ opencv


【解决方案1】:

如果我对任务的理解正确,你需要将你的算法分成两个阶段,因为我认为你不能在同一个循环中有效地完成这两件事:

  1. 填充pointVec

  2. 遍历pointVec并计算距离

填充pointVec

cv::Mat mat;
std::vector<cv::Point> pointVec;
const cv::Vec3b sought_value(0, 0, 255);

for (int i = 0; i < mat.rows; i++) {
    for (int j = 0; j < mat.cols; j++) {

        if (mat.at<Vec3b>(i, j) == sought_value) {
            pointVec.emplace_back(cv::Point(i, j));
        }

    }
}

我使用emplace_back() 而不是push_back() 并消除了用于存储点的临时变量,即使在这种情况下,由于优化,性能差异可能很小。我还介绍了sought_value,因为我认为这样更容易阅读,但取决于你选择哪个版本。

遍历pointVec并计算距离

如果我们先根据列对pointVec 进行排序,然后再对行进行排序,那么第 2 步会容易得多。这样我们就知道连续的点通常彼此相邻并且属于同一列。另外,我将使用std::tuple&lt;int, float, std::pair&lt;cv::Point, cv::Point&gt;&gt; 存储每列的最大距离以及列号和距离所指的点,因为这样我们可以轻松定位点并根据需要搜索每列的最大距离。

// keeps the results - column number, distance and points respectively:
using ColDistPointsTuple = std::tuple<int, float, std::pair<cv::Point, cv::Point>>;
std::vector <ColDistPointsTuple> column_maxes;

std::sort(column_maxes.begin(), column_maxes.end(),
    [](const cv::Point& a, const cv::Point& b) -> bool
    {
    if (a.x < b.x)
        return true;
    else if (a.x == b.x)
        return a.y < b.y;
    else
        return false;
    }
);

for (int j = 0; j < pointVec.size() - 1; ++j) // note '-1' here - otherwise you'll get out of bounds exception 
{
    if (pointVec[j].x == pointVec[j + 1].x) {

        float diffY = pointVec[j].y - pointVec[j + 1].y;
        float diffX = pointVec[j].x - pointVec[j + 1].x;
        float dist = sqrt((diffY * diffY) + (diffX * diffX));

        if (!column_maxes.empty())
        {
            if (std::get<0>(column_maxes.back()) == pointVec[j].x) // belongs to the same column
            {
                if (dist > std::get<1>(column_maxes.back())) // distance greater than the one stored for that column
                {
                    column_maxes.back() = 
                        std::make_tuple( pointVec[j].x, dist, pointVec[j], pointVec[j + 1] );
                    continue;
                }
            } 
        }

        column_maxes.emplace_back( pointVec[j].x, dist, pointVec[j], pointVec[j+1] );

    }
}

column_maxes 分别保存列号、距离和点数。我本可以跳过列号,但我认为搜索基于元素的例如在向量中属于元组对的点的第一个坐标上(啊!)将非常丑陋且违反直觉。就语法而言,上面的元组并不是最漂亮的东西,但我认为符合您想要使用结果的方式。

我没有机会测试此解决方案,因此它可能包含一些小错误,但总体思路应该可行。

如果您要根据列号进行大量搜索,请考虑使用std::map,将列号作为键,将距离和一对cv::Points 组成的元组作为值。基本算法看起来是一样的,但是你必须用映射迭代器替换对operator[] 的调用。点插入也会比较慢,所以这个解决方案就像上面显示的那样有其优点和缺点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-06
    • 2021-04-27
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 2019-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多