Opencv: преобразовать изображение плана здания в модель данных

мой план состоит в том, чтобы извлечь информацию из плана этажа, нарисованного на бумаге. Мне уже удалось обнаружить 70-80% оттянутых дверей:

Detecting doors in a floorplan

Теперь я хочу создать модель данных со стен. Мне уже удалось извлечь их, как вы можете видеть здесь:

extracted walls Из этого я создал контуры:

extracted wall lines Моя идея теперь состояла в том, чтобы получить пересечения линий с этого изображения и создать из них модель данных. Однако, если я использую алгоритм houghlines, я получаю что-то вроде этого:

enter image description here Есть ли у кого-то другое представление о том, как получить перекрестки или даже другую идею о том, как получить модель? Было бы очень приятно.

PS: Я использую javacv. Но алгоритм в opencv также был бы в порядке, как я мог бы это перевести.

Ответ 1

Мне кажется, что то, что вы действительно хотите, это не стены, а комнаты, которые, кстати, ограничены стенами.

Кроме того, хотя кажется, что ваши "стенные" данные довольно шумные (т.е. есть множество небольших разделов, которые можно смутить для маленьких комнат), но ваши "комнатные" данные не являются (их не так много) w600 > стены в середине комнат).

Таким образом, может быть полезно обнаружить комнаты (ориентированные по оси прямоугольники, которые не содержат белые пиксели над определенным порогом), и экстраполировать стены, просматривая границу между соседними пикселями.

Я бы выполнил это в три этапа: во-первых, попытайтесь обнаружить несколько основных осей из вывода houghlines (я бы сначала дошел до алгоритма кластеризации K-mean, а затем массировал вывод, чтобы получить перпендикулярную ось). Используйте эти данные для лучшего выравнивания изображения.

Во-вторых, начинайте посеять маленькие прямоугольники случайным образом вокруг изображения, в черных областях. "Растите" эти прямоугольники во всех направлениях, пока каждая сторона не ударит по белому пикселю над определенным порогом или не столкнется с другим прямоугольником. Продолжайте посев до тех пор, пока не будет покрыт большой процент площади изображения.

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

  • Обработать координаты прямоугольников на оси x & y независимо - в виде набора интервалов
  • Отсортируйте эти координаты и найдите смежные координаты, которые образуют верхнюю границу одного прямоугольника и нижнюю границу другого.
  • Наивно попробуйте объединить эти пробелы, найденные вдоль каждой оси, и протестировать полученные прямоугольники кандидатов для пересечения с комнатами. Отбросить пересекающиеся прямоугольники.
  • Свернуть эти новые прямоугольники в строки вдоль их основной оси.
  • Точки на концах линий затем могут быть соединены, когда они находятся на некотором минимальном расстоянии (расширяя линии до тех пор, пока они не совпадут).

Есть несколько недостатков этого подхода:

  • Это не будет хорошо работать с неосвещенными стенками. К счастью, вы, вероятно, хотите, чтобы они автоматически выровнялись большую часть времени в любом случае.
  • Скорее всего, он будет обрабатывать небольшие дверные проемы в стенах как часть стены - случайный зазор в чертеже линии. Они должны быть обнаружены отдельно и добавлены обратно к восстановленному чертежу.
  • Он не будет хорошо разбираться в шумных данных, но похоже, что вы уже сделали замечательную работу по деионизации данных с opencv уже!

Извиняюсь за то, что вы не указали фрагменты кода, но я подумал, что более важно передать идею, а не детали (просьба прокомментировать, если вы хотите, чтобы я расширил ее). Также обратите внимание, что, хотя несколько лет назад я играл с opencv, я ни в коем случае не специалист, поэтому у вас могут быть некоторые примитивы, чтобы сделать что-то из этого для вас.

Ответ 2

Во-первых, вы также можете использовать детектор линейного сегмента для обнаружения линий: http://www.ipol.im/pub/art/2012/gjmr-lsd/

Если я правильно понимаю, проблема в том, что вы получаете несколько разных коротких строк для каждой "реальной" линии. Вы можете взять все конечные точки "короткой линии" и приблизиться к строке, которая пересекает с помощью fitLine(): http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=fitline#fitline

Ответ 3

Попробуйте расширить линии от изображения преобразования Hough или исходного изображения контура на 1 пиксель. Вы можете сделать это, вытянув линии больше с толщиной линии 2 или 3 (если вы использовали преобразование hough для получения линий), или вы можете развернуть их вручную, используя этот код.

void dilate_one(cv::Mat& grid){
cv::Size sz = grid.size();
cv::Mat sc_copy = grid.clone();

for(int i = 1; i < sz.height -1; i++){
    for(int j = 1; j < sz.width -1; j++){
        if(grid.at<uchar>(i,j) != 0){
                sc_copy.at<uchar>(i+1,j) = 255;
                sc_copy.at<uchar>(i-1,j) = 255;
                sc_copy.at<uchar>(i,j+1) = 255;
                sc_copy.at<uchar>(i,j-1) = 255;
                sc_copy.at<uchar>(i-1,j-1) = 255;
                sc_copy.at<uchar>(i+1,j+1) = 255;
                sc_copy.at<uchar>(i-1,j+1) = 255;
                sc_copy.at<uchar>(i+1,j-1) = 255;
        }
    }
}
grid = sc_copy;
}

После преобразования Hough у вас есть набор векторов, которые представляют ваши строки, сохраненные как cv::Vec4i v

У этого есть конечные точки линии. Самое простое решение - совместить конечные точки каждой линии и найти те, которые ближе всего. Вы можете использовать простые нормы L1 или L2 для расчета расстояния.

p1 = cv::Point2i(v[0],v[1]) и p2 = cv::point2i(v[2],v[3]))

Точки, которые очень близки, должны быть пересечениями. Единственная проблема - это T-пересечения, где не может быть конечной точки, но это не кажется проблемой в вашем изображении.

Ответ 4

Я просто бросаю идею здесь, но вы можете попытаться начать с порога оригинального изображения (что может привести к интересным результатам, так как ваши рисунки находятся на белой бумаге). Затем, выполняя сегментирование области, растущую на двоичном изображении, вы, вероятно, окажетесь в комнатах, сегментированных друг от друга и от фона (критерием для определения номеров и фона может быть сходство области). Из этого вы сможете построить различные модели, как того требует ваша проблема: например, относительное расположение комнат, площади или даже композиции (т.е. Весь план этажа содержит большие комнаты, в которых есть более мелкие и т.д.).