可以使用matplotlib的等高线绘制来匹配像素边缘吗?

28 浏览
0 Comments

可以使用matplotlib的等高线绘制来匹配像素边缘吗?

如何在matplotlib中勾画像素边界?例如,对于像下面这样的半随机数据集,

# 下面的代码块与问题无关
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')

如何使轮廓与像素对齐?我在numpymatplotlib库中寻找解决方案。

0
0 Comments

Can matplotlib contours match pixel edges?

问题的出现原因:

如果图像的分辨率是每个单位1像素,那么如何定义像素的“边缘”?如果边缘的概念只在与像素本身相同分辨率的框架中有意义,那么如果contour与图像本身具有相同的分辨率,则不能绘制任何边缘。

解决方法:

另一方面,当然可以增加分辨率,使得“边缘”的概念具有意义。因此,假设将分辨率增加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绘制图像本身。

为什么imshowcontour之间存在不匹配?尽管通过将分辨率增加10倍而不是100倍可以更好地可视化。

关于像素边缘定义-我想说,没有什么能阻止我们将像素边缘定义为xy等于0.5, 1.0, 1.5, ...的网格线。然后可以使用基本的Line2d绘制这些线条。

0
0 Comments

Matplotlib的contour函数可以绘制出与像素边缘匹配的等高线。但是,有一些用户发现使用contour函数绘制的等高线与像素边缘不匹配。为了解决这个问题,用户提供了两种不同的解决方法。

首先,用户提供了一个名为contour_rect_slow的函数,该函数可以绘制出连接像素值为0和1的像素边缘的单条线段。该函数的实现过程如下:

1. 对输入的图像进行零填充。

2. 计算图像在垂直方向上相邻像素值的差异,并筛选出差异为1的像素点,将其作为线段的起点。

3. 计算图像在水平方向上相邻像素值的差异,并筛选出差异为1的像素点,将其作为线段的终点。

其次,用户还提供了一个名为contour_rect的更快的版本,该版本也能绘制出连接像素值为0和1的像素边缘的线段。该函数的实现过程如下:

1. 对输入的图像进行零填充。

2. 计算图像在垂直方向上相邻像素值的差异,并筛选出差异为1的像素点,将其作为线段的起点。

3. 计算图像在水平方向上相邻像素值的差异,并筛选出差异为1的像素点,将其作为线段的终点。

这两种方法都可以解决contour函数绘制的等高线与像素边缘不匹配的问题。用户可以根据自己的需求选择使用其中的一种方法。

需要注意的是,用户在使用上述方法时需要注意性能问题。对于大型图像来说,上述方法的执行速度明显较慢,比起使用mpl.contour函数要慢得多。

此外,用户还提出了一个建议,即在使用numpy版本低于1.17的情况下,需要更新np.pad()函数的调用方式,因为在旧版本的numpy中,np.pad()函数需要传入一个必需的参数mode。用户认为这个建议在仍在使用旧版本numpy的用户中可能会有用。

0