检测图像中直线的起点和终点(numpy数组)

2024-04-28 18:14:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我有这样一个形象:

enter image description here

我想要的是得到每个线段的起点和终点的坐标。实际上,我想的是考虑这样一个事实:每个极端点应该只有一个点属于它的邻域中的线段,而所有其他点都应该至少有2个。不幸的是,这条线的厚度不等于一个像素,所以这个推理不成立。在


Tags: 像素邻域事实起点形象厚度线段
3条回答

下面是一个相当简单的方法:

  • 加载图像并丢弃多余的alpha通道
  • 骷髅
  • 过滤器寻找3x3邻域,这些邻域有中心像素集并且只有一个

#!/usr/bin/env python3

import numpy as np
from PIL import Image
from scipy.ndimage import generic_filter
from skimage.morphology import medial_axis

# Line ends filter
def lineEnds(P):
    """Central pixel and just one other must be set to be a line end"""
    return 255 * ((P[4]==255) and np.sum(P)==510)

# Open image and make into Numpy array
im = Image.open('lines.png').convert('L')
im = np.array(im)

# Skeletonize
skel = (medial_axis(im)*255).astype(np.uint8)

# Find line ends
result = generic_filter(skel, lineEnds, (3, 3))

# Save result
Image.fromarray(result).save('result.png')

enter image description here


请注意,使用ImageMagick命令行,您可以获得完全相同的结果,所需的工作量要少得多:

^{pr2}$

或者,如果您希望它们是数字而不是图像:

convert result.png txt: | grep "gray(255)"

样本输出

134,78: (65535)  #FFFFFF  gray(255)    < - line end at coordinates 134,78
106,106: (65535)  #FFFFFF  gray(255)   < - line end at coordinates 106,106
116,139: (65535)  #FFFFFF  gray(255)   < - line end at coordinates 116,139
196,140: (65535)  #FFFFFF  gray(255)   < - line end at coordinates 196,140

另一种方法是使用scipy.ndimage.morphology.binary_hit_or_miss,并将您的“Hits”设置为下图中的白色像素,将您的“Misses”设置为黑色像素:

enter image description here

这个图表来自安东尼·蒂森的优秀材料here。在


与上述类似,您可以将上面的“Hits”“Misses”内核与OpenCV一起使用,如here

morphologyEx(input_image, output_image, MORPH_HITMISS, kernel);

我想这是最快的方法。在


关键词:Python、图像、图像处理、行尾、行尾、形态、命中或未命中、HMT、ImageMagick、filter。在

你提到的方法应该可以很好的工作,你只需要做一个形态学操作之前,减少线的宽度到一个像素。您可以使用scikit图像来实现:

from skimage.morphology import medial_axis
import cv2

# read the lines image
img = cv2.imread('/tmp/tPVCc.png', 0)

# get the skeleton
skel = medial_axis(img)

# skel is a boolean matrix, multiply by 255 to get a black and white image
cv2.imwrite('/tmp/res.png', skel*255)

enter image description here

this page关于skimage中的骨骼化方法。在

我会用分水岭式算法来解决这个问题。我在下面描述了这个方法,但它只处理单个(多段)线,所以您需要将图像分割成多行的图像。在

玩具示例:

0000000
0111110
0111110
0110000
0110000
0000000

其中0表示黑色,1表示白色。在

现在我的解决方案实现:

^{pr2}$

输出:

[[0 0 0 0 0 0 0]
 [0 5 4 4 5 6 0]
 [0 5 4 3 4 5 0]
 [0 6 5 0 0 0 0]
 [0 0 0 0 0 0 0]]

现在结束由上面数组中最大值的位置表示(在本例中是6)。在

解释:我正在检查尽可能多的白色像素。对于每一个这样的像素,我是“泛洪”图像-我放置特殊值(127-不同于0,不同于255),然后推广它-在每一步中,所有与特殊值相邻的255本身都成为特殊值。我正在计算删除所有255所需的步骤。因为如果你从末端开始(等速)注水,比在任何其他位置都有水源的情况下要花费更多的时间,那么最大的泛洪次数就是终点。在

我必须承认,我没有深入地测试这一点,所以我不能保证在特殊情况下正确工作,例如在自交线的情况下。我也意识到我的解决方案的粗糙度,特别是在检测邻居和传播特殊值方面,所以请随意改进它。我假设所有的边界像素都是黑色的(没有一条线接触到图像的“框架”)。在

相关问题 更多 >