File size: 5,251 Bytes
e83615d
 
8cea36d
 
e83615d
8cea36d
 
e83615d
 
 
 
 
 
 
 
8cea36d
e83615d
8cea36d
 
e83615d
8cea36d
e83615d
 
 
 
 
 
8cea36d
e83615d
 
8cea36d
e83615d
8cea36d
e83615d
8cea36d
 
e83615d
8cea36d
e83615d
 
 
8cea36d
e83615d
 
 
8cea36d
 
e83615d
 
8cea36d
e83615d
 
 
8cea36d
 
 
e83615d
8cea36d
 
 
 
 
e83615d
 
8cea36d
 
 
 
 
 
e83615d
 
8cea36d
e83615d
8cea36d
 
 
 
 
 
e83615d
 
8cea36d
 
 
 
e83615d
 
8cea36d
 
 
 
 
 
e83615d
 
8cea36d
e83615d
 
8cea36d
 
 
e83615d
8cea36d
 
 
e83615d
 
 
 
 
8cea36d
e83615d
 
8cea36d
 
e83615d
8cea36d
 
 
 
e83615d
8cea36d
 
 
e83615d
8cea36d
 
 
e83615d
8cea36d
 
 
e83615d
8cea36d
 
e83615d
8cea36d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import os
import ee
import folium
import folium.plugins as plugins

# GEE Authentication
GEE_CREDENTIALS_FILE = "./data/key/geospatial.json"
if not os.path.exists(GEE_CREDENTIALS_FILE):
    credentials = ee.ServiceAccountCredentials(None, key_data=os.getenv("geospatial_api_key"))
else:
    credentials = ee.ServiceAccountCredentials(None, GEE_CREDENTIALS_FILE)

ee.Initialize(credentials)


# Constants
CLASSES = {
    "names": ["Water", "Trees", "Flooded Vegetation", "Crops", "Built Area", "Bare Ground", "Snow/Ice", "Clouds", "Rangeland"],
    "colors": ["1a5bab", "358221", "87d19e", "ffdb5c", "ed022a", "ede9e4", "f2faff", "c8c8c8", "c6ad8d"],
}

CLOUDY_PIXEL_PERCENTAGE = 12
S2_START_DATE = "2023-08-01"
S2_END_DATE = "2023-08-31"
S2_LULC_START_DATE = "2023-01-01"
S2_LULC_END_DATE = "2023-12-31"

S2_VIS_PARAMS = {"bands": ["B4", "B3", "B2"], "min": 0, "max": 3000, "gamma": [1, 1, 1]}


# UTILS
def ApplyBitwiseS2CloudMask(image):
    """QA60 bandı üzerinden bitwise bulut maskesi uygular."""
    qa = image.select("QA60")
    cloudBitMask = 1 << 10  # Bit 10: yoğun bulut
    cirrusBitMask = 1 << 11  # Bit 11: cirrus bulut
    mask = qa.bitwiseAnd(cloudBitMask).eq(0).And(qa.bitwiseAnd(cirrusBitMask).eq(0))
    return image.updateMask(mask)


def ReColormap(image, old_colors: list, new_colors: list):
    """LULC sınıf değerlerini yeniden eşler."""
    return image.remap(old_colors, new_colors)


def CalculateIntersectionArea(image, roi: ee.Geometry):
    """Görüntü geometrisi ile ROI arasındaki kesişim alanını hesaplar."""
    convex_hull = image.geometry().convexHull()
    intersection = convex_hull.intersection(roi)
    return image.set("INTERSECTION_AREA", intersection.area())


def FilterBestAreaOfMGRSJoin(image):
    """Aynı MGRS tile içinden en büyük kesişim alanına sahip görüntüyü seçer."""
    return ee.ImageCollection.fromImages(image.get("mgrs_tile_match")).sort("INTERSECTION_AREA", False).first()


