【问题标题】:How to identify the shape of a floorplan?如何识别平面图的形状?
【发布时间】:2020-01-20 04:28:34
【问题描述】:

我正在尝试使用平面图来区分两种不同风格的房屋。我对cv2 很陌生,所以我在这里有点挣扎。我可以使用下面的代码使用轮廓识别房屋的外部,该代码来自另一个 Stack Overflow 响应。

import cv2
import numpy as np


def find_rooms(img, noise_removal_threshold=25, corners_threshold=0.1,
               room_closing_max_length=100, gap_in_wall_threshold=500):
    assert 0 <= corners_threshold <= 1
    # Remove noise left from door removal

    img[img < 128] = 0
    img[img > 128] = 255
    contours, _ = cv2.findContours(~img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    mask = np.zeros_like(img)
    for contour in contours:
        area = cv2.contourArea(contour)
        if area > noise_removal_threshold:
            cv2.fillPoly(mask, [contour], 255)

    img = ~mask

    # Detect corners (you can play with the parameters here)
    dst = cv2.cornerHarris(img ,2,3,0.04)
    dst = cv2.dilate(dst,None)
    corners = dst > corners_threshold * dst.max()

    # Draw lines to close the rooms off by adding a line between corners on the same x or y coordinate
    # This gets some false positives.
    # You could try to disallow drawing through other existing lines for example.
    for y,row in enumerate(corners):
        x_same_y = np.argwhere(row)
        for x1, x2 in zip(x_same_y[:-1], x_same_y[1:]):

            if x2[0] - x1[0] < room_closing_max_length:
                color = 0
                cv2.line(img, (x1, y), (x2, y), color, 1)

    for x,col in enumerate(corners.T):
        y_same_x = np.argwhere(col)
        for y1, y2 in zip(y_same_x[:-1], y_same_x[1:]):
            if y2[0] - y1[0] < room_closing_max_length:
                color = 0
                cv2.line(img, (x, y1), (x, y2), color, 1)


    # Mark the outside of the house as black
    contours, _ = cv2.findContours(~img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    contour_sizes = [(cv2.contourArea(contour), contour) for contour in contours]
    biggest_contour = max(contour_sizes, key=lambda x: x[0])[1]
    mask = np.zeros_like(mask)
    cv2.fillPoly(mask, [biggest_contour], 255)
    img[mask == 0] = 0


    return biggest_contour, mask



#Read gray image

img = cv2.imread("/content/51626-7-floorplan-2.jpg", cv2.IMREAD_GRAYSCALE)
ext_contour, mask = find_rooms(img.copy())
cv2_imshow(mask)
print('exterior')
epsilon = 0.01*cv2.arcLength(ext_contour,True)
approx = cv2.approxPolyDP(ext_contour,epsilon,True)
final = cv2.drawContours(img, [approx], -1, (0, 255, 0), 2)
cv2_imshow(final)

这些平面图将只有两种形状中的一种,即 6 面形状和 4 面形状。以下是两种样式:

我需要忽略任何凸窗或小突起。

我相信下一步是只为主墙创建一个轮廓,使该轮廓平滑,然后计算阵列中的边缘。我不知道如何做到这一点。任何帮助将不胜感激!

【问题讨论】:

标签: python opencv image-processing shapes opencv-contour


【解决方案1】:
  • 简单的轮廓查找不太可能为您提供可靠的解决方案。 但是,您当前的方法可以通过首先计算白色背景的蒙版来改进。 使用此蒙版的形状,您可以确定布局。

    lower_color_bounds = cv.Scalar(255, 255, 255) upper_color_bounds = cv.Scalar(220, 220, 220)

    mask = cv2.inRange(frame,lower_color_bounds,upper_color_bounds ) mask_rgb = cv2.cvtColor(mask,cv2.COLOR_GRAY2BGR)

【讨论】:

    【解决方案2】:

    如果您真的只需要决定,无论是四面还是六面的房子,您都可以简单地执行以下操作:灰度图像和反二进制阈值一切,这不是近乎白色的。然后,只需计算该掩码与总像素数之间的比率。四面房屋的该比率必须大于六面房屋的比率。确切的截止值取决于您的数据。对于给定的两个示例,可以将截止设置为0.9

    这里有一些代码:

    import cv2
    from skimage import io      # Only needed for web grabbing images
    
    
    def house_analysis(image):
    
        # Grayscale image
        mask = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
        # Inverse binary threshold everything, which is not nearly white
        mask = cv2.threshold(mask, 248, 255, cv2.THRESH_BINARY_INV)[1]
    
        # Calculate ratio between mask and total number of pixels
        ratio = cv2.countNonZero(mask) / (mask.shape[0] * mask.shape[1])
        print(ratio)
    
        # Decide with respect to cut-off, if house is four or six sided
        cutoff = 0.9
        if ratio > cutoff:
            print('Four sided house')
        else:
            print('Six sided house')
    
        cv2.imshow('image', image)
        cv2.imshow('mask', mask)
        cv2.waitKey(0)
    
    
    house_4 = cv2.cvtColor(io.imread('https://i.stack.imgur.com/vqzZB.jpg'), cv2.COLOR_RGB2BGR)
    house_6 = cv2.cvtColor(io.imread('https://i.stack.imgur.com/ZpkQW.jpg'), cv2.COLOR_RGB2BGR)
    
    house_analysis(house_4)
    house_analysis(house_6)
    
    cv2.destroyAllWindows()
    

    print 输出:

    0.9533036597428289
    Four sided house
    0.789531416400426
    Six sided house
    

    如果主墙周围有较大的空白区域,可以裁剪该部分以获得更可靠的比率。

    希望有帮助!

    ----------------------------------------
    System information
    ----------------------------------------
    Platform:  Windows-10-10.0.16299-SP0
    Python:    3.8.1
    OpenCV:    4.1.2
    ----------------------------------------
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-25
      • 1970-01-01
      • 2014-10-30
      • 1970-01-01
      • 2022-12-01
      • 1970-01-01
      • 2015-12-15
      相关资源
      最近更新 更多