2014-12-30 17 views
18

Versione corta: Esiste un metodo Python per la visualizzazione di un'immagine che mostra in tempo reale gli indici e le intensità dei pixel? In questo modo, mentre sposto il cursore sull'immagine, ho un display continuamente aggiornato come pixel[103,214] = 198 (per la scala di grigi) o pixel[103,214] = (138,24,211) per rgb?Informazioni pixel interattive di un'immagine in Python?

Versione lunga:

Supponiamo che io aprire un'immagine in scala di grigi salvato come ndarray im e visualizzarlo con imshow da matplotlib:

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

quello che ottengo è l'immagine, e nel fondo a destra della cornice della finestra, una visualizzazione interattiva degli indici dei pixel. Tranne che non sono abbastanza, in quanto i valori non sono numeri interi: x=134.64 y=129.169 per esempio.

Se ho impostato il display con risoluzione corretta:

plt.axis('equal') 

il valori xey non sono ancora interi.

Il metodo di imshow dal pacchetto spectral fa un lavoro migliore:

import spectral as spc 
spc.imshow(im) 

Poi in basso a destra mi hanno ora pixel=[103,152] per esempio.

Tuttavia, nessuno di questi metodi mostra anche i valori dei pixel. Così ho due domande:

  1. Può il imshow da matplotlib (e il imshow da scikit-image) essere costretti a mostrare i (intero) gli indici di pixel corretti?
  2. È possibile estendere uno di questi metodi per mostrare anche i valori dei pixel?

risposta

34

Ci sono un paio di modi diversi per farlo.

È possibile utilizzare la patch per scimmia ax.format_coord, simile a this official example. Qui userò un approccio leggermente più "pitonico" che non si basa su variabili globali. (Si noti che sto assumendo è stato specificato alcun extent kwarg, simile all'esempio matplotlib. Per essere pienamente generale, è necessario fare 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() 

enter image description here

In alternativa, basta collegare uno dei per i miei progetti, è possibile utilizzare mpldatacursor per questo. Se si specifica hover=True, verrà visualizzata la finestra ogni volta che si passa con il mouse su un artista abilitato. (Per impostazione predefinita, viene visualizzato solo quando si fa clic.) Si noti che mpldatacursor gestisce i kwargs extent e origin su imshow correttamente.

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

Inoltre, ho dimenticato di dire come mostrare gli indici di pixel. Nel primo esempio, supponiamo che sia i, j = int(y), int(x). Puoi aggiungere quelli al posto di x e , se preferisci.

Con mpldatacursor, è possibile specificarli con un formattatore personalizzato. Gli argomenti i e j sono gli indici di pixel corretti, indipendentemente dallo extent e dallo origin dell'immagine tracciata.

Per esempio (si noti la extent dell'immagine rispetto al i,j coordinate visualizzate):

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

+0

Duplicazione di https://stackoverflow.com/questions/27704490/interactive-pixel-information-of-an-image-in-python#27707723 e collegamenti in. Penso che questa sia una risposta migliore di qualsiasi gli altri. Puoi contrassegnarli tutti come duplicati di questo (ho già votato la maggior parte di essi prima che il duplicato di 1 voto fosse chiuso)? – tacaswell

+0

E puoi inserire un PR per cambiare l'esempio ufficiale per usare la classe 'Formatter'? – tacaswell

+0

@tcaswell - Fatto ai voti ravvicinati. (E grazie!) Se qualcuno di questi sembra significativamente diverso da questa domanda, sentitevi liberi di riaprirli. Inserirò un PR per l'esempio più tardi stasera. –

0

Tutti gli esempi che ho visto il lavoro solo se il x e y estensioni iniziano da 0. Ecco il codice che usa le estensioni dell'immagine per trovare il valore 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 

Se si utilizza PySide/PyQT ecco un esempio di avere un tooltip passaggio del mouse per i dati

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

con Jupyter è possibile farlo sia con datacursor(myax) o ax.format_coord.

codice di esempio:

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

il datacursor(myax) può anche essere sostituito con ax.format_coord = lambda x,y : "x=%g y=%g" % (x, y)

0

un assoluto scarno "one-liner" Per fare questo: (senza fare affidamento su 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) 

Mette l'immagine in chiusura, quindi si assicura che se si dispone di più immagini ciascuna visualizzerà i propri valori.