Files
courses/2024_Remote_Sensing/report.py
T
2025-02-12 19:27:51 +01:00

101 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import rasterio
import numpy as np
import pandas as pd
def map_two_digit_code(code: int) -> str:
"""
Returns a string label like 'Water -> Agriculture'
by interpreting the tens digit as the 'from' class
and the ones digit as the 'to' class.
Example:
code = 34
tens_digit = 3 -> 'Forest'
ones_digit = 4 -> 'Agriculture'
return 'Forest -> Agriculture'
"""
# Define what each digit means
digit_to_label = {
1: "Water",
2: "Urban",
3: "Forest",
4: "Agriculture"
}
# Tens digit = 'from' class
tens_digit = code // 10
from_label = digit_to_label.get(tens_digit, "Unknown")
# Ones digit = 'to' class
ones_digit = code % 10
to_label = digit_to_label.get(ones_digit, "Unknown")
return f"{from_label} -> {to_label}"
def generate_change_detection_report(tif_path: str, output_csv_path: str = None) -> pd.DataFrame:
"""
Reads a single-band change-detection GeoTIFF with classes from 11 to 44,
generates a report of pixel counts, area, and applies a label for every code.
:param tif_path: Path to the input GeoTIFF.
:param output_csv_path: If provided, saves the report as a CSV file.
:return: A pandas DataFrame with columns: ['Class_Value', 'Pixel_Count', 'Area', 'Label'].
"""
# 1. Open the raster
with rasterio.open(tif_path) as src:
band = src.read(1)
transform = src.transform
# Compute pixel area
pixel_width = transform[0]
pixel_height = -transform[4] # Typically negative
pixel_area = pixel_width * pixel_height
# 2. Count unique class values
unique_vals, counts = np.unique(band, return_counts=True)
# 3. Filter classes from 11 to 44
valid_mask = (unique_vals >= 11) & (unique_vals <= 44)
filtered_classes = unique_vals[valid_mask]
filtered_counts = counts[valid_mask]
# 4. Calculate area per class
areas = filtered_counts * pixel_area
# 5. Create a DataFrame
df_report = pd.DataFrame({
"Class_Value": filtered_classes,
"Pixel_Count": filtered_counts,
"Area": areas
})
# 6. Apply the custom mapping function to get a text label (e.g., 'Water -> Agriculture')
df_report["Label"] = df_report["Class_Value"].apply(map_two_digit_code)
# 7. (Optional) sort by Class_Value
df_report.sort_values(by="Class_Value", inplace=True)
# 8. Optionally save the DataFrame to a CSV file
if output_csv_path:
df_report.to_csv(output_csv_path, index=False)
return df_report
# ---------------
# Example usage:
if __name__ == "__main__":
input_tif = "change_detected/change_detection.tif" # Update path as needed
report_df = generate_change_detection_report(
tif_path=input_tif,
output_csv_path="report/change_detection_report.csv"
)
print("Detailed Report (11–44):")
print(report_df)
# Optional: Summarize area by the Label column
summary = report_df.groupby("Label")["Area"].sum().reset_index()
summary.columns = ["Label", "Total_Area"]
print("\nArea Summary by Label:")
print(summary)