Python Rasterio – Extract Selected Pixel Values with Coordinates

pixelpythonrasterio

My goal is to get the coordinates of all pixels with a specified value (ex: maximum and minimum pixel values).

# imports
import numpy as np
import pandas as pd
import geopandas as gpd
import rasterio

# load tif
src = rasterio.open('./data/thhz.tif')

# read band
band = src.read(1)

# get maximum and minimal values
max = np.max(band)
min = np.min(band)

# convert raster into shapefile
# got this from https://gis.stackexchange.com/questions/346288/extract-all-pixels-values-from-geotiff-with-python
### this process is too slow from here need to use other methods
px_vals = []

for x in range(band.shape[0]):
    for y in range(band.shape[1]):
        px_vals.append({'x': x, 
                        'y': y,
                        'value': band[x, y]})

# convert list to dataframe
vals = pd.DataFrame(data=px_vals, columns=['x', 'y', 'value'])

# convert dataframe to geopandas 
vals['geometry'] = gpd.points_from_xy(vals['x'], vals['y'])
vals = gpd.GeoDataFrame(vals, geometry='geometry', crs='EPSG:4326')

# transform coordinates with affine of raster
# get affine matrix with src.profile
vals['geometry'] = vals.affine_transform([0.001, 0.0, 2.616837667, 0.0, -0.001, 11.815923996])
# this also was not well converted

# slice values with coordinates
min_pixels = vals[vals['value'] == max]
max_pixels = vals[vals['value'] == min]

Best Answer

Looping over a numpy array will always be slower than using vectorized numpy operations only. Try:

min_rows, min_cols = np.where(band == np.min(band))
max_rows, max_cols = np.where(band == np.max(band))

band == np.min(band) gives back a boolean array, broadcasted to be in the same shape as band, and containing True where the element is equal to the min value.

np.where() gives back indices where the condition is true, if you only specify the first argument.

Related Question