Текущая ситуация: я пытаюсь извлечь сегменты из изображения. Благодаря методу openCV findContours()
теперь у меня есть список 8-связных точек для каждого контура. Однако эти списки нельзя использовать напрямую, поскольку они содержат много дубликатов.
Проблема: дан список из 8 связанных точек, которые могут содержать дубликаты, извлечь из него сегменты.
Возможные решения:
- Сначала я использовал метод openCV
approxPolyDP()
. Однако результаты довольно плохие... Вот увеличенные контуры:
Вот результат approxPolyDP()
: (9 сегментов! Некоторые перекрываются)
но то, что я хочу, больше похоже на:
Это плохо, потому что approxPolyDP()
может преобразовать то, что "выглядит как несколько сегментов" в "несколько сегментов". Однако у меня есть список точек, которые имеют тенденцию повторяться несколько раз.
Например, если мои точки:
0 1 2 3 4 5 6 7 8
9
Тогда список точек будет 0 1 2 3 4 5 6 7 8 7 6 5 4 3 2 1 9
... И если количество точек станет большим (>100), то сегменты, извлеченные approxPolyDP()
, к сожалению, не дублируются (т.е.: они перекрывают друг друга, но не строго равны, поэтому я нельзя просто сказать "удалить дубликаты", в отличие, например, от пикселей)
- Возможно, у меня есть решение, но оно довольно длинное (хотя и интересное). Прежде всего, для всех 8-связных списков я создаю разреженную матрицу (для эффективности) и устанавливаю значения матрицы равными 1, если пиксель принадлежит списку. Затем я создаю график с узлами, соответствующими пикселям, и ребрами между соседними пикселями. Это также означает, что я добавляю все недостающие ребра между пикселями (сложность небольшая, возможно из-за разреженной матрицы). Затем я удаляю все возможные "квадраты" (4 соседних узла), и это возможно, потому что я уже работаю с довольно тонкими контурами. Затем я могу запустить алгоритм минимального связующего дерева. И, наконец, я могу аппроксимировать каждую ветвь дерева с помощью
approxPolyDP()
openCV.
Подводя итог: у меня есть утомительный метод, который я еще не реализовал, так как он кажется подверженным ошибкам. Тем не менее, я спрашиваю вас, людей из Stack Overflow: существуют ли другие существующие методы, возможно, с хорошей реализацией?
Изменить: чтобы уточнить, когда у меня есть дерево, я могу извлечь «ветви» (ветки начинаются с листьев или узлов, связанных с 3 или более другими узлами). Затем алгоритм в approxPolyDP()
openCV - это алгоритм Ramer-Douglas-Peucker, а вот изображение из Википедии, что он делает:
С этой картинкой легко понять, почему она терпит неудачу, когда точки могут быть дубликатами друг друга.
Еще одно редактирование: в моем методе есть кое-что, что может быть интересно отметить. Когда вы рассматриваете точки, расположенные в сетке (например, пиксели), то, как правило, алгоритм минимального связующего дерева бесполезен, поскольку существует множество возможных минимальных деревьев.
X-X-X-X
|
X-X-X-X
принципиально сильно отличается от
X-X-X-X
| | | |
X X X X
но оба являются минимальными остовными деревьями
Однако в моем случае мои узлы редко образуют кластеры, потому что они должны быть контурами, и уже есть алгоритм прореживания, который запускается заранее в findContours()
.
Ответ на комментарий Томалака:
Если бы алгоритм DP возвращал 4 сегмента (отрезок от точки 2
до центра был там дважды), я был бы счастлив! Конечно, при хороших параметрах я могу дойти до состояния, когда «случайно» у меня есть одинаковые сегменты, и я могу удалить дубликаты. Однако очевидно, что алгоритм не предназначен для этого.
Вот реальный пример со слишком большим количеством сегментов:
are unfortunately not duplicates (i.e : they overlap each other, but are not stricly equal, so I can't just say "remove duplicates", as opposed to pixels for example)
Я этого не понимаю. Почему нет? - person Lightness Races in Orbit   schedule 20.06.2011