2013-01-04 13 views
6

Ho un gruppo di immagini come questo:curva di analisi adatta

enter image description here

I dati corrispondente non è disponibile. Ho bisogno di recuperare automaticamente circa 100 punti (regolarmente x-spaziati) sulla curva blu. Tutte le curve sono molto simili, quindi ho bisogno di almeno 1 pixel di precisione, ma il sub-pixel sarebbe preferito. La buona notizia è che tutte le curve partono da 0,0 e finiscono a 1,1, quindi potremmo dimenticare la griglia.

Qualche suggerimento sulle librerie Python che potrebbero aiutare o qualsiasi altro approccio? Grazie !

+0

Interessante domanda, sto lavorando a una soluzione, ma la precisione sub-pixel è improbabile. –

+1

Solo semi-automatico ma ancora pertinente alla domanda, questa web app può fare miracoli: http://arohatgi.info/WebPlotDigitizer/ –

risposta

6

Ho salvato l'immagine in un file 14154233_input.png. Allora questo programma

import pylab as plt 
import numpy as np 

# Read image from disk and filter all grayscale 
im = plt.imread("14154233_input.png")[:,:,:3] 
im -= im.mean(axis=2).reshape(im.shape[0], im.shape[1], 1).repeat(3,axis=2) 
im_maxnorm = im.max(axis=2) 

# Find y-position of remaining line 
ypos = np.ones((im.shape[1])) * np.nan 
for i in range(im_maxnorm.shape[1]): 
    if im_maxnorm[:,i].max()<0.01: 
     continue 
    ypos[i] = np.argmax(im_maxnorm[:,i]) 

# Pick only values that are set 
ys = 1-ypos[np.isfinite(ypos)] 
# Normalize to 0,1 
ys -= ys.min() 
ys /= ys.max() 

# Create x values 
xs = np.linspace(0,1,ys.shape[0]) 

# Create plot of both 
# read and filtered image and 
# data extracted 
plt.figure(figsize=(4,8)) 
plt.subplot(211) 
plt.imshow(im_maxnorm) 
plt.subplot(212, aspect="equal") 
plt.plot(xs,ys) 
plt.show() 

Produce questa trama:

Ausgabe

È quindi possibile fare con xs e ys quello che vuoi. Forse dovresti inserire questo codice in una funzione che restituisca xs e ys o così.

Uno potrebbe migliorare la precisione inserendo gaussiani su ogni colonna o così. Se ne hai davvero bisogno, dimmelo.

+0

Non sono pratico con pylab, posso chiederti di spiegare come 'im - = im.mean (axis = 2) .reshape (im.shape [0], im.shape [1], 1) .repeat (3, axis = 2) 'line funziona? –

+0

Sicuro. imread ci dà un'immagine RGBA, cioè il nostro array ha forma (x, y, 4), che immediatamente riduco scartando alfa ([:,:,: 3] nella riga precedente). Poi ho voluto impostare tutti i colori con rosso = verde = blu (tutti i grigi dal nero al bianco) in nero, in modo che rimanga solo la linea blu. Lo faccio sottraendo, per ogni pixel, la media dei valori R, G e B da ciascuno di essi. Se sono uguali, tutti diventano zero. '.mean (axis = 2)' calcola la media, creando una matrice 2d; '.reshape()' lo rende di nuovo 3d, aggiungendo solo un 3. dim of len 1; '.repeat()' reimposta la forma della matrice a quella di 'im' –

2

Innanzitutto, leggere l'immagine tramite

from scipy.misc import imread  
im = imread("thefile.png") 

Questo dà una matrice numpy 3D con la terza dimensione essendo i canali di colore (RGB + alfa). La curva è nel canale blu, ma la griglia è anche lì. Ma nel canale rosso, hai la griglia e non la curva. Quindi usiamo

a = im[:,:,2] - im[:,:,0] 

Ora, vogliamo la posizione del massimo lungo ogni colonna. Con una precisione di pixel, è data da

y0 = np.argmax(a, axis=0) 

Il risultato di questo è zero quando non c'è curva blu nella colonna, cioè all'esterno della cornice. Su può ottenere i limiti del frame da

xmin, xmax = np.where(y0>0)[0][[0,-1] 

Con questo, potrebbe essere possibile ridimensionare l'asse x.

Quindi, si desidera la risoluzione subpixel. Concentriamoci una singola colonna

f=a[:,x] 

Usiamo una singola iterazione del metodo di Newton definire la posizione di un extrema

y1 = y0 - f'[y]/f''[y] 

noti che non possiamo iterare ulteriormente a causa del campionamento discreto. Ciononostante, vogliamo una buona approssimazione delle derivate, quindi useremo uno schema a 5 punti per entrambi.

coefprime = np.array([1,-8, 0, 8, -1], float) 
coefsec = np.array([-1, 16, -30, 16, -1], float) 
y1 = y0 - np.dot(f[y0-2:y0+3], coefprime)/np.dot(f[y0-2:y0+3], coefsec) 

P.S. : Thorsten Kranz era più veloce di me (almeno qui), ma la mia risposta ha la precisione subpixel e il mio modo di estrarre la curva blu è probabilmente più comprensibile.