Opencv: преобразование изображения плана этажа в модель данных
мой план состоит в том, чтобы извлечь информацию из поэтажного плана, вычерченного на бумаге. Мне уже удалось обнаружить 70-80% нарисованных дверей:
теперь я хочу создать модель данных со стен. Мне уже удалось извлечь их, как вы можете видеть здесь:
Из этого я создал контуры:
Теперь моя идея состояла в том, чтобы получить пересечения линий из этого изображения и создать модель данных из этого. Однако, если я использую алгоритм houghlines я получаю что-то вроде этого:
У кого-то есть другое представление о том, как получить пересечения или даже другое представление о том, как получить модель? Было бы очень мило.
PS: я использую javacv. Но алгоритм в opencv также будет в порядке, поскольку я мог бы перевести это.
4 ответов
более того, хотя похоже, что ваши "стеновые" данные довольно шумные (т. е. есть много небольших разделов, которые можно спутать для крошечных комнат), но ваши "комнатные" данные нет (в середине комнат не так много фантомных стен).
поэтому может быть полезно обнаружить комнаты (приблизительно выровненные по оси прямоугольники, которые не содержат белые пиксели над определенным порогом) и экстраполируют стены, глядя на границу между соседними пикселями.
Я бы реализовал это в три этапа: во-первых, попробуйте обнаружить несколько принципиальных осей от выхода houghlines (я бы сначала достиг алгоритма кластеризации K-средних, а затем массировать выход, чтобы получить перпендикулярную ось). Используйте эти данные для лучшего выравнивания изображения.
во-вторых, начните заполнять небольшие прямоугольники случайным образом вокруг изображения, черным цветом области. "Растите" эти прямоугольники во всех направлениях, пока каждая сторона не попадет в белый пиксель над определенным порогом или они не столкнутся с другим прямоугольником. Продолжайте посев до тех пор, пока не будет покрыт большой процент площади изображения.
В-третьих, найдите области (также прямоугольники, надеюсь), не покрытые прямоугольниками, и сверните их в строки:
- относитесь к координатам прямоугольников на оси x&y независимо-как к набору интервалов
- сортировка эти координаты и искать смежные координаты, которые образуют верхнюю границу одного прямоугольника и нижнюю границу другого.
- наивно попробуйте соединить эти промежутки, найденные вдоль каждой оси, и проверить полученные прямоугольники-кандидаты на пересечение с комнатами. Отбросить пересекающиеся прямоугольники.
- сверните эти новые прямоугольники в линии вдоль их основной оси.
- точки На концах линий могут быть соединены, когда в некоторых минимальное расстояние (путем расширения линий до их встречи).
в этом подходе есть несколько недостатков:
- он не будет работать с не-оси выровнены стены. К счастью, вы, вероятно, хотите, чтобы они автоматически выравнивались большую часть времени.
- вероятно, он будет рассматривать небольшие дверные проемы в стенах как часть стены-случайный зазор в чертеже. Они должны быть обнаружены отдельно и добавлены обратно в реконструированный рисунок.
- это не будет иметь дело с шумными данными - но похоже, что вы уже проделали замечательную работу по де-шумизации данных с opencv уже!
Я прошу прощения за то, что не включаю фрагменты кода, но я подумал, что важнее передать идею, а не детали (прокомментируйте, если вы хотите, чтобы я расширил любой из них). Также обратите внимание, что, хотя я играл с opencv несколько лет назад, я ни в коем случае не эксперт - так что это может быть уже пусть какие-нибудь примитивы сделают это за тебя.
во-первых, вы также можете использовать детектор сегмента линии для обнаружения линий: 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
попробуйте расширить линии из изображения преобразования Хоу или исходного контурного изображения на 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 пересечений, где может не быть конечной точки, но это не кажется проблемой в вашем образе.
Я просто бросаю идею здесь, но вы можете попытаться начать с порога исходного изображения (что может привести к интересным результатам, так как ваши рисунки на белой бумаге). Затем, выполняя сегментацию растущей области на двоичном изображении, вы, вероятно, получите сегментированные комнаты друг от друга и от фона (критерием для идентификации комнат и фона может быть сходство области). Из этого вы сможете создавать различные модели, как того требует ваш проблема: например, относительное расположение комнат, площадь или даже состав (т. е. весь план этажа содержит большие комнаты, которые содержат меньшие и так далее).