如何连接图像中的分离线或边缘?

发布于 2025-01-20 05:34:07 字数 1041 浏览 5 评论 0原文

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

在二进制图像中,线被拆分或折断。我想加入损坏的线路。

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

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')

如果您对如何连接线路有任何建议或步骤,我真的很感激?谢谢

I am currently working on lines extraction from a binary image. I initially performed a few image processing steps including threshold segmentation and obtained the following binary image.

In the binary image the lines are splitted or broken. And I wanted to join the broken line.

FYI, I used the following code to perform the preprocessing.

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')

I would really appreciate it if you have any suggestions or steps on how to connect the lines? Thank you

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

耳根太软 2025-01-27 05:34:07

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

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.后处理

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

Using the following sequence of methods I was able to get a rough approximation. It is a very simple solution and might not work for all cases.

1. Morphological operations

To merge neighboring lines perform morphological (dilation) operations on the binary image.

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)

enter image description here

2. Finding contours and extreme points

  1. My idea now is to find contours.
  2. Then find the extreme points of each contour.
  3. Finally find the closest distance among these extreme points between neighboring contours. And draw a line between them.
cnts1 = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)`

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

Lets take a quick detour to visualize where these extreme points are present:

# 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)

(Note: The extreme points points are based of contours from morphological operations, but drawn on the original image)

enter image description here

3. Finding closest distances between neighboring contours

Sorry for the many loops.

  1. First, iterate through every contour (split line) in the image.
  2. Find the extreme points for them. Extreme points mean top-most, bottom-most, right-most and left-most points based on its respective bounding box.
  3. Compare the distance between every extreme point of a contour with those of every other contour. And draw a line between points with the least distance.
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)

enter image description here

4. Post-processing

Since the final output is not perfect, you can perform additional morphology operations and then skeletonize it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文