Skip to content

Instantly share code, notes, and snippets.

@celoyd
Created December 1, 2016 20:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save celoyd/4b4d725c99b5d070598642abd639c741 to your computer and use it in GitHub Desktop.
Save celoyd/4b4d725c99b5d070598642abd639c741 to your computer and use it in GitHub Desktop.
# python pca_multiband.py input.jpeg output.tif
# n-band image -> PCA -> n-band TIFF image
# with lots of hackety assumptions
# (e.g., output is same type as input)
from sys import argv
import rasterio as rio
import numpy as np
from sklearn import decomposition
with rio.open(argv[1]) as src:
meta = src.meta
pixels = src.read()
dtype = meta['dtype']
count = meta['count']
# Todo: make this cleaner:
pixels = np.dstack([c.ravel() for c in pixels])[0]
ica = decomposition.FastICA(n_components=count, algorithm='parallel', whiten=True)
ica.fit(pixels)
print dir(ica)
# for band in range(len(pca.components_)):
# print(
# 'Band {0} will hold {1:.4g} of variance with weights:\n{2}'.format(
# band+1,
# pca.explained_variance_ratio_[band],
# ', '.join("{0:.4g}".format(x) for x in pca.components_[band])))
# # .format() within .format()! Wow! Very pro move, very well
# # respected technique, 9.7 even from the East German judges!
# Here's the actual work:
out = ica.transform(pixels)
# This is the messy reverse of the messy ravel above:
xyz = np.array([
out[:,c].reshape(meta['height'], meta['width'])
for c in range(count)
])
# Scale each band separately to fill out the data type.
# (You either really want this or really don't want this.)
xyz = np.array([
((c - np.amin(c))/(np.amax(c) - np.amin(c)))*np.iinfo(dtype).max
for c in xyz
])
xyz = xyz.astype(dtype)
meta.update({
'transform': meta['affine'],
'driver': 'GTiff',
'photometric': 'none'
})
with rio.open(argv[2], 'w', **meta) as dst:
dst.write(xyz)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment