Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

How to merge nearby rectangles

I am working on character segmentation and looking to merge nearby characters into a box. I have successfully found the contours but I am not sure how to find a straight line between the top and bottom points.

def findContours(self, image):
    contour_img = image.copy()
    vis = image.copy()
    vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)
    _, contours, hierarchy = cv2.findContours(contour_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    contoursBBS = []
    for contour in contours:
        [x, y, w, h] = cv2.boundingRect(contour)

        if w > 100 or h < 8:
            continue

        contoursBBS.append([x, y, w, h, w*h])
    contoursBBS = np.array(contoursBBS)

    # reject outliers based on width, height, and area
    rejectH = self.rejectOutliers(contoursBBS, 3, m=4)
    rejectW = self.rejectOutliers(rejectH, 2, m=4)
    rejectA = self.rejectOutliers(rejectW, 4, m=4)

    contourRects = []
    for c in rejectA:
        [x, y, w, h, a] = c
        if w < 9 or h < 15 or a < 300 or a > 6000:
            continue
        contourRects.append(c)

    for i, rect in enumerate(contourRects):
        [x, y, w, h, a] = rect
        topCenter, bottomCenter = (int((2*x + w)/2), int(y)), (int((2*x + w)/2), int(y+h))

        print("X: {:4d}  Y:  {:4d}  W: {:4d}  H: {:4d}  A: {:4d}".format(x, y, w, h, a))


        cv2.rectangle(vis, (x, y), (x+w, y+h), (0, 255, 0), 2)
        cv2.circle(vis, topCenter, 2, (0, 0, 255), 2)
        cv2.circle(vis, bottomCenter, 2, (0, 0, 255), 2)

Result

image description

What I am hoping to achieve

image description

How to merge nearby rectangles

I am working on character segmentation and looking to merge nearby characters into a box. I have successfully found the contours but I am not sure how to find a straight line between the top and bottom points.

def findContours(self, image):
    contour_img = image.copy()
    vis = image.copy()
    vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)
    _, contours, hierarchy = cv2.findContours(contour_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    contoursBBS = []
    for contour in contours:
        [x, y, w, h] = cv2.boundingRect(contour)

        if w > 100 or h < 8:
            continue

        contoursBBS.append([x, y, w, h, w*h])
    contoursBBS = np.array(contoursBBS)

    # reject outliers based on width, height, and area
    rejectH = self.rejectOutliers(contoursBBS, 3, m=4)
    rejectW = self.rejectOutliers(rejectH, 2, m=4)
    rejectA = self.rejectOutliers(rejectW, 4, m=4)

    contourRects = []
    for c in rejectA:
        [x, y, w, h, a] = c
        if w < 9 or h < 15 or a < 300 or a > 6000:
            continue
        contourRects.append(c)

    for i, rect in enumerate(contourRects):
        [x, y, w, h, a] = rect
        topCenter, bottomCenter = (int((2*x + w)/2), int(y)), (int((2*x + w)/2), int(y+h))

        print("X: {:4d}  Y:  {:4d}  W: {:4d}  H: {:4d}  A: {:4d}".format(x, y, w, h, a))


        cv2.rectangle(vis, (x, y), (x+w, y+h), (0, 255, 0), 2)
        cv2.circle(vis, topCenter, 2, (0, 0, 255), 2)
        cv2.circle(vis, bottomCenter, 2, (0, 0, 255), 2)

Result

image description

What I am hoping to achieve

image description

Some test images (requested by @supra56)

  1. https://ibb.co/bgtyypp
  2. https://ibb.co/XtdHgWg
  3. https://ibb.co/5R4QVTR
  4. https://ibb.co/gD8KymR (very challenging)
  5. https://ibb.co/k5YDT1Q