最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - How to draw straight lines from one edge of a blob to the other in opencv - Stack Overflow

programmeradmin1浏览0评论

I have a blob of irregular shapes like this:

Now I want to draw lines from the outer edge to the inner edge of the blob like this:

I have used cv2.connectedComponents() on result after applying Canny edge detection to get the two edges.

originalimage = cv2.imread(R"blob.png")
edge = cv2.Canny(originalimage, 100, 200)

def get_islands(img):
    n, labels = cv2.connectedComponents(img.astype(np.uint8))
    islands = [(labels == i).astype(np.uint8) for i in range(1, n)]
    return islands

edge_sets = get_islands(edge)
inner = edge_sets[1]
outer = edge_sets[0]

Now I want to draw line from outer to inner. I have tried calculating slope for each point in the outer layer from it's nearest neighbors. But it fails for corner points. First I have tried creating a graph of neighboring pixels.

def create_graph(binary_image):
    graph = defaultdict(list)

    height, width = binary_image.shape
    all_points = np.nonzero(binary_image)
    all_points= sorted(list(map(list, [*zip(*all_points)]))) #Transpose the List
    
    for x, y in all_points:
        for dx in range(-1, 2, 1):
            for dy in range(-1, 2, 1):
                if dx == 0 and dy == 0:
                    continue
                if (x+dx>=0 and y+dy>=0 and x+dx < height and y+dy < width) and binary_image[x+dx][y+dy]:
                    graph[(x, y)].append((x+dx, y+dy))
    return graph

outer_graph = create_graph(edge_sets[0])
inner_graph = create_graph(edge_sets[1])

Then I have tried calculating slope of the outer edge at every point from its neighboring pixels and drawing perpendicular line to it.

def get_slope(graph, point):
    neighbours = graph[point]
    slopes = []
    eps = 1e-6
    for neighbour in neighbours:
        if neighbour[0] != point[0]: # Vertical Line
            slopes.append((neighbour[1] - point[1]) / (neighbour[0] - point[0] + eps))
    if slopes:
        return np.mean(slopes)
    else:
        return 0

lines = []

for point in outer_graph:
    slope = get_slope(outer_graph, point)
    if slope == 0:
        continue
    perpedicular_slope = -1/slope
    for inner_point in inner_graph:
        if abs(get_slope(inner_graph, inner_point) - perpedicular_slope) < 0.01 \
            and is_line_in_image(point, inner_point, originalimage):
            lines.append([point, inner_point])

But it fails at the points where the edge is not smooth and the lines deviates a lot.

lines = np.array(lines)
line_image = cv2.cvtColor(originalimage, cv2.COLOR_GRAY2RGB)
for i, line in enumerate(lines):
    if i % 100 == 0:
        line_image = cv2.line(line_image, tuple(line[0][::-1]), tuple(line[1][::-1]), (255, 0, 0), 3)
plt.imshow(line_image)

Output:

How can I improve my algorithm to get the expected output? Is my approach correct?

发布评论

评论列表(0)

  1. 暂无评论