Opencv separate overlapping rectangles


This image is the first processed image from a map created with a LiDAR sensor.
If you look closely at the image, there are many bumpy parts that are not exactly straight lines.


I want to make the result like this image.


This is the first map image scanned with LiDAR.

I tried using the hough line, but it’s not perfect.
I would like to figure out a method that can be applied in different situations

Here is my code.

import numpy as np
import math
import cv2

def get_dist(pt1, pt2):
    return math.hypot(pt1[0]-pt2[0], pt1[1]-pt2[1])
def reorderPts(pts):
    idx = np.lexsort((pts[:, 1], pts[:, 0]))
    pts = pts[idx]

    if pts[0, 1] > pts[1, 1]:
        pts[[0, 1]] = pts[[1, 0]]

    if pts[2, 1] < pts[3, 1]:
        pts[[2, 3]] = pts[[3, 2]]

    return pts

def solve(src):
    H, W = src.shape[:2]
    dst = src.copy()

    gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
    _, bin = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
    bin = cv2.erode(bin, np.ones((5, 5)))

    cv2.floodFill(bin, np.zeros((H+2, W+2), np.uint8), (0, 0), 0)
    bin = cv2.medianBlur(bin, 7)

    nonRectArea = bin.copy()
    cv2.floodFill(nonRectArea, np.zeros((H+2, W+2), np.uint8), (W//2, H//2), 0)
    bin[np.where(nonRectArea == 255)] = 0

    contours, _ = cv2.findContours(bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    rect = cv2.minAreaRect(contours[0])
    box = cv2.boxPoints(rect)
    box = np.int0(box)
    cv2.drawContours(dst, [box], 0, (0, 255, 0), 1)

    srcQuad = reorderPts(box.reshape(4, 2).astype(np.float32))
    dw = int(get_dist(srcQuad[0], srcQuad[3])*2)
    dh = int(get_dist(srcQuad[0], srcQuad[1])*2)
    dstQuad = np.array([[0, 0], [0, dh], [dw, dh], [dw, 0]], np.float32)
    pers = cv2.getPerspectiveTransform(srcQuad, dstQuad)
    dst = cv2.warpPerspective(src, pers, (dw, dh))

    gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
    _, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)
    thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, np.ones((25, 25)))

    lines = cv2.HoughLinesP(thresh, 0.8, np.pi/180, 80, minLineLength=30, maxLineGap=100)
    w, h = dst.shape[:2]
    mask = np.zeros((w, h), dtype=np.uint8)
    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv2.line(dst, (x1,y1), (x2, y2), (0,255,0), 3)
        cv2.line(mask, (x1,y1), (x2, y2), 255, 3)

    mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, np.ones((7, 7), dtype=np.uint8))
    thresh = cv2.bitwise_and(thresh,thresh,mask=~mask)
    thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, np.ones((9, 9), dtype=np.uint8))

    cv2.imshow("src", src)
    cv2.imshow("dst", dst)
    cv2.imshow("thresh", thresh)
    cv2.waitKey()

src = cv2.imread('map.png')
solve(src)

This is code result.