找到部分闭合的精巧边缘的中间

Find middle of partially closed canny edges

我有如下(低分辨率)图像:

(原图 1)

最终目标是为图像中的每条线定义线段坐标:

我试过的策略是扩张 -> 找到轮廓 -> 模糊 -> 侵蚀 -> canny 边缘检测:

import numpy as np
import cv2
from skimage.feature import canny

image = cv2.imread('image.png')

kernel = np.ones((1,1),np.uint8)
dilated_img = cv2.dilate(gray, kernel, iterations = 1)
canvas = cv2.cvtColor(dilated_img, cv2.COLOR_GRAY2RGB)
contours, hierarchy = cv2.findContours(dilated_img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)

for i,cont in enumerate(contours):                                                                                                                                                                                                                                              
    if ( hierarchy[0][i][3] != -1 ):                                                                                                                                                                                                                                            
        cv2.fillPoly(canvas, pts =[cont], color=(0, 180, 0))                                                                                                                                                                                       
    else:                                                                                                                                                                                                                                                                       
        cv2.drawContours(canvas, cont, -1, (255, 0, 0), 1) 

canvas = cv2.GaussianBlur(canvas,(1, 1),39)
edges = canny(image, 3, 1, 25)

输出 (edges) 看起来像下图,除了绿色,我添加绿色是为了表示我希望通过此策略实现的目标:如果我能找到管子的中间(绿色),然后我可以从中构建线段。也许这是实现目标的一种不必要的复杂方式...

边缘出来的大多是这些管状结构,可以完全封闭也可以不封闭。

图像中的绿线表示我想要找到的东西——基本上只是管子的大约中间。

我尝试对 edge 对象做的是逐行(和逐列)逐个像素地根据白色和黑色像素的方式找到管的中间出现,但结果很乱,并且在许多管方向上效果不佳。

(图像1边缘,颜色反转)

所以假设这个策略对于实现上述目标是可行的,我怎样才能找到管子的中点?如果攻略不好,怎么办?

谢谢!

希望这个方法对你有所帮助

你的绿线是阈值图像的骨架图像。查看 here 了解更多关于骨架图像的信息。

import cv2
import numpy as np
from skimage.morphology import skeletonize


def read_image(image_path):
    image = cv2.imread(image_path)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    _, thresh = cv2.threshold(image, 200, 255, cv2.THRESH_BINARY_INV)
    return thresh


def get_skeleton_iamge(threshold_image):
    skeleton = skeletonize(threshold_image / 255)
    skeleton = skeleton.astype(np.uint8)
    skeleton *= 255
    return skeleton


if __name__ == "__main__":
    threshold_image = read_image("image.png")
    cv2.imshow("threshold_image", threshold_image)

    skeleton_iamge = get_skeleton_iamge(threshold_image)
    cv2.imshow("skeleton_iamge", skeleton_iamge)

    canny_edges = cv2.Canny(threshold_image, 100, 200)
    cv2.imshow("canny_edges", canny_edges)

    # for displaying image only
    colour_skeleton_iamge = cv2.cvtColor(skeleton_iamge, cv2.COLOR_GRAY2BGR)
    colour_canny_edges = cv2.cvtColor(canny_edges, cv2.COLOR_GRAY2BGR)
    colour_skeleton_iamge[skeleton_iamge == 255] = [0, 255, 0]
    combined_image = cv2.scaleAdd(colour_skeleton_iamge, 0.5, colour_canny_edges, 0.5)
    cv2.imshow("combined_image", combined_image)

    cv2.waitKey(0)
    cv2.destroyAllWindows()

输出:

image threshold_image skeleton_iamge canny_edges combined_image