【问题标题】:pixel-precise positioning of line mesh on top of image data with matplotlib使用 matplotlib 在图像数据顶部进行线网格的像素精确定位
【发布时间】:2019-05-27 17:19:34
【问题描述】:

我正在尝试在 python 库 matplotlib 显示的图像网格顶部精确覆盖 1 像素宽的线网格。

不幸的是,我似乎无法对结果进行足够精细的控制,以实现线网格与数据网格的正确对齐,如下面的代码所示。结果似乎总是很接近,但并不完全正确。

我尝试过同时使用imshowpcolormesh 函数,但都遇到了问题。

imshow 方法:

import matplotlib.pyplot as plt
import numpy as np

size = 60
border = 5

#create test data for image and ticks location
im = np.zeros(shape=(size,size),dtype=np.float32)
ticks = np.arange(size)+0.5

#create test checkerboard pattern outside of border area
for index in range(size-2*border):
    im[border+index,border:-border] += index % 2
for index in range(size-2*border):
    im[border:-border,index+border] -= index % 2
im = np.abs(im)

#display image with imshow
plt.imshow(im, interpolation='nearest', cmap='binary', vmin=0, vmax=1)
ax = plt.gca()
ax.set_xticks(ticks)
ax.set_xticklabels([])
ax.set_yticks(ticks)
ax.set_yticklabels([])
ax.grid(color='r', linestyle='-', linewidth=1)
#sometimes line is off by 1 pixel
plt.show()

我希望红线的线网格准确地覆盖数据网格的棋盘格图案,但它们相差一个像素。

此缩放图像显示了结果,并且偏移量很容易看到:

我也尝试过使用 pcolormesh 和 edgecolor(使用与上面相同的数据):

plt.pcolormesh(im, cmap='binary', vmin=0, vmax=1, edgecolors='r', linewidth=0.005)
plt.show()

这里的红线网格对齐更好,但线宽不一致,有时是 1 像素宽,有时是 2 像素宽,如下图所示:

在这里,理想情况下,我希望始终获得 1 像素宽的线条。 可以使用 linewidth 参数,但是如果我将其设置得太小,那么线条开始具有 0 像素宽度并且它们完全消失,而且我不太了解 linewidth 的单位是什么。

总之,如果有任何关于如何在定位(红线网格不偏离黑白棋盘格)和线宽(在屏幕上总是正好 1 像素宽)方面实现一致性的建议,我将不胜感激。

【问题讨论】:

  • 网格被捕捉到最近的像素,但如果一个与像素边界重叠,它有时会变得两倍宽。如果您真的想像这样戳像素,我可以建议 matplotlib 不是最好的工具吗? Pillow 将允许您将图像文件读取和写入到 numpy 数组中,并且您可以直接在那里更改 RGBA 值。当假设分辨率足够高,抗锯齿可以在屏幕或图形中做出令人愉悦的表示时,Matplotlib 的效果会更好。
  • Hallo @Jody ,用例是具有数千个芯片的晶圆图的交互式显示(也允许放大等功能),我们还显示其他内容,如值的直方图分布 - 因此matplotlib 解决方案将更加理想和简单(如果可能的话)。虽然问题仅在最缩小的级别可见,但您可以在此处看到整个晶圆,因此最有用。
  • 我认为这两个在 GitHub 上都有问题。您可以在那里挖掘并发表评论。但基本上 imshow 和刻度/网格捕捉到最近的像素和 pcolormesh 使用抗锯齿。此外还有一些错误 w imshow 以及它如何从数据转换为图像像素。
  • github.com/matplotlib/matplotlib/issues/12934 描述了此问题,并且大多数其他类似问题都已链接。我已经不再担心这个问题了,因为我认为 matplotlib 很快就会转向使用 cairo 作为主要的光栅化后端,并且它已经解决了很多这些问题。

标签: python matplotlib


【解决方案1】:

哦,好吧,我想我会回答我自己的问题。这是基于反复试验,所以我不确定它是否普遍有效,但我希望这些信息可能对某人有用。

我能够使用下面的代码一致地绘制宽度恰好为 1 像素的 pcolormesh 网格,其中 my_dpi 需要精确设置为显示屏的 dpi 分辨率 imsize_pixel_ximsize_pixel_y 是绘图窗口的所需大小。

my_dpi = 96.0
imsize_pixel_x = 800
imsize_pixel_y = 600

plt.figure(figsize=(imsize_pixel_x/my_dpi, imsize_pixel_y/my_dpi), dpi=my_dpi)
plt.pcolormesh(im, cmap='binary', vmin=0, vmax=1, edgecolors='r', linewidth=my_dpi/(1024*32))

plt.show()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-20
    • 2019-07-14
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-14
    • 2015-12-31
    相关资源
    最近更新 更多