如何连接图像中不相交的线条或边缘?

问题描述 投票:0回答:1

我目前正在研究从二进制图像中提取线条。我最初执行了一些图像处理步骤,包括阈值分割,并获得了以下二值图像。

从二值图像中可以看出,线条被分割或断开。我想加入虚线,如下图所示,用红色标记。我手动标记了红线以进行演示。

仅供参考,我使用以下代码来执行预处理。

img = cv2.imread('original_image.jpg')  # loading image 
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # coverting to gray scale
median_filter = cv2.medianBlur (gray_image, ksize = 5) # median filtering 

th, thresh = cv2.threshold (median_filter, median_filter.mean(), 255, cv2.THRESH_BINARY) # theshold segmentation

# small dots and noise removing 
nlabels, labels, stats, centroids = cv2.connectedComponentsWithStats(thresh, None, None, None, 8, cv2.CV_32S)
areas = stats[1:,cv2.CC_STAT_AREA]
result = np.zeros((labels.shape), np.uint8)
min_size = 150 
for i in range(0, nlabels - 1):
    if areas[i] >= min_size:   #keep
        result[labels == i + 1] = 255

fig, ax = plt.subplots(2,1, figsize=(30,20))
ax[0].imshow(img)
ax[0].set_title('Original image')

ax[1].imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
ax[1].set_title('preprocessed image')

如果您对如何连接线路有任何建议或步骤,我将不胜感激?谢谢你

opencv image-processing line edge-detection binary-image
1个回答
4
投票

使用以下一系列方法,我能够得到一个粗略的近似值。这是一个非常简单的解决方案,可能不适用于所有情况。

1。形态学运算

要合并相邻线,请对二值图像执行形态(膨胀)操作。

img = cv2.imread('image_path', 0)     # grayscale image
img1 = cv2.imread('image_path', 1)    # color image

th = cv2.threshold(img, 150, 255, cv2.THRESH_BINARY)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (19, 19))
morph = cv2.morphologyEx(th, cv2.MORPH_DILATE, kernel)

2。寻找轮廓和极值点

  1. 我现在的想法是找到轮廓。
  2. 然后找到每个轮廓的极值点。
  3. 最后找到这些相邻轮廓之间的极值点之间的最近距离。并在它们之间画一条线。
cnts1 = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)`

cnts = cnts1[0]     # storing contours in a variable

让我们快速绕道看看这些极值点出现在哪里:

# visualize extreme points for each contour
for c in cnts:
    left = tuple(c[c[:, :, 0].argmin()][0])
    right = tuple(c[c[:, :, 0].argmax()][0])
    top = tuple(c[c[:, :, 1].argmin()][0])
    bottom = tuple(c[c[:, :, 1].argmax()][0])

    # Draw dots onto image
    cv2.circle(img1, left, 8, (0, 50, 255), -1)
    cv2.circle(img1, right, 8, (0, 255, 255), -1)
    cv2.circle(img1, top, 8, (255, 50, 0), -1)
    cv2.circle(img1, bottom, 8, (255, 255, 0), -1)

(注意:极值点是基于形态学运算的轮廓,而是在原始图像上绘制的)

3.查找相邻轮廓之间的最近距离

抱歉,循环很多。

  1. 首先,迭代图像中的每个轮廓(分割线)。
  2. 找到它们的极值点。极值点是指基于其各自边界框的最顶部、最底部、最右侧和最左侧的点。
  3. 将轮廓的每个极值点之间的距离与其他轮廓的极值点之间的距离进行比较。并在距离最小的点之间画一条线。
for i in range(len(cnts)):

    min_dist = max(img.shape[0], img.shape[1])

    cl = []
    
    ci = cnts[i]
    ci_left = tuple(ci[ci[:, :, 0].argmin()][0])
    ci_right = tuple(ci[ci[:, :, 0].argmax()][0])
    ci_top = tuple(ci[ci[:, :, 1].argmin()][0])
    ci_bottom = tuple(ci[ci[:, :, 1].argmax()][0])
    ci_list = [ci_bottom, ci_left, ci_right, ci_top]
    
    for j in range(i + 1, len(cnts)):
        cj = cnts[j]
        cj_left = tuple(cj[cj[:, :, 0].argmin()][0])
        cj_right = tuple(cj[cj[:, :, 0].argmax()][0])
        cj_top = tuple(cj[cj[:, :, 1].argmin()][0])
        cj_bottom = tuple(cj[cj[:, :, 1].argmax()][0])
        cj_list = [cj_bottom, cj_left, cj_right, cj_top]
        
        for pt1 in ci_list:
            for pt2 in cj_list:
                dist = int(np.linalg.norm(np.array(pt1) - np.array(pt2)))     #dist = sqrt( (x2 - x1)**2 + (y2 - y1)**2 )
                if dist < min_dist:
                    min_dist = dist             
                    cl = []
                    cl.append([pt1, pt2, min_dist])
    if len(cl) > 0:
        cv2.line(img1, cl[0][0], cl[0][1], (255, 255, 255), thickness = 5)

4。后期处理

由于最终输出并不完美,可以进行额外的形态学操作,然后将其骨架化。

© www.soinside.com 2019 - 2024. All rights reserved.