在python opencv中查找镂空图像的交叉点

时间:2017-01-17 19:29:35

标签: python opencv image-processing opencv-contour line-intersection

我有一个镂空图像(如下所示)。

Skeleton Image

我想得到这些线的交叉点。我在下面尝试了以下方法,skeleton是一个openCV图像,算法返回一个坐标列表:

def getSkeletonIntersection(skeleton):
    image = skeleton.copy();
    image = image/255;
    intersections = list();
    for y in range(1,len(image)-1):
        for x in range(1,len(image[y])-1):
            if image[y][x] == 1:
                neighbourCount = 0;
                neighbours = neighbourCoords(x,y);
                for n in neighbours:
                    if (image[n[1]][n[0]] == 1):
                        neighbourCount += 1;
                if(neighbourCount > 2):
                    print(neighbourCount,x,y);
                    intersections.append((x,y));
    return intersections;

它找到有两个以上相邻像素的白色像素的坐标。我认为这只会返回角落,但事实并非如此 - 它会返回更多的点数。

Skeleton with marked coordinates

这是输出,其检测到的点在图像上标记。这是因为它检测到下面显示的一些不是交叉点的例子。

0 0 0    1 1 0    0 1 1
1 1 1    0 1 0    1 1 0
0 0 1    0 0 1    0 0 0

还有更多例子。我应该考虑另一种方法来检测交叉点。感谢所有的意见和想法。

4 个答案:

答案 0 :(得分:3)

我不确定 OpenCV 功能,但您应该尝试使用 Hit and Miss 形态,这些描述为here

阅读 Line Junctions 并查看您需要测试的12个模板:

enter image description here

答案 1 :(得分:2)

我最近收到了一封电子邮件,要求我最终解决问题。它发布在下面,以便通知其他人。我没有声称这段代码特别快或稳定 - 只是它对我有用!该功能还包括过滤一起检测到的重复项和交叉点,表明它们不是真正的交叉点,而是引入了骨架化过程中的噪声。

def neighbours(x,y,image):
    """Return 8-neighbours of image point P1(x,y), in a clockwise order"""
    img = image
    x_1, y_1, x1, y1 = x-1, y-1, x+1, y+1;
    return [ img[x_1][y], img[x_1][y1], img[x][y1], img[x1][y1], img[x1][y], img[x1][y_1], img[x][y_1], img[x_1][y_1] ]   


def getSkeletonIntersection(skeleton):
    """ Given a skeletonised image, it will give the coordinates of the intersections of the skeleton.

    Keyword arguments:
    skeleton -- the skeletonised image to detect the intersections of

    Returns: 
    List of 2-tuples (x,y) containing the intersection coordinates
    """
    # A biiiiiig list of valid intersections             2 3 4
    # These are in the format shown to the right         1 C 5
    #                                                    8 7 6 
    validIntersection = [[0,1,0,1,0,0,1,0],[0,0,1,0,1,0,0,1],[1,0,0,1,0,1,0,0],
                         [0,1,0,0,1,0,1,0],[0,0,1,0,0,1,0,1],[1,0,0,1,0,0,1,0],
                         [0,1,0,0,1,0,0,1],[1,0,1,0,0,1,0,0],[0,1,0,0,0,1,0,1],
                         [0,1,0,1,0,0,0,1],[0,1,0,1,0,1,0,0],[0,0,0,1,0,1,0,1],
                         [1,0,1,0,0,0,1,0],[1,0,1,0,1,0,0,0],[0,0,1,0,1,0,1,0],
                         [1,0,0,0,1,0,1,0],[1,0,0,1,1,1,0,0],[0,0,1,0,0,1,1,1],
                         [1,1,0,0,1,0,0,1],[0,1,1,1,0,0,1,0],[1,0,1,1,0,0,1,0],
                         [1,0,1,0,0,1,1,0],[1,0,1,1,0,1,1,0],[0,1,1,0,1,0,1,1],
                         [1,1,0,1,1,0,1,0],[1,1,0,0,1,0,1,0],[0,1,1,0,1,0,1,0],
                         [0,0,1,0,1,0,1,1],[1,0,0,1,1,0,1,0],[1,0,1,0,1,1,0,1],
                         [1,0,1,0,1,1,0,0],[1,0,1,0,1,0,0,1],[0,1,0,0,1,0,1,1],
                         [0,1,1,0,1,0,0,1],[1,1,0,1,0,0,1,0],[0,1,0,1,1,0,1,0],
                         [0,0,1,0,1,1,0,1],[1,0,1,0,0,1,0,1],[1,0,0,1,0,1,1,0],
                         [1,0,1,1,0,1,0,0]];
    image = skeleton.copy();
    image = image/255;
    intersections = list();
    for x in range(1,len(image)-1):
        for y in range(1,len(image[x])-1):
            # If we have a white pixel
            if image[x][y] == 1:
                neighbours = neighbours(x,y,image);
                valid = True;
                if neighbours in validIntersection:
                    intersections.append((y,x));
    # Filter intersections to make sure we don't count them twice or ones that are very close together
    for point1 in intersections:
        for point2 in intersections:
            if (((point1[0] - point2[0])**2 + (point1[1] - point2[1])**2) < 10**2) and (point1 != point2):
                intersections.remove(point2);
    # Remove duplicates
    intersections = list(set(intersections));
    return intersections;

