or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdcrs.mddata-types.mddataset-io.mdfeatures.mdindex.mdprocessing.mdtransformations.mdwindowing.md

features.mddocs/

0

# Feature Operations

1

2

Conversion between raster and vector data including shape extraction, geometry rasterization, and spatial analysis operations. These functions bridge raster and vector geospatial data formats.

3

4

## Capabilities

5

6

### Shape Extraction

7

8

Extract polygon shapes from raster data, converting raster regions into vector geometries.

9

10

```python { .api }

11

def shapes(image, mask=None, connectivity=4, transform=None):

12

"""

13

Extract polygon shapes from raster data.

14

15

Parameters:

16

- image (numpy.ndarray): Input raster array

17

- mask (numpy.ndarray): Mask array (same shape as image)

18

- connectivity (int): Pixel connectivity (4 or 8)

19

- transform (Affine): Geospatial transformation for coordinates

20

21

Yields:

22

tuple: (geometry, value) pairs where geometry is GeoJSON-like dict

23

"""

24

```

25

26

Usage examples:

27

28

```python

29

from rasterio.features import shapes

30

import rasterio

31

import json

32

33

# Extract shapes from classified raster

34

with rasterio.open('landcover.tif') as dataset:

35

# Read classification data

36

landcover = dataset.read(1)

37

38

# Extract all shapes

39

shape_gen = shapes(

40

landcover,

41

transform=dataset.transform,

42

connectivity=8 # 8-connected pixels

43

)

44

45

# Convert to GeoJSON features

46

features = []

47

for geometry, value in shape_gen:

48

feature = {

49

'type': 'Feature',

50

'geometry': geometry,

51

'properties': {'class_id': int(value)}

52

}

53

features.append(feature)

54

55

# Save as GeoJSON

56

geojson = {

57

'type': 'FeatureCollection',

58

'features': features

59

}

60

61

with open('landcover_polygons.geojson', 'w') as f:

62

json.dump(geojson, f)

63

64

# Extract shapes with custom mask

65

with rasterio.open('elevation.tif') as dataset:

66

elevation = dataset.read(1)

67

68

# Create mask for areas above threshold

69

high_elevation_mask = elevation > 2000 # meters

70

71

# Extract high elevation areas as shapes

72

high_areas = list(shapes(

73

elevation,

74

mask=high_elevation_mask,

75

transform=dataset.transform

76

))

77

78

print(f"Found {len(high_areas)} high elevation areas")

79

```

80

81

### Geometry Rasterization

82

83

Convert vector geometries into raster format by "burning" them into pixel arrays.

84

85

```python { .api }

86

def rasterize(shapes, out_shape=None, fill=0, out=None, transform=None,

87

all_touched=False, merge_alg=MergeAlg.replace, default_value=1,

88

dtype=None):

89

"""

90

Burn vector geometries into raster array.

91

92

Parameters:

93

- shapes (iterable): Geometries with optional values [(geom, value), ...]

94

- out_shape (tuple): Output array shape (height, width)

95

- fill (number): Fill value for background pixels

96

- out (numpy.ndarray): Pre-allocated output array

97

- transform (Affine): Geospatial transformation

98

- all_touched (bool): Burn all pixels touched by geometry

99

- merge_alg (MergeAlg): Algorithm for merging values

100

- default_value (number): Default value for geometries without values

101

- dtype (numpy.dtype): Output data type

102

103

Returns:

104

numpy.ndarray: Rasterized array

105

"""

106

```

107

108

Usage examples:

109

110

