【问题标题】:Interactive pixel information of an image in Python?Python中图像的交互式像素信息?
【发布时间】:2015-02-26 13:28:27
【问题描述】:

简短版: 是否有一种 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. 是否可以扩展这些方法以显示像素值?

【问题讨论】:

    标签: python image image-processing matplotlib scikit-image


    【解决方案1】:

    有几种不同的方法可以解决这个问题。

    你可以猴子补丁ax.format_coord,类似于this official example。我将在这里使用一种稍微“pythonic”的方法,它不依赖于全局变量。 (请注意,我假设没有指定 extent kwarg,类似于 matplotlib 示例。要完全通用,您需要执行 a touch more work。)

    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 确实可以正确处理 extentoriginimshow 的 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,您可以使用自定义格式化程序指定它们。 ij 参数是正确的像素索引,与绘制的图像的 extentorigin 无关。

    例如(注意图像的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()
    

    【讨论】:

    • stackoverflow.com/questions/27704490/… 的副本和其中的链接。我认为这是比其他任何一个更好的答案。你能把它们都标记为这个的重复项吗(在我有 1 票重复关闭之前,我已经对它们中的大多数进行了投票)?
    • 你能不能把官方的例子改成使用Formatter类?
    • @tcaswell - 在接近投票时完成。 (谢谢!)如果其中任何一个看起来与这个问题有很大不同,请随时重新打开它们。今晚晚些时候我会为这个例子提交一个 PR。
    • @YonatanSimson - 是的,它应该可以工作。但是,我认为您的问题可能与我几天前刚刚修复的一个错误有关:github.com/joferkington/mpldatacursor/commit/… 如果有机会,您可以尝试从当前的 github master 重新安装。很抱歉!
    • 请注意,第一个例子有半个像素的错误。它应该是z = self.im.get_array()[int(y+0.5), int(x+0.5)]
    【解决方案2】:

    做到这一点的绝对准系统“单线”:(不依赖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)
    

    它将图像置于封闭状态,以确保您有多个图像,每个图像都会显示其自己的值。

    【讨论】:

      【解决方案3】:

      我看到的所有示例仅在您的 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()
      

      【讨论】:

        【解决方案4】:

        使用 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)

        【讨论】:

          【解决方案5】:

          如果您像我一样在 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()
          

          【讨论】:

            【解决方案6】:

            要获取图像的交互式像素信息,请使用模块 imagetoolbox 要下载模块,请打开命令提示符并编写

            pip install imagetoolbox 编写给定的代码以获取图像的交互式像素信息 enter image description here 输出:enter image description here

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-03-10
              • 2015-08-24
              • 2019-02-02
              • 1970-01-01
              • 2021-02-05
              相关资源
              最近更新 更多