Salva array numpy a 16 bit come immagine PNG a 16 bit
Sto cercando di salvare un array numpy a 16 bit come PNG a 16 bit ma quello che ottengo è solo un'immagine nera. Metto qui un minimo esempio di ciò di cui sto parlando.
im = np.random.randint(low=1, high=6536, size=65536).reshape(256,256) #sample numpy array to save as image
plt.imshow(im, cmap=plt.cm.gray)
Dato l'array numpy sopra, questa è l'immagine che vedo con matplotlib, ma quando poi salvo l'immagine come png a 16 bit ottengo l'immagine qui sotto:
import imageio
imageio.imwrite('result.png', im)
Immagine salvata:
dove sono visibili alcuni punti grigio chiaro ma l'immagine è sostanzialmente nera. Comunque quando rileggo l'immagine e la visualizzo di nuovo con matplotlib vedo la stessa immagine iniziale. Ho anche provato altre librerie invece di imageio(come PILo PyPNG) ma con lo stesso risultato.
So che i valori dell'immagine a 16 bit vanno da 0 a 65535 e nell'array numpy qui ci sono solo valori da 1 a 6536, ma ho bisogno di salvare immagini di array numpy simili a questo, cioè dove il valore massimo rappresentato nell'immagine non è è il valore massimo rappresentabile. Penso che una sorta di nornalizzazione sia coinvolta nel processo di salvataggio. Ho bisogno di salvare l'array esattamente come li vedo in matplotlib alla massima risoluzione e senza compressione o restringimento nei loro valori (quindi la divisione per 255 o la conversione in array a 8 bit non sono adatte).
Risposte
Sembra che imageio.imwritefarà la cosa giusta se converti il tipo di dati dell'array numpy.uint16prima di scrivere il file PNG:
imageio.imwrite('result.png', im.astype(np.uint16))
Quando lo faccio, result.pngè un file PNG in scala di grigi a 16 bit.
Se si desidera che l'immagine abbia l'intera gamma della scala di grigi dal nero al bianco, sarà necessario ridimensionare i valori all'intervallo [0, 65535]. Ad esempio qualcosa come:
im2 = (65535*(im - im.min())/im.ptp()).astype(np.uint16)
Quindi puoi salvare quell'array con
imageio.imwrite('result2.png', im2)
Per scrivere un array NumPy in un file PNG, un'alternativa è numpngw(un pacchetto che ho creato). Per esempio,
from numpngw import write_png
im2 = (65535*(im - im.min())/im.ptp()).astype(np.uint16)
write_png('result2.png', im2)
Se stai già utilizzando imageio, probabilmente non ci sono vantaggi significativi nell'utilizzo numpngw. Tuttavia, è una dipendenza molto più leggera di imageio--dipende solo da NumPy (nessuna dipendenza da PIL / Pillow e nessuna dipendenza da libpng).