```python

111

from rasterio.features import rasterize

112

from rasterio.enums import MergeAlg

113

import geopandas as gpd

114

import numpy as np

115

116

# Rasterize vector polygons

117

# Load vector data

118

gdf = gpd.read_file('study_areas.shp')

119

120

# Define raster parameters

121

height, width = 1000, 1000

122

transform = from_bounds(*gdf.total_bounds, width, height)

123

124

# Prepare geometries with values

125

shapes_with_values = [

126

(geom, value) for geom, value in

127

zip(gdf.geometry, gdf['area_id'])

128

]

129

130

# Rasterize polygons

131

rasterized = rasterize(

132

shapes_with_values,

133

out_shape=(height, width),

134

transform=transform,

135

fill=0, # Background value

136

all_touched=False, # Only pixels with center inside geometry

137

dtype='uint16'

138

)

139

140

# Save rasterized result

141

profile = {

142

'driver': 'GTiff',

143

'dtype': 'uint16',

144

'nodata': 0,

145

'width': width,

146

'height': height,

147

'count': 1,

148

'crs': gdf.crs,

149

'transform': transform

150

}

151

152

with rasterio.open('rasterized_areas.tif', 'w', **profile) as dst:

153

dst.write(rasterized, 1)

154

155

# Rasterize with different merge algorithms

156

# Create overlapping geometries

157

overlapping_shapes = [(geom, 1) for geom in gdf.geometry]

158

159

# Replace (default) - later values overwrite earlier ones

160

raster_replace = rasterize(overlapping_shapes, (height, width), transform=transform)

161

162

# Add - sum overlapping values

163

raster_add = rasterize(

164

overlapping_shapes,

165

(height, width),

166

transform=transform,

167

merge_alg=MergeAlg.add

168

)

169

```

170

171

### Geometry Masking

172

173

Create boolean masks from vector geometries for spatial filtering and analysis.

174

175

```python { .api }

176

def geometry_mask(geometries, out_shape, transform, all_touched=False,

177

invert=False):

178

"""

179

Create boolean mask from geometries.

180

181

Parameters:

182

- geometries (iterable): Input geometries (GeoJSON-like)

183

- out_shape (tuple): Output array shape (height, width)

184

- transform (Affine): Geospatial transformation

185

- all_touched (bool): Include pixels touched by geometries

186

- invert (bool): Invert mask (True inside geometries)

187

188

Returns:

189

numpy.ndarray: Boolean mask array (True = masked by default)

190

"""

191

```

192

193

Usage examples:

194

195

```python

196

from rasterio.features import geometry_mask

197

198

# Create mask from study area boundary

199

study_area = {

200

'type': 'Polygon',

201

'coordinates': [[

202

[-120.5, 35.2], [-119.8, 35.2],

203

[-119.8, 35.9], [-120.5, 35.9],

204

[-120.5, 35.2]

205

]]

206

}

207

208

# Define raster grid

209

height, width = 500, 700

210

transform = from_bounds(-121, 35, -119, 36, width, height)

211

212

# Create mask (True outside polygon, False inside)

213

mask = geometry_mask(

214

[study_area],

215

out_shape=(height, width),

216

transform=transform,

217

invert=False # False = not masked (inside geometry)

218

)

219

220

# Create inverted mask (True inside polygon)

221

inside_mask = geometry_mask(

222

[study_area],

223

out_shape=(height, width),

224

transform=transform,

225

invert=True # True = inside geometry

226

)

227

228

# Apply mask to raster data

229

with rasterio.open('satellite_image.tif') as dataset:

230

# Read data

231

data = dataset.read(1)

232

233

# Apply study area mask

234

masked_data = np.where(inside_mask, data, -9999) # -9999 outside study area

235

236

# Or use numpy masked arrays

237

import numpy.ma as ma

238

masked_array = ma.array(data, mask=~inside_mask) # ~ inverts boolean

239

```

240

241

### Spatial Analysis Utilities

242

243

Additional utilities for spatial analysis and feature processing.

244

245

