图像的交互式像素信息

29

简短版本:有没有Python方法可以实时显示像素索引和强度的图像?这样,当我在图像上移动光标时,我可以得到一个不断更新的显示,例如pixel[103,214] = 198(对于灰度图像)或pixel[103,214] = (138,24,211)(对于RGB图像)。

详细版本:

假设我打开了一个保存为ndarray格式的灰度图像im,并使用matplotlib的imshow函数显示它:

im = plt.imread('image.png')
plt.imshow(im,cm.gray)

我得到的是图像,窗口框架右下角有一个交互式显示像素索引。不过,它们并不完全是整数值:x=134.64 y=129.169 例如。

如果我设置正确的分辨率显示:

plt.axis('equal')

x 和 y 的值仍然不是整数。

spectral 包中的 imshow 方法效果更好:

import spectral as spc
spc.imshow(im)

然后在右下角,我现在有pixel=[103,152]作为示例。

然而,这些方法中没有一个也显示像素值。所以我有两个问题:

  1. matplotlibimshow(以及scikit-imageimshow)能强制显示正确的(整数)像素索引吗?
  2. 这些方法中是否有任何一种可以扩展以显示像素值?
7个回答

49

有几种不同的方法可以实现这个。

你可以类似于这个官方示例中的做法,对 ax.format_coord 进行 monkey-patch。在这里,我将使用稍微更为“pythonic”的方法,不依赖全局变量。(请注意,我假设没有指定 extent kwarg,与 matplotlib 示例类似。要完全通用,你需要进行更多工作。)

import numpy as np
import matplotlib.pyplot as plt

class Formatter(object):
    def __init__(self, im):
        self.im = im
    def __call__(self, x, y):
        z = self.im.get_array()[int(y), int(x)]
        return 'x={:.01f}, y={:.01f}, z={:.01f}'.format(x, y, z)

data = np.random.random((10,10))

fig, ax = plt.subplots()
im = ax.imshow(data, interpolation='none')
ax.format_coord = Formatter(im)
plt.show()

在此输入图像描述

或者,只是为了推广我自己的一个项目,你可以使用mpldatacursor。如果你指定hover=True,当你将鼠标悬停在启用的艺术家上时,框会弹出。 (默认情况下,它只在单击时弹出。)请注意,mpldatacursor会正确处理imshowextentorigin kwargs。

import numpy as np
import matplotlib.pyplot as plt
import mpldatacursor

data = np.random.random((10,10))

fig, ax = plt.subplots()
ax.imshow(data, interpolation='none')

mpldatacursor.datacursor(hover=True, bbox=dict(alpha=1, fc='w'))
plt.show()

图片描述

另外,我忘了如何显示像素索引。在第一个例子中,它只是假设i, j = int(y), int(x)。如果您愿意,可以将其添加到xy的位置。

使用mpldatacursor,您可以使用自定义格式设置器指定它们。无论所绘制图像的extentorigin如何,ij参数都是正确的像素索引。

例如(请注意图像的extent与显示的i,j坐标之间的差异):

import numpy as np
import matplotlib.pyplot as plt
import mpldatacursor

data = np.random.random((10,10))

fig, ax = plt.subplots()
ax.imshow(data, interpolation='none', extent=[0, 1.5*np.pi, 0, np.pi])

mpldatacursor.datacursor(hover=True, bbox=dict(alpha=1, fc='w'),
                         formatter='i, j = {i}, {j}\nz = {z:.02g}'.format)
plt.show()

在此输入图片描述


这篇文章比其他所有文章都更好,我认为它是一个更好的答案。您能将它们全部标记为此问题的副本吗?(在我有1票重复关闭之前,我已经对大多数文章进行了投票) - tacaswell
你能否提交一个PR来更改官方示例以使用Formatter类? - tacaswell
@tcaswell - 关于关闭投票的问题已经处理完毕。(谢谢!) 如果其中任何一个与此问题显著不同,请随时重新打开它们。我今晚稍后会提交示例的PR。 - Joe Kington
1
@YonatanSimson - 是的,它应该可以工作。但是,我认为你的问题可能与我几天前刚刚修复的一个错误有关:https://github.com/joferkington/mpldatacursor/commit/9eaca06b65d1a202b914bc990419717ede1e83ff 如果有机会,你可以尝试从当前的github主分支重新安装。对此感到抱歉! - Joe Kington
4
请注意,第一个示例的像素值不正确。更准确的做法是z = self.im.get_array()[int(y+0.5), int(x+0.5)] - ImportanceOfBeingErnest
显示剩余3条评论

