我有一个镂空图像(如下所示)。
我想得到这些线的交叉点。我在下面尝试了以下方法,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;
它找到有两个以上相邻像素的白色像素的坐标。我认为这只会返回角落,但事实并非如此 - 它会返回更多的点数。
这是输出,其检测到的点在图像上标记。这是因为它检测到下面显示的一些不是交叉点的例子。
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
还有更多例子。我应该考虑另一种方法来检测交叉点。感谢所有的意见和想法。
答案 0 :(得分:3)
答案 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)