PySptools Cookbook: Practical Recipes for Spectral Data Processing
Introduction
PySptools is a Python library for hyperspectral image processing and spectral analysis. This cookbook provides concise, practical recipes to help you perform common tasks: loading data, visualizing spectra, preprocessing (noise removal, normalization), spectral unmixing, classification, and exporting results. Each recipe includes a short explanation and code snippets ready to adapt.
Setup
Install required packages:
bash
pip install pysptools numpy matplotlib scipy scikit-learn rasterio
1. Load a hyperspectral image
Use rasterio to read common hyperspectral formats (ENVI, GeoTIFF). Convert to a 3D array (rows, cols, bands).
python
import rasterio import numpy as np def loadhyperspectral(path): with rasterio.open(path) as src: data = src.read() # shape: (bands, rows, cols) meta = src.meta data = np.transpose(data, (1, 2, 0)) # (rows, cols, bands) return data.astype(np.float32), meta
2. View a single-pixel spectrum
Plot the spectral signature at a given pixel (row, col).
python
import matplotlib.pyplot as plt def plotspectrum(img, wavelengths, row, col): spectrum = img[row, col, :] plt.plot(wavelengths, spectrum) plt.xlabel(‘Wavelength (nm)’) plt.ylabel(‘Reflectance’) plt.title(f’Spectrum at ({row},{col})’) plt.grid(True) plt.show()
3. Display an RGB composite
Create an RGB visualization by selecting three bands or using nearest bands to standard RGB wavelengths.
python
def rgb_composite(img, r_band, g_band, b_band, stretch=True): rgb = img[:, :, [r_band, g_band, b_band]].copy() if stretch: p2, p98 = np.percentile(rgb, (2, 98)) rgb = np.clip((rgb - p2) / (p98 - p2), 0, 1) return rgb # Display plt.imshow(rgb_composite(hyperimg, 30, 20, 10)) plt.axis(‘off’) plt.show()
4. Bad-band removal and masking
Remove noisy bands (e.g., water absorption) and mask invalid pixels.
python
def remove_bad_bands(img, bad_band_indices): mask = np.ones(img.shape[2], dtype=bool) mask[bad_band_indices] = False return img[:, :, mask] def mask_invalid(img, invalid_value=0): mask = np.any(img != invalidvalue, axis=2) return img * mask[:, :, None]
5. Spectral smoothing (Savitzky–Golay)
Reduce noise in spectra with Savitzky–Golay filter from scipy.
python
from scipy.signal import savgol_filter def smooth_spectra(img, window_length=7, polyorder=2): rows, cols, bands = img.shape flat = img.reshape(-1, bands) smoothed = savgol_filter(flat, window_length=window_length, polyorder=polyorder, axis=1) return smoothed.reshape(rows, cols, bands)
6. Continuum removal
Normalize absorption features by removing continuum using PySptools’ continuumremoval.
python
from pysptools.spectro import continuum_removal def continuum(img): rows, cols, bands = img.shape flat = img.reshape(-1, bands) cr = continuumremoval(flat) return cr.reshape(rows, cols, bands)
7. Endmember extraction with N-FINDR
Extract pure spectral signatures using N-FINDR from PySptools.
python
from pysptools.eea import nfindr def extract_endmembers(img, n_endmembers): rows, cols, bands = img.shape flat = img.reshape(-1, bands).T # shape: (bands, pixels) nf = nfindr.NFINDR(flat) E, idx = nf.extract(endmembers=n_endmembers) return E.T # shape: (nendmembers, bands)
8. Linear spectral unmixing (LSU)
Unmix each pixel into abundances using least squares.
python
import numpy.linalg as la def linear_unmix(img, endmembers): rows, cols, bands = img.shape flat = img.reshape(-1, bands) E = endmembers.T # shape: (bands, n_endmembers) abundances, _, _, _ = la.lstsq(E, flat.T, rcond=None) abundances = abundances.T.reshape(rows, cols, -1) return np.clip(abundances, 0, 1)
9. Spectral Angle Mapper (SAM) classification
Classify pixels by spectral angle to reference spectra.
python
from pysptools.distance import sam def sam_classify(img, references): rows, cols, bands = img.shape flat = img.reshape(-1, bands) sam_vals = sam.SAM(flat.T, references.T) # expects (bands, pixels) and (bands, refs) labels = samvals.argmin(axis=1).reshape(rows, cols) return labels
10. Simple supervised classification (SVM)
Train an SVM on labeled pixels and predict across the image.
python
from sklearn.svm import SVC def svm_classify(img, train_idx, train_labels): rows, cols, bands = img.shape flat = img.reshape(-1, bands) X = flat[train_idx] clf = SVC(kernel=‘rbf’, probability=False) clf.fit(X, trainlabels) labels = clf.predict(flat).reshape(rows, cols) return labels
11. Dimensionality reduction (PCA)
Reduce bands to the top principal components for visualization or preprocessing.
python
from sklearn.decomposition import PCA def pca_reduce(img, n_components=3): rows, cols, bands = img.shape flat = img.reshape(-1, bands) pca = PCA(n_components=n_components) pcs = pca.fit_transform(flat) return pcs.reshape(rows, cols, ncomponents), pca
12. Save results as GeoTIFF
Write classification or abundance maps back to disk preserving georeference.
python
import rasterio from rasterio.transform import from_origin def save_geotiff(path, array, meta, dtype=‘uint8’): # array shape: (rows, cols) or (rows, cols, bands) if array.ndim == 2: array = array[None, :, :] else: array = np.transpose(array, (2, 0, 1)) meta_copy = meta.copy() meta_copy.update(driver=‘GTiff’, count=array.shape[0], dtype=dtype) with rasterio.open(path, ‘w’, **metacopy) as dst: dst.write(array)
13. Performance tips
- Work on flattened arrays for batch operations.
- Use memory mapping or chunking for very large images.
- Precompute masks to skip invalid pixels in heavy loops.
14. Quick end-to-end example
Load image → remove bad bands → smooth → extract endmembers → unmix → save abundance maps.
python
img, meta = load_hyperspectral(‘image.tif’) img = remove_bad_bands(img, bad_band_indices=[0,1,2,-1]) img = smooth_spectra(img) endmembers = extract_endmembers(img, 4) abundances = linear_unmix(img, endmembers) save_geotiff(‘abundances.tif’, abundances, meta, dtype=‘float32’)
References
- PySptools documentation and modules used: spectro, eea, distance.
- scipy, scikit-learn, rasterio for supporting functionality.
This cookbook gives compact, reusable recipes; adapt window sizes, band indices, and model parameters to your dataset.
Leave a Reply