5
一个非常简单的“一行代码”可以实现此操作(不依赖于datacursor)。
def val_shower(im):
    return lambda x,y: '%dx%d = %d' % (x,y,im[int(y+.5),int(x+.5)])

plt.imshow(image)
plt.gca().format_coord = val_shower(ims)

它将图像放在闭包中,因此确保如果您有多个图像,则每个图像都会显示自己的值。


0

我看到的所有示例都只适用于x和y范围从0开始的情况。这里是使用图像范围查找z值的代码。

import numpy as np
import matplotlib.pyplot as plt

fig, ax = plt.subplots()

d = np.array([[i+j for i in range(-5, 6)] for j in range(-5, 6)])
im = ax.imshow(d)
im.set_extent((-5, 5, -5, 5))

def format_coord(x, y):
    """Format the x and y string display."""
    imgs = ax.get_images()
    if len(imgs) > 0:
        for img in imgs:
            try:
                array = img.get_array()
                extent = img.get_extent()

                # Get the x and y index spacing
                x_space = np.linspace(extent[0], extent[1], array.shape[1])
                y_space = np.linspace(extent[3], extent[2], array.shape[0])

                # Find the closest index
                x_idx= (np.abs(x_space - x)).argmin()
                y_idx= (np.abs(y_space - y)).argmin()

                # Grab z
                z = array[y_idx, x_idx]
                return 'x={:1.4f}, y={:1.4f}, z={:1.4f}'.format(x, y, z)
            except (TypeError, ValueError):
                pass
        return 'x={:1.4f}, y={:1.4f}, z={:1.4f}'.format(x, y, 0)
    return 'x={:1.4f}, y={:1.4f}'.format(x, y)
# end format_coord

ax.format_coord = format_coord

如果您正在使用PySide/PyQT,这里有一个示例,可以为数据设置鼠标悬停提示。
import matplotlib
matplotlib.use("Qt4Agg")
matplotlib.rcParams["backend.qt4"] = "PySide"
import matplotlib.pyplot as plt

fig, ax = plt.subplots()

# Mouse tooltip
from PySide import QtGui, QtCore
mouse_tooltip = QtGui.QLabel()
mouse_tooltip.setFrameShape(QtGui.QFrame.StyledPanel)
mouse_tooltip.setWindowFlags(QtCore.Qt.ToolTip)
mouse_tooltip.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)
mouse_tooltip.show()

def show_tooltip(msg):
    msg = msg.replace(', ', '\n')
    mouse_tooltip.setText(msg)

    pos = QtGui.QCursor.pos()
    mouse_tooltip.move(pos.x()+20, pos.y()+15)
    mouse_tooltip.adjustSize()
fig.canvas.toolbar.message.connect(show_tooltip)


# Show the plot
plt.show()

0
如果你和我一样在使用Google Colab,那么这些解决方案可能不适用,因为Colab禁用了matplotlib的交互式图像功能。那么你可以尝试使用Plotly: https://plotly.com/python/imshow/
import plotly.express as px
import numpy as np
img_rgb = np.array([[[255, 0, 0], [0, 255, 0], [0, 0, 255]],
                [[0, 255, 0], [0, 0, 255], [255, 0, 0]]
               ], dtype=np.uint8)
fig = px.imshow(img_rgb)
fig.show()

enter image description here


对我来说,这只显示了 x 和 y,但没有颜色。 - Kaschi14
我之前已经将数值标准化为float32 0-1,但是为了显示颜色信息,您需要使用uint8的0-255。 - Kaschi14

0

pixel value at the corner

Matplotlib有内置的交互式图表,可以记录屏幕角落的像素值。

要设置,请首先安装pip install ipympl

然后使用%matplotlib notebook%matplotlib widget代替%matplotlib inline

plotlyBokeh的缺点是它们不能在Pycharm上工作。

有关更多信息,请查看doc


0

使用Jupyter,您可以通过datacursor(myax)ax.format_coord来实现。

示例代码:

%matplotlib nbagg

import numpy as np  
import matplotlib.pyplot as plt

X = 10*np.random.rand(5,3)

fig,ax = plt.subplots()    
myax = ax.imshow(X, cmap=cm.jet,interpolation='nearest')
ax.set_title('hover over the image')

datacursor(myax)

plt.show()

datacursor(myax) 可以被替换为 ax.format_coord = lambda x,y : "x=%g y=%g" % (x, y)


datacurser未定义,请详细说明您的答案。 - Kaschi14

-1
要获取图像的交互式像素信息,请使用 imagetoolbox 模块。 要下载该模块,请打开命令提示符并输入:
``` pip install imagetoolbox ```
输入以下代码以获取图像的交互式像素信息: 在此输入图像描述 输出:在此输入图像描述

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接