'How to connect broken lines that cannot be connected by erosion and dilation?

I have an image like this that has multiple stoppers and some of the lines are broken. To connect this broken line, I used a morphological operation like this:

import cv2
import numpy as np

img = cv2.imread('sample.png', cv2.IMREAD_GRAYSCALE)
morph = cv2.morphologyEx(im, cv2.MORPH_CLOSE, np.ones((10,10),np.uint8))

But this didn't connect my broken lines. How can I connect the lines without affecting the other lines?

img

A line break is a break between two small lines in the center of the image. Only the discontinuous part does not have rounded ends.

image

applied morphological operation

applied morphological operation



Solution 1:[1]

    1. You can use createFastLineDetector for detecting each line.

    1. Calculate the slope of the current and neighboring lines.

    1. If the slope of current and neighboring lines are the same draw line.

Initializing Line Detector


We will be using ximgproc library for detecting lines.

import cv2

img = cv2.imread("lines.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
d = cv2.ximgproc.createFastLineDetector()
lines = d.detect(gray)
  • The lines variable returns similar values like [[14.82, 78.90, 90.89, 120.78]] where x1=14.82, y1=78.90, x2=90.89, y2=120.78 respectively.

Calculating Slope


  • The slope of a line is calculated with the formula: m = (y2 - y1) / (x2 - x1)

  • For a given line object, get the coordinates and return the slope.

  • def calculate_slope(line_object):
        x_point1 = line_object[0]
        y_point1 = line_object[1]
        x_point2 = line_object[2]
        y_point2 = line_object[3]
    
        m = abs((y_point2 - y_point1) / (x_point2 - x_point1))
        m = float("{:.2f}".format(m))
        return m
    

Comparing Slopes


    1. Check the equality of the lines. if the points are equal, that means they are the same line.
    • for current_line in lines:
           current_slope = calculate_slope(current_line[0])
      
           for neighbor_line in lines:
               current_x1 = int(current_line[0][0])
               current_y1 = int(current_line[0][1])
               current_x2 = int(current_line[0][2])
               current_y2 = int(current_line[0][3])
      
               compare_lines = current_line == neighbor_line[0]
               equal_arrays = compare_lines.all()
      
    1. If the lines are not equal, calculate the neighbor's line slope.
      if not equal_arrays:
          neighbor_slope = calculate_slope(neighbor_line[0])
      
    1. If slopes are equal, draw the line. From neighbor to current and current to neighbor.
      if abs(current_slope - neighbor_slope) < 1e-3:
          neighbor_x1 = int(neighbor_line[0][0])
          neighbor_y1 = int(neighbor_line[0][1])
          neighbor_x2 = int(neighbor_line[0][2])
          neighbor_y2 = int(neighbor_line[0][3])
      
          cv2.line(img,
                   pt1=(neighbor_x1, neighbor_y1),
                   pt2=(current_x2, current_y2),
                   color=(255, 255, 255),
                   thickness=3)
          cv2.line(img,
                   pt1=(current_x1, current_y1),
                   pt2=(neighbor_x2, neighbor_y2),
                   color=(255, 255, 255),
                   thickness=3)
      

Result


enter image description here

Possible Question But why couldn't you connect the following parts?

enter image description here

Answer

Well, the red dotted line slopes are not equal. Therefore I couldn't connect them.

Possible Question Why didn't you use dilate and erode methods? as shown in here

Answer

I tried, but the result is not satisfactory.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1