如何勾画matplotlib
中的像素边界?例如,对于像下面那样的半随机数据集,
# the code block that follows is irrelevant
import numpy as np
k = []
for s in [2103, 1936, 2247, 2987]:
np.random.seed(s)
k.append(np.random.randint(0, 2, size=(2,6)))
arr = np.hstack([np.vstack(k)[:, :-1], np.vstack(k).T[::-1].T ])
image = np.zeros(shape=(arr.shape[0]+2, arr.shape[1]+2))
image[1:-1, 1:-1] = arr
很明显,image
的像素边缘的轮廓匹配优先于轮廓函数的默认行为,其中轮廓线有效地绘制在对角线上边缘像素。
import matplotlib.pyplot as plt
plt.contour(image[::-1], [0.5], colors='r')
如何使轮廓与像素对齐?我正在寻找numpy
和matplotlib
库中的解决方案。
答案 0 :(得分:7)
如果图像的每单位分辨率为1像素,您将如何定义" edge"一个像素? " edge"的概念仅在与像素本身相比增加分辨率的帧中才有意义,contour
如果使用与图像本身相同的解析,则无法绘制任何边。
另一方面,当然可以增加分辨率,使得概念" edge"有意义。因此,我们假设我们将分辨率提高了100倍,我们可以使用contour
图来轻松绘制边缘。
import matplotlib.pyplot as plt
import numpy as np
k = []
for s in [2103, 1936, 2247, 2987]:
np.random.seed(s)
k.append(np.random.randint(0, 2, size=(2,6)))
arr = np.hstack([np.vstack(k)[:, :-1], np.vstack(k).T[::-1].T ])
image = np.zeros(shape=(arr.shape[0]+2, arr.shape[1]+2))
image[1:-1, 1:-1] = arr
f = lambda x,y: image[int(y),int(x) ]
g = np.vectorize(f)
x = np.linspace(0,image.shape[1], image.shape[1]*100)
y = np.linspace(0,image.shape[0], image.shape[0]*100)
X, Y= np.meshgrid(x[:-1],y[:-1])
Z = g(X[:-1],Y[:-1])
plt.imshow(image[::-1], origin="lower", interpolation="none", cmap="Blues")
plt.contour(Z[::-1], [0.5], colors='r', linewidths=[3],
extent=[0-0.5, x[:-1].max()-0.5,0-0.5, y[:-1].max()-0.5])
plt.show()
为了进行比较,我们还可以使用imshow
在同一个图中绘制图像。
答案 1 :(得分:1)
contour_rect_slow
在像素之间的边界上绘制值为0和1的单条线。contour_rect
是一种更紧凑的版本,将更长的线连接到一条线上。
代码:
import numpy as np
k = []
for s in [2103, 1936, 2247, 2987]:
np.random.seed(s)
k.append(np.random.randint(0, 2, size=(2,6)))
arr = np.hstack([np.vstack(k)[:, :-1], np.vstack(k).T[::-1].T ])
image = np.zeros(shape=(arr.shape[0]+2, arr.shape[1]+2))
image[1:-1, 1:-1] = arr[::1]
# image[1, 1] = 1
import matplotlib.pyplot as plt
plt.imshow(image, interpolation="none", cmap="Blues")
def contour_rect_slow(im):
"""Clear version"""
pad = np.pad(im, [(1, 1), (1, 1)]) # zero padding
im0 = np.abs(np.diff(pad, n=1, axis=0))[:, 1:]
im1 = np.abs(np.diff(pad, n=1, axis=1))[1:, :]
lines = []
for ii, jj in np.ndindex(im0.shape):
if im0[ii, jj] == 1:
lines += [([ii-.5, ii-.5], [jj-.5, jj+.5])]
if im1[ii, jj] == 1:
lines += [([ii-.5, ii+.5], [jj-.5, jj-.5])]
return lines
def contour_rect(im):
"""Fast version"""
lines = []
pad = np.pad(im, [(1, 1), (1, 1)]) # zero padding
im0 = np.abs(np.diff(pad, n=1, axis=0))[:, 1:]
im1 = np.abs(np.diff(pad, n=1, axis=1))[1:, :]
im0 = np.diff(im0, n=1, axis=1)
starts = np.argwhere(im0 == 1)
ends = np.argwhere(im0 == -1)
lines += [([s[0]-.5, s[0]-.5], [s[1]+.5, e[1]+.5]) for s, e
in zip(starts, ends)]
im1 = np.diff(im1, n=1, axis=0).T
starts = np.argwhere(im1 == 1)
ends = np.argwhere(im1 == -1)
lines += [([s[1]+.5, e[1]+.5], [s[0]-.5, s[0]-.5]) for s, e
in zip(starts, ends)]
return lines
lines = contour_rect(image)
for line in lines:
plt.plot(line[1], line[0], color='r', alpha=1)
警告:对于大图像,此速度慢得多 。