代码之家  ›  专栏  ›  技术社区  ›  Richard

消除末端未连接的线条

  •  1
  • Richard  · 技术社区  · 6 年前

    我有以下骨架:

    从这张图中,我想消除不属于循环的线条。

    我把这想象成一个过程,在这个过程中,线的两端被发现(用红点标记),线被吞噬,直到有一个点在那里分支(用蓝点标记)。

    我在opencv或scikit image中没有找到此操作。

    这种转换有名字吗?有没有一种方法可以在Python中实现它,从而有效地工作?

    我还上传了图像 here in case the above image does't load correctly.

    从这张图中,我想消除不属于循环的线。

    我把这想象成一个过程,在这个过程中,线条的末端被发现(用红点标记),而线条被吞噬,直到有一个分支点(用蓝点标记)。

    我在OpenCV或SciKit图像中没有找到此操作。

    这种转换有名字吗?有没有一种方法可以在Python中实现它,从而有效地工作?

    我也上传了图片 here 如果上面的图像加载不正确。

    2 回复  |  直到 6 年前
        1
  •  2
  •   Richard    6 年前

    在矩阵大小上扫描以识别种子细胞的时间(那些在融合开始时的细胞),然后 o(n) 时间在保险丝的总长度上,以消除相关线路。

    熔丝变换算法

    %%cython -a --cplus
    import numpy as np
    import cv2
    import skimage.morphology as skm
    import cython
    from libcpp.queue cimport queue
    cimport numpy as np
    
    @cython.boundscheck(False)
    @cython.wraparound(False)
    @cython.nonecheck(False)
    @cython.cdivision(True) 
    #Richard's Fuse Transform
    #https://stackoverflow.com/a/51738867/752843
    cpdef void FuseTransform(unsigned char [:, :] image):
        # set the variable extension types
        cdef int c, x, y, nx, ny, width, height, neighbours
        cdef queue[int] q
    
        # grab the image dimensions
        height = image.shape[0]
        width  = image.shape[1]
    
        cdef int dx[8]
        cdef int dy[8]
    
        #Offsets to neighbouring cells
        dx[:] = [-1,-1,0,1,1,1,0,-1]
        dy[:] = [0,-1,-1,-1,0,1,1,1]
    
        #Find seed cells: those with only one neighbour
        for y in range(1, height-1):
            for x in range(1, width-1):
                if image[y,x]==0: #Seed cells cannot be blank cells
                    continue
                neighbours = 0
                for n in range(0,8):   #Looks at all neighbours
                    nx = x+dx[n]
                    ny = y+dy[n]
                    if image[ny,nx]>0: #This neighbour has a value
                        neighbours += 1
                if neighbours==1:      #Was there only one neighbour?
                    q.push(y*width+x)  #If so, this is a seed cell
    
        #Starting with the seed cells, gobble up the lines
        while not q.empty():
            c = q.front()
            q.pop()
            y = c//width         #Convert flat index into 2D x-y index
            x = c%width
            image[y,x] = 0       #Gobble up this part of the fuse
            neighbour  = -1      #No neighbours yet
            for n in range(0,8): #Look at all neighbours
                nx = x+dx[n]     #Find coordinates of neighbour cells
                ny = y+dy[n]
                #If the neighbour would be off the side of the matrix, ignore it
                if nx<0 or ny<0 or nx==width or ny==height:
                    continue
                if image[ny,nx]>0:      #Is the neighbouring cell active?
                    if neighbour!=-1:   #If we've already found an active neighbour
                        neighbour=-1    #Then pretend we found no neighbours
                        break           #And stop looking. This is the end of the fuse.
                    else:               #Otherwise, make a note of the neighbour's index.
                        neighbour = ny*width+nx
            if neighbour!=-1:           #If there was only one neighbour
                q.push(neighbour)       #Continue burning the fuse
    
    #Read in image
    img         = cv2.imread('part.jpg')
    ShowImage('Original',img,'bgr')
    
    #Convert image to grayscale
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    
    #Apply Otsu's method to eliminate pixels of intermediate colour
    ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_OTSU)
    
    #Apply the Fuse Transform
    skh_dilated = skelhuman.copy()
    FuseTransform(skh_dilated)
    

    输入

    Skeleton

    结果

    Fuse Transform

        2
  •  1
  •   dhanushka    6 年前

    在下面的算法中,首先我将图像像素标准化为值0和1。然后,我通过应用3x3非标准化框过滤器来检查非零像素的8个连接邻居。如果我们将输入图像的过滤器输出乘以(像素),我们得到所有的非零像素,这次,它们的值告诉我们它们有多少8个连接的邻居加上1。因此,在这里,中心像素将自身视为其邻居。

    红色是中心像素。黄色是它的8连接邻居。

    8-neighbors

    Richard

    import cv2
    import numpy as np
    
    im = cv2.imread('USqDW.png', 0)
    
    # set max pixel value to 1
    s = np.uint8(im > 0)
    
    count = 0
    i = 0
    while count != np.sum(s):
        # non-zero pixel count
        count = np.sum(s)
        # examine 3x3 neighborhood of each pixel
        filt = cv2.boxFilter(s, -1, (3, 3), normalize=False)
        # if the center pixel of 3x3 neighborhood is zero, we are not interested in it
        s = s*filt
        # now we have pixels where the center pixel of 3x3 neighborhood is non-zero
        # if a pixels' 8-connectivity is less than 2 we can remove it
        # threshold is 3 here because the boxfilter also counted the center pixel
        s[s < 3] = 0
        # set max pixel value to 1
        s[s > 0] = 1
        i = i + 1
    

    prune