```python { .api }

246

def sieve(image, size, out=None, mask=None, connectivity=4):

247

"""

248

Remove small polygons from raster data.

249

250

Parameters:

251

- image (numpy.ndarray): Input raster array

252

- size (int): Minimum polygon size (pixels)

253

- out (numpy.ndarray): Output array

254

- mask (numpy.ndarray): Mask array

255

- connectivity (int): Pixel connectivity (4 or 8)

256

257

Returns:

258

numpy.ndarray: Sieved raster array

259

"""

260

261

def bounds(geometry):

262

"""

263

Calculate bounding box of geometry.

264

265

Parameters:

266

- geometry (dict): GeoJSON-like geometry

267

268

Returns:

269

tuple: (left, bottom, right, top) bounds

270

"""

271

```

272

273

Usage examples:

274

275

```python

276

from rasterio.features import sieve, bounds

277

278

# Remove small polygons from classification

279

with rasterio.open('classification.tif') as dataset:

280

classified = dataset.read(1)

281

282

# Remove polygons smaller than 100 pixels

283

cleaned = sieve(

284

classified,

285

size=100,

286

connectivity=8 # 8-connected neighborhoods

287

)

288

289

# Save cleaned classification

290

profile = dataset.profile.copy()

291

with rasterio.open('cleaned_classification.tif', 'w', **profile) as dst:

292

dst.write(cleaned, 1)

293

294

# Calculate geometry bounds

295

polygon = {

296

'type': 'Polygon',

297

'coordinates': [[

298

[-120.5, 35.2], [-119.8, 35.2],

299

[-119.8, 35.9], [-120.5, 35.9],

300

[-120.5, 35.2]

301

]]

302

}

303

304

geom_bounds = bounds(polygon)

305

print(f"Geometry bounds: {geom_bounds}") # (-120.5, 35.2, -119.8, 35.9)

306

```

307

308

### Feature Processing Enumerations

309

310

Enumerations for controlling feature processing algorithms:

311

312

```python { .api }

313

class MergeAlg(Enum):

314

"""Algorithms for merging rasterized values."""

315

316

replace = 'replace' # Later values overwrite earlier (default)

317

add = 'add' # Sum overlapping values

318

```

319

320

Usage in rasterization:

321

322

```python

323

from rasterio.enums import MergeAlg

324

325

# Different merge strategies for overlapping features

326

shapes_with_weights = [(geometry, weight) for geometry, weight in data]

327

328

# Sum weights in overlapping areas

329

density_raster = rasterize(

330

shapes_with_weights,

331

out_shape=(height, width),

332

transform=transform,

333

merge_alg=MergeAlg.add, # Sum overlapping values

334

dtype='float32'

335

)

336

337

# Last feature wins in overlapping areas

338

priority_raster = rasterize(

339

shapes_with_weights,

340

out_shape=(height, width),

341

transform=transform,

342

merge_alg=MergeAlg.replace, # Default behavior

343

dtype='uint16'

344

)

345

```

346

347

### Integration with Vector Libraries

348

349

Feature operations work seamlessly with popular Python geospatial libraries:

350

351

```python

352

# Integration with GeoPandas

353

import geopandas as gpd

354

355

# Read vector data

356

gdf = gpd.read_file('polygons.shp')

357

358

# Convert to rasterio format

359

geometries = gdf.geometry.apply(lambda x: x.__geo_interface__)

360

values = gdf['field_value']

361

shapes_list = list(zip(geometries, values))

362

363

# Rasterize

364

raster = rasterize(shapes_list, out_shape=(1000, 1000), transform=transform)

365

366

# Integration with Shapely

367

from shapely.geometry import Polygon, Point

368

369

# Create Shapely geometries

370

polygon = Polygon([(-120, 35), (-119, 35), (-119, 36), (-120, 36)])

371

point = Point(-119.5, 35.5)

372

373

# Convert to GeoJSON for rasterio

374

polygon_geojson = polygon.__geo_interface__

375

point_geojson = point.__geo_interface__

376

377

# Use in rasterio operations

378

mask = geometry_mask([polygon_geojson], (100, 100), transform)

379

```