def AddGEELayer(fmap: folium.Map, ee_image, vis_params: dict, name: str, show: bool = True):
    """GEE imajını folium haritasına tile katmanı olarak ekler."""
    map_id = ee_image.getMapId(vis_params)
    tile_url = map_id["tile_fetcher"].url_format
    folium.TileLayer(tiles=tile_url, attr="Google Earth Engine", name=name, overlay=True, control=True, show=show).add_to(fmap)


def RequestFunction(roi_coords: list) -> folium.Map:
    """
    Verilen koordinat listesinden Sentinel-2 ve ESRI LULC katmanlarını
    içeren bir Folium haritası döndürür.
    """
    if not roi_coords:
        return None

    roi = ee.Geometry.Polygon(roi_coords)

    # ROI merkezini hesapla (harita başlangıç konumu)
    centroid = roi.centroid().getInfo()["coordinates"]
    center_lat = centroid[1]
    center_lon = centroid[0]

    # Sentinel-2 koleksiyonu
    S2Collection = (
        ee.ImageCollection("COPERNICUS/S2_HARMONIZED")
        .filterBounds(roi)
        .filterDate(S2_START_DATE, S2_END_DATE)
        .filter(ee.Filter.lt("CLOUDY_PIXEL_PERCENTAGE", CLOUDY_PIXEL_PERCENTAGE))
        .sort("CLOUDY_PIXEL_PERCENTAGE", ascending=True)
    )

    # ESRI LULC koleksiyonu
    esriLULCCollection = ee.ImageCollection("projects/sat-io/open-datasets/landcover/ESRI_Global-LULC_10m_TS").filterDate(
        S2_LULC_START_DATE, S2_LULC_END_DATE
    )
    esriLULCCollection = ee.ImageCollection(esriLULCCollection.mosaic().clip(roi)).map(
        lambda img: ReColormap(img, [1, 2, 4, 5, 7, 8, 9, 10, 11], [1, 2, 3, 4, 5, 6, 7, 8, 9])
    )

    # Bulut maskeleme
    S2Collection = S2Collection.map(ApplyBitwiseS2CloudMask)

    # Alan hesaplama ve MGRS tile eşleştirme
    S2Collection = S2Collection.map(lambda img: CalculateIntersectionArea(img, roi)).sort("INTERSECTION_AREA", False)

    joinCol = ee.Join.saveAll("mgrs_tile_match").apply(
        primary=S2Collection.distinct("MGRS_TILE"),
        secondary=S2Collection,
        condition=ee.Filter.equals(leftField="MGRS_TILE", rightField="MGRS_TILE"),
    )

    bestCollection = ee.ImageCollection(joinCol.map(FilterBestAreaOfMGRSJoin))
    s2Image = bestCollection.mosaic().clip(roi)

    # LULC maskesi: yalnızca geçerli S2 piksellerini göster
    esriLULCImage = esriLULCCollection.first().updateMask(s2Image.select("B4").gt(0))

    # Folium MAP
    fmap = folium.Map(location=[center_lat, center_lon], zoom_start=10, tiles=None)

    # Temel katman
    folium.TileLayer(tiles="https://tile.openstreetmap.org/{z}/{x}/{y}.png", attr="OpenStreetMap", name="OpenStreetMap", show=True).add_to(
        fmap
    )

    folium.TileLayer(
        tiles="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", attr="Esri", name="Esri Uydu"
    ).add_to(fmap)

    # ROI sınırı
    roi_geojson = roi.getInfo()
    folium.GeoJson(roi_geojson, name="Pilot Bölge", style_function=lambda x: {"color": "black", "weight": 2, "fillOpacity": 0}).add_to(fmap)

    # GEE katmanları
    AddGEELayer(fmap, s2Image, S2_VIS_PARAMS, "Sentinel-2 RGB")
    AddGEELayer(fmap, esriLULCImage, {"min": 1, "max": 9, "palette": CLASSES["colors"]}, "ESRI LULC")

    folium.LayerControl(position="bottomleft").add_to(fmap)
    plugins.Fullscreen(position="topright").add_to(fmap)

    return fmap