OpenCV C ++, как узнать количество контуров в строке для сортировки? - PullRequest
0 голосов
/ 01 марта 2019

У меня есть двоичное изображение: На этом изображении я легко могу отсортировать контуры, которые я нашел сверху вниз и слева направо, используя перегруженные std::sort.

Iсначала сортируйте сверху вниз с помощью:

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_bottom и left_to_right - отдельные функции, которые я передаюфункция сортировки.И no_of_contours_horizontally по отношению к первому изображению составляет три (3).

Однако это работает, только если я знаю количество контуров по горизонтали.Если изображение, которое я использую, будет иметь различное количество горизонтальных контуров, как на этом изображении. contours_sample .Программа не работает.Я мог бы грубой силой и определить для конкретного индекса, чтобы изменить количество найденных контуров.Тем не менее, это ограничило бы программу для работы с определенным входом вместо гибкости.Я имею в виду создание линий или линий, которые я могу наложить поверх изображения, и с этим посчитать количество контуров внутри, чтобы я мог получить значение количества горизонтальных контуров.Если бы было более элегантное решение, я был бы признателен.

Вот мои функции сортировки

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

Ответы [ 2 ]

0 голосов
/ 01 марта 2019

Полагаю, вашей единственной проблемой было не соблюдение равенства для одной из координат!?

Вот так:

// 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 голосов
/ 01 марта 2019

Простым практическим решением является сортировка по

y*100 + x

Что-то более сложное, что будет работать и при вращающемся вводе:

  1. Выберите минимальное расстояние между двумя каплями
  2. Давайте назовем вектор, соединяющий эти две точки (dx, dy)
  3. Сортировка на основе (x*dx + y*dy)*100 + (x*dy - y*dx)

Вывод будет в «сеточном» порядке (может бытьтот, который вы хотите, или один, повернутый на 90 градусов, но с повернутым вводом проблема некорректна, вы должны выбрать между двумя, используя некоторое правило).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...