OpenCV C ++如何知道每行轮廓的数量?

问题描述 投票:2回答:2

我有一个binary image:在这张图片中,我可以轻松地使用重载的std::sort对从上到下和从左到右找到的轮廓进行排序。

我首先从上到下排序:

sort(contours.begin(), contours.end(), top_to_bottom_contour_sorter());

然后我从左到右排序:

for (int i = 0; i < contours.size(); i = i + no_of_contours_horizontally)
    {
        sort(i, i + no_of_contours_horizontally, left_to_right_contour_sorter);
    }

其中top_to_bottomleft_to_right是我传递给sort函数的单独函数。而no_of_contours_horizontally相对于第一张图像是三(3)。

但是这只有在我知道水平轮廓的数量时才有效。如果我正在使用的图像将在水平方向上具有不同数量的轮廓,就像在此图像中一样。 contours_sample。该计划失败。我可以蛮力并定义一个特定的索引来改变找到的轮廓的数量。但是,它会限制程序在特定输入上运行而不是灵活。我正在考虑创建我可以叠加在图像顶部的rects或line,并计算内部轮廓的数量,这样我就可以获得水平轮廓数量的值。如果有一个更优雅的解决方案,我会很感激。

这是我的排序功能

bool top_to_bottom_contour_sorter(const std::vector<Point> &lhs, const std::vector<Point> &rhs)
{
    Rect rectLhs = boundingRect(Mat(lhs));
    Rect rectRhs = boundingRect(Mat(rhs));

    return rectLhs.y < rectRhs.y;
}

bool left_to_right_contour_sorter(const std::vector<Point> &lhs, const std::vector<Point> &rhs)
{
    Rect rectLhs = boundingRect(Mat(lhs));
    Rect rectRhs = boundingRect(Mat(rhs));

    return rectLhs.x < rectRhs.x;
}

编辑这是我当前的输出和每个图像的所需输出。使用第一个图像和我当前的工作代码。 Current_Output

我想要的第二张图像的输出。 Desired_Output

c++ sorting opencv
2个回答
1
投票

我猜,你唯一的问题是不尊重其中一个坐标的平等!?

开始了:

// Custom sorter.
bool sortContour(std::vector<cv::Point> a, std::vector<cv::Point> b)
{
    cv::Rect rectA = cv::boundingRect(a);
    cv::Rect rectB = cv::boundingRect(b);

    if (rectA.y == rectB.y)
        return (rectA.x < rectB.x);

    return (rectA.y < rectB.y);
}

int main()
{
    // Load image.
    cv::Mat image = cv::imread("contours.jpg", cv::IMREAD_GRAYSCALE);

    // There are some artifacts in the JPG...
    cv::threshold(image, image, 128, 255, cv::THRESH_BINARY);

    // Find contours.
    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(image, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);

    // Output unsorted contours.
    cv::Mat imageUnsorted = image.clone();
    for (int i = 0; i < contours.size(); i++)
    {
        cv::Rect rect = cv::boundingRect(contours[i]);
        cv::putText(imageUnsorted, std::to_string(i), cv::Point(rect.x - 10, rect.y - 10), cv::FONT_HERSHEY_COMPLEX, 0.5, cv::Scalar(255));
    }
    cv::imwrite("unsorted.png", imageUnsorted);

    // Sort using custom sorter.
    std::sort(contours.begin(), contours.end(), sortContour);

    // Output sorted contours.
    cv::Mat imageSorted = image.clone();
    for (int i = 0; i < contours.size(); i++)
    {
        cv::Rect rect = cv::boundingRect(contours[i]);
        cv::putText(imageSorted, std::to_string(i), cv::Point(rect.x - 10, rect.y - 10), cv::FONT_HERSHEY_COMPLEX, 0.5, cv::Scalar(255));
    }
    cv::imwrite("sorted.png", imageSorted);
}

未分类的轮廓:

Unsorted contours

排序的轮廓:

Sorted contours

正如你所看到的,人们也可以反转原始顺序,因为cv::findContours只是朝相反的方向发展。 ;-)

一个很大的警告:如果扫描(或者你获得调查)甚至逆时针稍微旋转,这个程序将失败。因此,应预先检查整个扫描(或......)的角度。


0
投票

一个简单实用的解决方案是排序

y*100 + x

在旋转输入的情况下,更复杂的东西也可以使用

  1. 选择两个blob之间的最小距离
  2. 让我们调用连接这两个点(dx, dy)的向量
  3. 根据(x*dx + y*dy)*100 + (x*dy - y*dx)排序

输出将是“网格”顺序(可能是您想要的或旋转90度,但旋转输入问题是不适合的,您应该使用一些规则在两者之间进行选择)。

© www.soinside.com 2019 - 2024. All rights reserved.