首页 > 解决方案 > 在图像中标记边缘

问题描述

我写了一个函数来标记像素级标记图像中对象的边缘:

import numpy as np

def mark_edges(image, marker):

     axes = len(image.shape)
     edges = []

     for i in range(axes):
         shiftright = np.greater(image, np.roll(image, 1, axis=i))
         shiftleft = np.greater(image, np.roll(image, -1, axis=i))
         idx = np.where(shiftright != shiftleft)
         edges.append(idx)

     for idx in edges:
         image[idx] = marker

     return image

对于孤立的对象,这很好,因为每个标签都大于背景:

a = np.zeros(40).reshape(5,8)
a[1:4, 1:7] = 2
print(mark_edges(a, 99))

[[  0.   0.   0.   0.   0.   0.   0.   0.]
 [  0.  99.  99.  99.  99.  99.  99.   0.]
 [  0.  99.   2.   2.   2.   2.  99.   0.]
 [  0.  99.  99.  99.  99.  99.  99.   0.]
 [  0.   0.   0.   0.   0.   0.   0.   0.]]

但是,如果两个不同标记的对象彼此相邻,则结果会略有不同:

b = np.zeros(40).reshape(5,8)
b[1:4, 1:4] = 2
b[1:4, 4:7] = 4
print(mark_edges(b, 99))

[[  0.   0.   0.   0.   0.   0.   0.   0.]
 [  0.  99.  99.  99.  99.  99.  99.   0.]
 [  0.  99.   2.   2.  99.   4.  99.   0.]
 [  0.  99.  99.  99.  99.  99.  99.   0.]
 [  0.   0.   0.   0.   0.   0.   0.   0.]]

理想情况下,位置 (2,3) 应该有另一个标记。我必须接受这种不准确还是有办法解决?

标签: pythonnumpyimage-processinglogic

解决方案


而不是np.greater,使用np.not_equal. 这将导致所有区域的边缘都被标记,包括背景区域。

接下来,删除背景区域的边缘。

在下面的代码中,我使用“蒙版图像”而不是边缘像素列表。我发现这更容易使用,而且效率也很高。

import numpy as np

def mark_edges(image, marker):

  axes = len(image.shape)
  mask = np.zeros(image.shape, dtype=bool)

  for i in range(axes):
    shiftright = np.not_equal(image, np.roll(image, 1, axis=i))
    shiftleft = np.not_equal(image, np.roll(image, -1, axis=i))
    mask |= shiftright != shiftleft

  mask[image==0] = 0
  image[mask] = marker

  return image

问题中图像b的输出:

>>> b = np.zeros(40).reshape(5,8)
>>> b[1:4, 1:4] = 2
>>> b[1:4, 4:7] = 4
>>> print(mark_edges(b, 99))
[[  0.   0.   0.   0.   0.   0.   0.   0.]
 [  0.  99.  99.  99.  99.  99.  99.   0.]
 [  0.  99.   2.  99.  99.   4.  99.   0.]
 [  0.  99.  99.  99.  99.  99.  99.   0.]
 [  0.   0.   0.   0.   0.   0.   0.   0.]]

推荐阅读