Information interactive en pixel d'une image en Python?

version courte: existe-t-il une méthode Python pour afficher une image qui affiche, en temps réel, les indices et les intensités des pixels? Donc, en déplaçant le curseur sur l'image, j'ai un affichage continuellement mis à jour tel que pixel[103,214] = 198 (pour l'échelle de gris) ou pixel[103,214] = (138,24,211) pour rgb?

version longue:

supposons que j'ouvre une image en échelle de gris enregistrée en tant que im et que je l'affiche avec imshow de matplotlib:

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

ce que j'obtiens c'est l'image, et en bas à droite du cadre de la fenêtre, un affichage interactif des indices pixels. Sauf qu'ils ne sont pas tout à fait, car les valeurs ne sont pas des entiers: x=134.64 y=129.169 par exemple.

si je règle l'affichage avec la bonne résolution:

plt.axis('equal')

les valeurs x et y ne sont toujours pas des entiers.

le imshow méthode du paquet spectral fait un meilleur travail:

import spectral as spc
spc.imshow(im)

Puis en bas à droite j'ai maintenant pixel=[103,152] par exemple.

cependant, aucune de ces méthodes n'affiche les valeurs des pixels. J'ai donc deux questions:

  1. le imshow de matplotlib (et le imshow de scikit-image ) peut-il être forcé à montrer les bons indices (entiers) de pixels?
  2. Pouvez une de ces méthodes, être étendu pour afficher les valeurs des pixels?
18
demandé sur Alasdair 2014-12-30 14:19:52

4 réponses

il y a plusieurs façons de procéder.

vous pouvez Monkey-patch ax.format_coord , similaire à cet exemple officiel . Je vais utiliser ici une approche un peu plus" pythonique " qui ne repose pas sur des variables globales. (Notez que je suppose qu'aucun extent kwarg n'a été spécifié, similaire à l'exemple de matplotlib. Pour être tout à fait général, vous devez faire un peu plus de travail .)

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()

enter image description here

Sinon, juste brancher l'un de mes propres projets, vous pouvez utiliser mpldatacursor pour cela. Si vous spécifiez hover=True , la boîte apparaîtra à chaque fois que vous survolerez un artiste activé. (Par défaut, il ne s'affiche lorsque l'utilisateur clique dessus.) Notez que mpldatacursor manipule correctement les extent et origin kwargs à imshow .

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()

enter image description here

aussi, j'ai oublié de mentionner comment afficher les indices de pixels. Dans le premier exemple, c'est juste supposer que i, j = int(y), int(x) . Vous pouvez les ajouter à la place de x et y , si vous préférez.

avec mpldatacursor , vous pouvez les spécifier avec un formatteur personnalisé. Les arguments i et j sont les indices pixels corrects, indépendamment des extent et origin de l'image tracer.

par exemple (notez le extent de l'image par rapport aux coordonnées i,j affichées):

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()

enter image description here

35
répondu Joe Kington 2014-12-30 16:37:23

absolue " bare bones "one-liner" pour ce faire: (sans compter sur les 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)

il met l'image dans la fermeture donc s'assure que si vous avez plusieurs images chacune affichera ses propres valeurs.

2
répondu Roy Shilkrot 2017-09-18 13:31:30

tous les exemples que j'ai vu ne fonctionnent que si vos X et y sont à partir de 0. Voici le code qui utilise vos extensions d'image pour trouver la valeur de 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

si vous utilisez PySide/PyQT voici un exemple pour avoir un tooltip de mouse hover pour les données""

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
répondu justengel 2016-10-05 22:42:39

avec Jupyter vous pouvez le faire soit avec datacursor(myax) ou par ax.format_coord .

code échantillon:

%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()

le datacursor(myax) peut également être remplacé par ax.format_coord = lambda x,y : "x=%g y=%g" % (x, y)

0
répondu shahar_m 2017-05-29 08:07:20