final 2024_Remote_Sensing
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import rasterio
|
||||
import numpy as np
|
||||
from shapely.geometry import mapping
|
||||
from rasterio.features import geometry_mask
|
||||
|
||||
# Step 1: Load Raster Data
|
||||
def load_raster(raster_path):
|
||||
with rasterio.open(raster_path) as src:
|
||||
bands = [src.read(i) for i in range(1, src.count + 1)]
|
||||
profile = src.profile
|
||||
return np.stack(bands, axis=-1), profile
|
||||
|
||||
# Step 2: Extract Reference Spectra
|
||||
def extract_reference_spectra(raster, training_shapefile, profile):
|
||||
import geopandas as gpd
|
||||
training_labels = gpd.read_file(training_shapefile)
|
||||
|
||||
reference_spectra = {}
|
||||
|
||||
for _, row in training_labels.iterrows():
|
||||
class_id = row['class_id']
|
||||
geom = [mapping(row['geometry'])]
|
||||
|
||||
mask = geometry_mask(
|
||||
geom, transform=profile['transform'], invert=True, out_shape=(profile['height'], profile['width'])
|
||||
)
|
||||
|
||||
masked_pixels = raster[mask]
|
||||
mean_spectrum = np.mean(masked_pixels, axis=0)
|
||||
reference_spectra[class_id] = mean_spectrum
|
||||
|
||||
return reference_spectra
|
||||
|
||||
# Step 3: Spectral Angle Mapping
|
||||
def spectral_angle(pixel_spectrum, reference_spectrum):
|
||||
# Avoid zero vectors
|
||||
pixel_norm = np.linalg.norm(pixel_spectrum)
|
||||
reference_norm = np.linalg.norm(reference_spectrum)
|
||||
|
||||
if pixel_norm == 0 or reference_norm == 0:
|
||||
return np.pi # Maximum angle (180 degrees)
|
||||
|
||||
numerator = np.dot(pixel_spectrum, reference_spectrum)
|
||||
denominator = pixel_norm * reference_norm
|
||||
|
||||
# Clip to avoid numerical issues with arccos
|
||||
cosine_similarity = numerator / denominator
|
||||
cosine_similarity = np.clip(cosine_similarity, -1.0, 1.0)
|
||||
|
||||
angle = np.arccos(cosine_similarity)
|
||||
return angle
|
||||
|
||||
|
||||
def classify_with_sam(raster, reference_spectra):
|
||||
rows, cols, bands = raster.shape
|
||||
classified_image = np.full((rows, cols), fill_value=255, dtype=np.uint8) # 255 as nodata
|
||||
|
||||
for i in range(rows):
|
||||
for j in range(cols):
|
||||
pixel_spectrum = raster[i, j, :]
|
||||
angles = {class_id: spectral_angle(pixel_spectrum, ref_spectrum)
|
||||
for class_id, ref_spectrum in reference_spectra.items()}
|
||||
classified_image[i, j] = min(angles, key=angles.get) # Class with smallest angle
|
||||
|
||||
return classified_image
|
||||
|
||||
# Step 4: Save Classified Image
|
||||
def save_classified_image(classified_image, profile, output_path):
|
||||
profile.update(count=1, dtype=rasterio.uint8, nodata=255)
|
||||
with rasterio.open(output_path, "w", **profile) as dst:
|
||||
dst.write(classified_image, 1)
|
||||
|
||||
# Main Execution
|
||||
if __name__ == "__main__":
|
||||
# File paths
|
||||
raster_path = "stacked/stacked.tif"
|
||||
training_shapefile = "training/training.shp"
|
||||
output_path = "classified/sam.tif"
|
||||
|
||||
# Load raster and metadata
|
||||
raster, profile = load_raster(raster_path)
|
||||
|
||||
# Extract reference spectra
|
||||
print("Extracting reference spectra...")
|
||||
reference_spectra = extract_reference_spectra(raster, training_shapefile, profile)
|
||||
|
||||
# Classify raster using SAM
|
||||
print("Classifying with SAM...")
|
||||
classified_image = classify_with_sam(raster, reference_spectra)
|
||||
|
||||
# Save the classified image
|
||||
save_classified_image(classified_image, profile, output_path)
|
||||
print(f"Classified image saved to {output_path}")
|
||||
Reference in New Issue
Block a user