Мой план состоит в том, чтобы извлечь информацию из плана этажа, нарисованного на бумаге. Мне уже удалось обнаружить 70-80% нарисованных дверей:
Теперь я хочу создать модель данных из стен. Мне уже удалось извлечь их, как вы можете видеть здесь:
Из этого я создал контуры:
Моя идея теперь состояла в том, чтобы получить пересечения линий из этого изображения и создать модель данных из этого. Однако, если я использую алгоритм houghlines, я получаю что-то вроде этого:
Есть ли у кого-то другое представление о том, как получить пересечения, или даже другое, как получить модель? Было бы очень приятно.
PS: я использую javacv. Но алгоритм в opencv также был бы в порядке, поскольку я мог бы перевести это.
Мне кажется, что вы действительно хотите не обязательно стены, а комнаты, которые случайно ограничены стенами.
Более того, несмотря на то, что ваши «настенные» данные выглядят довольно шумно (т. Е. Есть много маленьких секций, которые можно перепутать для крошечных комнат), но ваши «комнатные» данные — нет (в фантомных стенах не так много середина комнаты).
Следовательно, может быть полезно обнаружить комнаты (приблизительно выровненные по оси прямоугольники, которые не содержат белых пикселей выше определенного порога) и экстраполировать стены, глядя на границу между соседними пикселями.
Я бы реализовал это в три этапа: во-первых, попытаться определить несколько принципиальных осей по выходным линиям (сначала я достигну алгоритма кластеризации K-средних, а затем массирую выходные данные, чтобы получить перпендикулярную ось). Используйте эти данные, чтобы лучше выровнять изображение.
Во-вторых, начните беспорядочно высевать маленькие прямоугольники вокруг изображения в черных областях. «Расти» эти прямоугольники во всех направлениях, пока каждая сторона не достигнет белого пикселя через определенный порог, или они не столкнутся с другим прямоугольником. Продолжайте посев, пока большой процент площади изображения не будет покрыт.
В-третьих, найдите области (также, возможно, прямоугольники), не покрытые прямоугольниками, и сложите их в линии:
У этого подхода есть несколько недостатков:
Я прошу прощения за то, что не включил какие-либо фрагменты кода — но я подумал, что важнее передать идею, а не детали (пожалуйста, прокомментируйте, если вы хотите, чтобы я расширил какой-либо из них). Также обратите внимание, что хотя я играл с 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 (если вы использовали грубое преобразование, чтобы получить линии), или вы можете расширить их вручную, используя этот код.
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;
}
После преобразования Хафа у вас есть набор векторов, которые представляют ваши строки, сохраненные как cv::Vec4i v
Это имеет конечные точки линии. Самым простым решением было бы сопоставить конечные точки каждой линии и найти те, которые ближе всего. Вы можете использовать простые нормы L1 или L2 для расчета расстояния.
p1 = cv::Point2i(v[0],v[1])
а также p2 = cv::point2i(v[2],v[3]))
Точки, которые находятся очень близко, должны быть пересечениями. Единственная проблема — это Т-образные пересечения, где не может быть конечной точки, но это не является проблемой в вашем изображении.
Я просто привожу здесь идею, но вы можете попытаться начать с установки порога исходного изображения (что может привести к интересным результатам, поскольку ваши рисунки на белой бумаге). Затем, выполняя сегментацию растущего региона на бинарном изображении, вы, вероятно, в конечном итоге получите комнаты, сегментированные друг от друга и от фона (критерием для определения комнат и фона может быть сходство областей). Исходя из этого, вы сможете строить различные модели в соответствии с вашей задачей: например, относительное расположение комнат, площадь или даже композицию (то есть весь план этажа содержит большие комнаты, в которых есть более мелкие и т. Д.).