Spaces:
Sleeping
Sleeping
import streamlit as st | |
import ee | |
import geemap.foliumap as geemap | |
import pandas as pd | |
import matplotlib.pyplot as plt | |
import datetime | |
import os | |
# Set page title and layout | |
st.set_page_config(page_title="سیستم پایش مزارع نیشکر", layout="wide") | |
# Header | |
st.title("سیستم پایش هوشمند مزارع نیشکر") | |
st.markdown("---") | |
# Initialize Earth Engine | |
def initialize_ee(): | |
try: | |
# Path to your service account key file | |
service_account = 'dehkhodamap-e9f0da4ce9f6514021@ee-esmaeilkiani13877.iam.gserviceaccount.com' | |
credentials_path = 'ee-esmaeilkiani13877-cfdea6eaf411.json' | |
# Check if credentials file exists | |
if os.path.exists(credentials_path): | |
credentials = ee.ServiceAccountCredentials(service_account, credentials_path) | |
ee.Initialize(credentials) | |
return True | |
else: | |
st.error("فایل احراز هویت یافت نشد. لطفا مسیر فایل را بررسی کنید.") | |
return False | |
except Exception as e: | |
st.error(f"خطا در اتصال به Google Earth Engine: {str(e)}") | |
return False | |
# Initialize Earth Engine | |
ee_initialized = initialize_ee() | |
if ee_initialized: | |
# Define coordinates for the area of interest | |
LATITUDE = 31.534442 | |
LONGITUDE = 48.724416 | |
# Create a point geometry | |
point = ee.Geometry.Point([LONGITUDE, LATITUDE]) | |
# Create a buffer around the point (5 km radius) | |
aoi = point.buffer(5000) | |
# Sidebar for controls | |
with st.sidebar: | |
st.header("تنظیمات") | |
# Date selection | |
st.subheader("انتخاب بازه زمانی") | |
today = datetime.datetime.now() | |
default_start_date = today - datetime.timedelta(days=365) | |
start_date = st.date_input("تاریخ شروع", default_start_date) | |
end_date = st.date_input("تاریخ پایان", today) | |
# Convert dates to strings | |
start_date_str = start_date.strftime("%Y-%m-%d") | |
end_date_str = end_date.strftime("%Y-%m-%d") | |
# Cloud cover filter | |
cloud_cover = st.slider("حداکثر درصد ابر", 0, 100, 10) | |
# Index selection | |
index_options = { | |
"NDVI (شاخص تفاضل نرمال شده پوشش گیاهی)": "NDVI", | |
"EVI (شاخص پوشش گیاهی بهبود یافته)": "EVI", | |
"SAVI (شاخص پوشش گیاهی تعدیل شده خاک)": "SAVI", | |
"NDMI (شاخص رطوبت تفاضل نرمال شده)": "NDMI" | |
} | |
selected_index = st.selectbox("انتخاب شاخص", list(index_options.keys())) | |
index_code = index_options[selected_index] | |
# Analysis type | |
analysis_type = st.selectbox( | |
"نوع تحلیل", | |
["پایش سلامت و رشد", "مدیریت آبیاری", "مدیریت آفات", "مدیریت برداشت", "مدیریت زمین"] | |
) | |
st.markdown("---") | |
st.info("برای بهترین نتیجه، تصاویر با درصد ابر کمتر از 10 درصد توصیه میشود.") | |
# Main content | |
col1, col2 = st.columns([2, 1]) | |
with col1: | |
st.subheader("نقشه پایش مزارع نیشکر") | |
# Get Sentinel-2 collection | |
sentinel = ee.ImageCollection('COPERNICUS/S2_SR') \ | |
.filterDate(start_date_str, end_date_str) \ | |
.filterBounds(aoi) \ | |
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', cloud_cover)) | |
# Sort by cloud cover and get the most recent image | |
recent_image = sentinel.sort('CLOUDY_PIXEL_PERCENTAGE').first() | |
# Check if we have an image | |
if recent_image: | |
# Function to calculate indices | |
def calculate_index(image, index_name): | |
if index_name == 'NDVI': | |
# NDVI = (NIR - Red) / (NIR + Red) | |
return image.normalizedDifference(['B8', 'B4']).rename('NDVI') | |
elif index_name == 'EVI': | |
# EVI = 2.5 * ((NIR - Red) / (NIR + 6 * Red - 7.5 * Blue + 1)) | |
return image.expression( | |
'2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', { | |
'NIR': image.select('B8'), | |
'RED': image.select('B4'), | |
'BLUE': image.select('B2') | |
}).rename('EVI') | |
elif index_name == 'SAVI': | |
# SAVI = ((NIR - Red) / (NIR + Red + L)) * (1 + L), where L = 0.5 | |
return image.expression( | |
'((NIR - RED) / (NIR + RED + 0.5)) * 1.5', { | |
'NIR': image.select('B8'), | |
'RED': image.select('B4') | |
}).rename('SAVI') | |
elif index_name == 'NDMI': | |
# NDMI = (NIR - SWIR1) / (NIR + SWIR1) | |
return image.normalizedDifference(['B8', 'B11']).rename('NDMI') | |
# Calculate the selected index | |
index_image = calculate_index(recent_image, index_code) | |
# Create a map | |
Map = geemap.Map() | |
Map.centerObject(aoi, 13) | |
# Add the index layer with appropriate visualization parameters | |
if index_code == 'NDVI' or index_code == 'EVI' or index_code == 'SAVI': | |
vis_params = {'min': 0, 'max': 1, 'palette': ['FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901', '66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01', '012E01', '011D01', '011301']} | |
elif index_code == 'NDMI': | |
vis_params = {'min': -1, 'max': 1, 'palette': ['red', 'orange', 'yellow', 'green', 'cyan', 'blue']} | |
Map.addLayer(index_image, vis_params, f'{index_code} Index') | |
# Add true color layer | |
true_color_vis = {'bands': ['B4', 'B3', 'B2'], 'min': 0, 'max': 3000} | |
Map.addLayer(recent_image, true_color_vis, 'True Color', False) | |
# Add AOI | |
Map.addLayer(aoi, {'color': 'red'}, 'Area of Interest') | |
# Display the map | |
Map.to_streamlit(height=600) | |
# Display image metadata | |
image_date = ee.Date(recent_image.get('system:time_start')).format('YYYY-MM-dd').getInfo() | |
cloud_percentage = recent_image.get('CLOUDY_PIXEL_PERCENTAGE').getInfo() | |
st.info(f"تاریخ تصویر: {image_date} | درصد ابر: {cloud_percentage:.2f}%") | |
else: | |
st.error("هیچ تصویری با شرایط مورد نظر یافت نشد. لطفا محدوده زمانی یا درصد ابر را تغییر دهید.") | |
with col2: | |
st.subheader("تحلیل و توصیهها") | |
if recent_image: | |
# Calculate statistics for the index | |
stats = index_image.reduceRegion( | |
reducer=ee.Reducer.mean().combine( | |
reducer2=ee.Reducer.stdDev(), | |
sharedInputs=True | |
).combine( | |
reducer2=ee.Reducer.minMax(), | |
sharedInputs=True | |
), | |
geometry=aoi, | |
scale=10, | |
maxPixels=1e9 | |
).getInfo() | |
# Display statistics | |
if index_code in stats: | |
mean_val = stats[f'{index_code}_mean'] | |
std_val = stats[f'{index_code}_stdDev'] | |
min_val = stats[f'{index_code}_min'] | |
max_val = stats[f'{index_code}_max'] | |
st.write(f"**میانگین {index_code}:** {mean_val:.4f}") | |
st.write(f"**انحراف معیار:** {std_val:.4f}") | |
st.write(f"**حداقل:** {min_val:.4f}") | |
st.write(f"**حداکثر:** {max_val:.4f}") | |
# Interpretation based on index and analysis type | |
st.markdown("### تفسیر و توصیهها") | |
if index_code == 'NDVI': | |
if mean_val > 0.7: | |
health_status = "عالی" | |
color = "green" | |
elif mean_val > 0.5: | |
health_status = "خوب" | |
color = "lightgreen" | |
elif mean_val > 0.3: | |
health_status = "متوسط" | |
color = "orange" | |
else: | |
health_status = "ضعیف" | |
color = "red" | |
st.markdown(f"**وضعیت سلامت گیاه:** <span style='color:{color}'>{health_status}</span>", unsafe_allow_html=True) | |
if analysis_type == "پایش سلامت و رشد": | |
if mean_val > 0.7: | |
st.success("گیاهان در وضعیت سلامت عالی قرار دارند. رشد مطلوب است.") | |
elif mean_val > 0.5: | |
st.info("گیاهان در وضعیت سلامت خوبی قرار دارند. نظارت منظم توصیه میشود.") | |
elif mean_val > 0.3: | |
st.warning("سلامت گیاهان متوسط است. بررسی عوامل محدودکننده رشد توصیه میشود.") | |
else: | |
st.error("سلامت گیاهان ضعیف است. بررسی فوری عوامل تنشزا ضروری است.") | |
elif analysis_type == "مدیریت آبیاری": | |
if mean_val < 0.4: | |
st.error("احتمال تنش آبی وجود دارد. افزایش آبیاری توصیه میشود.") | |
elif mean_val > 0.7: | |
st.success("وضعیت آبیاری مطلوب است.") | |
else: | |
st.info("وضعیت آبیاری قابل قبول است. نظارت منظم توصیه میشود.") | |
elif index_code == 'NDMI': | |
if mean_val > 0.4: | |
moisture_status = "بالا" | |
color = "blue" | |
elif mean_val > 0.2: | |
moisture_status = "مناسب" | |
color = "green" | |
elif mean_val > 0: | |
moisture_status = "متوسط" | |
color = "orange" | |
else: | |
moisture_status = "پایین" | |
color = "red" | |
st.markdown(f"**وضعیت رطوبت:** <span style='color:{color}'>{moisture_status}</span>", unsafe_allow_html=True) | |
if analysis_type == "مدیریت آبیاری": | |
if mean_val < 0: | |
st.error("رطوبت خاک پایین است. افزایش آبیاری توصیه میشود.") | |
elif mean_val > 0.4: | |
st.warning("رطوبت خاک بالاست. کاهش آبیاری توصیه میشود.") | |
else: | |
st.success("رطوبت خاک در محدوده مناسبی قرار دارد.") | |
# Add more specific recommendations based on analysis type | |
st.markdown("### اقدامات پیشنهادی") | |
if analysis_type == "پایش سلامت و رشد": | |
st.write("1. بررسی منظم وضعیت سلامت گیاه") | |
st.write("2. نمونهبرداری از خاک برای بررسی وضعیت مواد مغذی") | |
st.write("3. بررسی علائم بیماریها و آفات در مناطق با NDVI پایین") | |
elif analysis_type == "مدیریت آبیاری": | |
st.write("1. تنظیم برنامه آبیاری بر اساس شاخصهای رطوبتی") | |
st.write("2. نصب سنسورهای رطوبت خاک در مناطق بحرانی") | |
st.write("3. بررسی سیستم زهکشی در مناطق با رطوبت بالا") | |
elif analysis_type == "مدیریت آفات": | |
st.write("1. بازرسی دقیق مناطق با NDVI پایین برای شناسایی آفات") | |
st.write("2. برنامهریزی سمپاشی هدفمند در مناطق آلوده") | |
st.write("3. پایش مستمر مناطق مستعد آلودگی") | |
elif analysis_type == "مدیریت برداشت": | |
st.write("1. اولویتبندی مناطق برای برداشت بر اساس شاخص بلوغ") | |
st.write("2. برنامهریزی مسیرهای بهینه برداشت") | |
st.write("3. تخمین عملکرد محصول بر اساس شاخصهای گیاهی") | |
elif analysis_type == "مدیریت زمین": | |
st.write("1. شناسایی مناطق با پتانسیل بهبود") | |
st.write("2. برنامهریزی کوددهی بر اساس نقشههای شاخص گیاهی") | |
st.write("3. ارزیابی تأثیر روشهای مدیریتی مختلف") | |
else: | |
st.error(f"خطا در محاسبه آمار {index_code}") | |
# Historical trend analysis section | |
if recent_image: | |
st.markdown("---") | |
st.subheader("تحلیل روند تاریخی") | |
# Get historical data for the selected index | |
def get_historical_data(): | |
# Create a time series of the selected index | |
def calculate_index_for_collection(image): | |
index = calculate_index(image, index_code) | |
mean = index.reduceRegion( | |
reducer=ee.Reducer.mean(), | |
geometry=aoi, | |
scale=30, | |
maxPixels=1e9 | |
).get(index_code) | |
return image.set('date', image.date().format('YYYY-MM-dd')).set('index_mean', mean) | |
# Get a 12-month collection | |
collection = sentinel.map(calculate_index_for_collection) | |
# Get the dates and index values | |
dates = collection.aggregate_array('date').getInfo() | |
values = collection.aggregate_array('index_mean').getInfo() | |
# Create a dataframe | |
data = {'date': dates, 'value': values} | |
df = pd.DataFrame(data) | |
df = df.dropna() # Remove any NaN values | |
# Convert to datetime | |
df['date'] = pd.to_datetime(df['date']) | |
# Sort by date | |
df = df.sort_values('date') | |
return df | |
# Get the historical data | |
try: | |
hist_data = get_historical_data() | |
if not hist_data.empty: | |
# Plot the data | |
fig, ax = plt.subplots(figsize=(10, 4)) | |
ax.plot(hist_data['date'], hist_data['value'], marker='o', linestyle='-') | |
ax.set_title(f'روند تغییرات {index_code} در طول زمان') | |
ax.set_xlabel('تاریخ') | |
ax.set_ylabel(index_code) | |
ax.grid(True) | |
# Display the plot | |
st.pyplot(fig) | |
# Trend analysis | |
if len(hist_data) > 1: | |
first_value = hist_data['value'].iloc[0] | |
last_value = hist_data['value'].iloc[-1] | |
change = ((last_value - first_value) / first_value) * 100 if first_value != 0 else 0 | |
if change > 10: | |
st.success(f"روند صعودی: افزایش {change:.2f}% در شاخص {index_code} از ابتدای دوره") | |
elif change < -10: | |
st.error(f"روند نزولی: کاهش {abs(change):.2f}% در شاخص {index_code} از ابتدای دوره") | |
else: | |
st.info(f"روند ثابت: تغییر {change:.2f}% در شاخص {index_code} از ابتدای دوره") | |
else: | |
st.warning("دادههای کافی برای تحلیل روند تاریخی وجود ندارد.") | |
except Exception as e: | |
st.error(f"خطا در تحلیل روند تاریخی: {str(e)}") | |
else: | |
st.error("اتصال به Google Earth Engine برقرار نشد. لطفا تنظیمات احراز هویت را بررسی کنید.") |