这也适用于github here

答案 2 :(得分:1)

如果对于给定像素,而不是计算总共8个邻居(=具有连接8的邻居)的数量,则可以帮助计算8个邻居的数量,这些邻居不是4个邻居彼此

所以在你的误报的例子中

0 0 0    1 1 0    0 1 1
1 1 1    0 1 0    1 1 0
0 0 1    0 0 1    0 0 0

对于每种情况,您有3个邻居,但每次,其中2个是4连接。 (标记为&#34; 2&#34;在下一个片段中的像素)

0 0 0    2 2 0    0 2 2
1 1 2    0 1 0    1 1 0
0 0 2    0 0 1    0 0 0

如果您只考虑其中一个用于计算(而不是现在代码中的两个),那么您确实只有2个新定义的&#34;邻居&#34;并且考虑的点不被视为交叉点。 其他&#34;真正的十字路口&#34;仍然会保留,如下所示

0 1 0    0 1 0    0 1 0
1 1 1    0 1 0    1 1 0
0 0 0    1 0 1    0 0 1

仍然有3个新定义的邻居。

如果图像效果很好,我还没有检查过你的图片,但是我已经为这个问题实现过这样的问题...

答案 3 :(得分:0)

这是我的解决方法:


    # Functions to generate kernels of curve intersection 

    def generate_nonadjacent_combination(input_list,take_n):
        """ 
        It generates combinations of m taken n at a time where there is no adjacent n.
        INPUT:
            input_list = (iterable) List of elements you want to extract the combination 
            take_n =     (integer) Number of elements that you are going to take at a time in
                         each combination
        OUTPUT:
            all_comb =   (np.array) with all the combinations
        """
        all_comb = []
        for comb in itertools.combinations(input_list, take_n):
            comb = np.array(comb)
            d = np.diff(comb)
            fd = np.diff(np.flip(comb))
            if len(d[d==1]) == 0 and comb[-1] - comb[0] != 7:
                all_comb.append(comb)        
                print(comb)
        return all_comb


    def populate_intersection_kernel(combinations):
        """
        Maps the numbers from 0-7 into the 8 pixels surrounding the center pixel in
        a 9 x 9 matrix clockwisely i.e. up_pixel = 0, right_pixel = 2, etc. And 
        generates a kernel that represents a line intersection, where the center 
        pixel is occupied and 3 or 4 pixels of the border are ocuppied too.
        INPUT:
            combinations = (np.array) matrix where every row is a vector of combinations
        OUTPUT:
            kernels =      (List) list of 9 x 9 kernels/masks. each element is a mask.
        """
        n = len(combinations[0])
        template = np.array((
                [-1, -1, -1],
                [-1, 1, -1],
                [-1, -1, -1]), dtype="int")
        match = [(0,1),(0,2),(1,2),(2,2),(2,1),(2,0),(1,0),(0,0)]
        kernels = []
        for n in combinations:
            tmp = np.copy(template)
            for m in n:
                tmp[match[m][0],match[m][1]] = 1
            kernels.append(tmp)
        return kernels


    def give_intersection_kernels():
        """
        Generates all the intersection kernels in a 9x9 matrix.
        INPUT:
            None
        OUTPUT:
            kernels =      (List) list of 9 x 9 kernels/masks. each element is a mask.
        """
        input_list = np.arange(8)
        taken_n = [4,3]
        kernels = []
        for taken in taken_n:
            comb = generate_nonadjacent_combination(input_list,taken)
            tmp_ker = populate_intersection_kernel(comb)
            kernels.extend(tmp_ker)
        return kernels


    # Find the curve intersections
    def find_line_intersection(input_image, show=0):
        """
        Applies morphologyEx with parameter HitsMiss to look for all the curve 
        intersection kernels generated with give_intersection_kernels() function.
        INPUT:
            input_image =  (np.array dtype=np.uint8) binarized m x n image matrix
        OUTPUT:
            output_image = (np.array dtype=np.uint8) image where the nonzero pixels 
                           are the line intersection.
        """
        kernel = np.array(give_intersection_kernels())
        output_image = np.zeros(input_image.shape)
        for i in np.arange(len(kernel)):
            out = cv2.morphologyEx(input_image, cv2.MORPH_HITMISS, kernel[i,:,:])
            output_image = output_image + out
        if show == 1:
            show_image = np.reshape(np.repeat(input_image, 3, axis=1),(input_image.shape[0],input_image.shape[1],3))*255
            show_image[:,:,1] = show_image[:,:,1] -  output_image *255
            show_image[:,:,2] = show_image[:,:,2] -  output_image *255
            plt.imshow(show_image)
        return output_image

    #  finding corners
    def find_endoflines(input_image, show=0):
        """
        """
        kernel_0 = np.array((
                [-1, -1, -1],
                [-1, 1, -1],
                [-1, 1, -1]), dtype="int")

        kernel_1 = np.array((
                [-1, -1, -1],
                [-1, 1, -1],
                [1,-1, -1]), dtype="int")

        kernel_2 = np.array((
                [-1, -1, -1],
                [1, 1, -1],
                [-1,-1, -1]), dtype="int")

        kernel_3 = np.array((
                [1, -1, -1],
                [-1, 1, -1],
                [-1,-1, -1]), dtype="int")

        kernel_4 = np.array((
                [-1, 1, -1],
                [-1, 1, -1],
                [-1,-1, -1]), dtype="int")

        kernel_5 = np.array((
                [-1, -1, 1],
                [-1, 1, -1],
                [-1,-1, -1]), dtype="int")

        kernel_6 = np.array((
                [-1, -1, -1],
                [-1, 1, 1],
                [-1,-1, -1]), dtype="int")

        kernel_7 = np.array((
                [-1, -1, -1],
                [-1, 1, -1],
                [-1,-1, 1]), dtype="int")

        kernel = np.array((kernel_0,kernel_1,kernel_2,kernel_3,kernel_4,kernel_5,kernel_6, kernel_7))
        output_image = np.zeros(input_image.shape)
        for i in np.arange(8):
            out = cv2.morphologyEx(input_image, cv2.MORPH_HITMISS, kernel[i,:,:])
            output_image = output_image + out

        if show == 1:
            show_image = np.reshape(np.repeat(input_image, 3, axis=1),(input_image.shape[0],input_image.shape[1],3))*255
            show_image[:,:,1] = show_image[:,:,1] -  output_image *255
            show_image[:,:,2] = show_image[:,:,2] -  output_image *255
            plt.imshow(show_image)    

        return output_image#, np.where(output_image == 1)

    # 0- Find end of lines
    input_image = img.astype(np.uint8) # must be blaack and white thin network image
    eol_img = find_endoflines(input_image, 0)

    # 1- Find curve Intersections
    lint_img = find_line_intersection(input_image, 0)

    # 2- Put together all the nodes
    nodes = eol_img + lint_img
    plt.imshow(nodes)