Skip to content

Commit cb4e447

Browse files
committed
Update sentinel2.py
1 parent 5033b99 commit cb4e447

File tree

1 file changed

+265
-0
lines changed

1 file changed

+265
-0
lines changed

sentinel2.py

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
# IMPORTANT: Make sure you install below packages in advance
2+
#!pip install sentinelsat
3+
#!pip install rasterio
4+
#!apt install gdal-bin python-gdal python3-gdal
5+
#!apt install python3-rtree
6+
#!pip install git+git://github.com/geopandas/geopandas.git
7+
#!pip install descartes
8+
#!pip install shapely
9+
#!pip install six
10+
#!pip install pyproj
11+
#!pip install descartes
12+
#!pip install geopandas
13+
#!pip install folium
14+
15+
import os
16+
import numpy as np
17+
18+
from sentinelsat import SentinelAPI, read_geojson, geojson_to_wkt
19+
from shapely.geometry import MultiPolygon, Polygon
20+
from rasterio.plot import show
21+
from geojson import Polygon
22+
from osgeo import gdal
23+
from PIL import Image, ImageDraw, ImageFont
24+
import geopandas as gpd
25+
import pandas as pd
26+
import numpy as np
27+
import matplotlib.pyplot as plt
28+
import json
29+
import shutil
30+
import glob
31+
32+
import rasterio as rio
33+
import rasterio.mask
34+
import fiona
35+
import folium
36+
import zipfile
37+
38+
from notebook import notebookapp
39+
import urllib
40+
import ipykernel
41+
42+
#Generate coordinate of Area of Interest by using tools from Keene University below
43+
#from IPython.display import HTML
44+
#HTML(r'<iframe width="960" height="480" src="https://www.keene.edu/campus/maps/tool/" frameborder="0"></iframe>')
45+
46+
# Sentinel API credentials
47+
user = 'username'
48+
password = 'password'
49+
api = SentinelAPI(user, password, 'https://scihub.copernicus.eu/dhus')
50+
51+
52+
def sentinel2_hello():
53+
print("Hello from Sentinel2")
54+
return
55+
56+
# (JupyterNotebook only) Get notebookpath
57+
def notebook_path():
58+
"""Returns the absolute path of the Notebook or None if it cannot be determined
59+
NOTE: works only when the security is token-based or there is also no password
60+
"""
61+
connection_file = os.path.basename(ipykernel.get_connection_file())
62+
kernel_id = connection_file.split('-', 1)[1].split('.')[0]
63+
64+
for srv in notebookapp.list_running_servers():
65+
try:
66+
if srv['token']=='' and not srv['password']: # No token and no password, ahem...
67+
req = urllib.request.urlopen(srv['url']+'api/sessions')
68+
else:
69+
req = urllib.request.urlopen(srv['url']+'api/sessions?token='+srv['token'])
70+
sessions = json.load(req)
71+
for sess in sessions:
72+
if sess['kernel']['id'] == kernel_id:
73+
return os.path.join(srv['notebook_dir'],sess['notebook']['path'])
74+
except:
75+
pass # There may be stale entries in the runtime directory
76+
return None
77+
78+
# Convert the Polygon data to GeoJSON format
79+
def Sentinel2_convert_polygon_to_json(object_name, polygon_object):
80+
print("Converting polygon to GeoJSON...")
81+
with open(object_name +'.geojson', 'w') as f:
82+
json.dump(polygon_object, f)
83+
print(object_name +".geojson created")
84+
return
85+
86+
## Get Sentinel Geodataframe
87+
def Sentinel2_get_productsgdf(footprint_geojson, start_date, end_date):
88+
print("Start Date: ", start_date)
89+
print("End Date: ", end_date)
90+
91+
print("Querying Sentinel-2...")
92+
products = api.query(footprint_geojson,
93+
date = (start_date, end_date), #Desired date for the beginning and ending time of Sentinel-2 image
94+
platformname = 'Sentinel-2',
95+
processinglevel = 'Level-2A',
96+
cloudcoverpercentage = (0,70))
97+
98+
products_gdf = api.to_geodataframe(products)
99+
products_gdf_sorted_by_date = products_gdf.sort_values(['ingestiondate'], ascending=[True])
100+
return products_gdf_sorted_by_date
101+
102+
## Get Sentinel all scenes
103+
def Sentinel2_get_all_data(products_gdf, index, fontfile, object_name, start_date, resolution):
104+
print("\n---START---")
105+
products_gdf = products_gdf
106+
107+
title = products_gdf.iloc[index]["title"]
108+
print(" Sentinel-2 title: \t", str(title))
109+
110+
uuid = products_gdf.iloc[index]["uuid"]
111+
product_title = products_gdf.iloc[index]["title"]
112+
113+
ingestion_date = products_gdf.iloc[index]["ingestiondate"].strftime('%Y%m%d-%H:%M')
114+
print(" IngestionDate: \t", ingestion_date)
115+
116+
cloudcoverpercentage = products_gdf.iloc[index]["cloudcoverpercentage"]
117+
print(" Cloud percentage: \t", cloudcoverpercentage)
118+
119+
datasize = products_gdf.iloc[index]["size"]
120+
print(" Data size: \t", datasize)
121+
122+
#Download Sentinel-2 data
123+
print(" Download data now...")
124+
api.download(uuid)
125+
file_name = str(product_title) +'.zip'
126+
print(" Successfully downloaded data as: \t", file_name)
127+
128+
129+
#Extract downloaded Sentinel-2 data
130+
print("\nExtracting data.zip file...")
131+
with zipfile.ZipFile(file_name) as zf:
132+
zf.extractall()
133+
134+
#Get image's folder path
135+
print("\nFile identification...")
136+
print(" Resolution: \t", resolution)
137+
path = str(product_title) + '.SAFE/GRANULE'
138+
files = os.listdir(path)
139+
pathA = str(product_title) + '.SAFE/GRANULE/' + str(files[0])
140+
files2 = os.listdir(pathA)
141+
pathB = str(product_title) + '.SAFE/GRANULE/' + str(files[0]) +'/' + str(files2[1]) +'/R' + resolution + 'm'
142+
files3 = os.listdir(pathB)
143+
144+
145+
path_b2 = str(product_title) + '.SAFE/GRANULE/' + str(files[0]) +'/' + str(files2[1]) +'/R' + resolution + 'm/' +str(files3[0][0:23] +'B02_'+resolution+'m.jp2')
146+
path_b3 = str(product_title) + '.SAFE/GRANULE/' + str(files[0]) +'/' + str(files2[1]) +'/R' + resolution + 'm/' +str(files3[0][0:23] +'B03_'+resolution+'m.jp2')
147+
path_b4 = str(product_title) + '.SAFE/GRANULE/' + str(files[0]) +'/' + str(files2[1]) +'/R' + resolution + 'm/' +str(files3[0][0:23] +'B04_'+resolution+'m.jp2')
148+
149+
print(" ", path_b2)
150+
print(" ", path_b3)
151+
print(" ", path_b4)
152+
153+
#Open Band4(Blue), 3(Green) and 2(Red)
154+
b4 = rio.open(path_b4)
155+
b3 = rio.open(path_b3)
156+
b2 = rio.open(path_b2)
157+
158+
#RGB color compose (output file as GeoTiff: public domain metadata standard which allows georeferencing information to be embedded within a TIFF file)
159+
print("\nRGB Color composing...")
160+
with rio.open(object_name +'.tiff','w',driver='Gtiff', width=b4.width, height=b4.height,
161+
count=3,crs=b4.crs,transform=b4.transform, dtype=b4.dtypes[0]) as rgb:
162+
rgb.write(b4.read(1),1)
163+
rgb.write(b3.read(1),2)
164+
rgb.write(b2.read(1),3)
165+
rgb.close()
166+
167+
#Read polygon from .geojson
168+
nReserve_geo = gpd.read_file(object_name +'.geojson')
169+
170+
# Reference https://rasterio.readthedocs.io/en/latest/api/rasterio.crs.html#module-rasterio.crs
171+
# EPSGの326544というのは、地図投影する際によく利用される、WGS84のUTM座標系のことを表します。
172+
epsg = b4.crs
173+
174+
# Since this RGB image is large and huge you save both computing power and time to clip and use only the area of interest.
175+
# We will clip the Natural reserve area from the RGB image.
176+
nReserve_proj = nReserve_geo.to_crs({'init': str(epsg)})
177+
178+
#Create directory for temporary Masked Tiff
179+
print("Creating directory Image_tiff...")
180+
os.makedirs('./Image_tiff', exist_ok=True)
181+
182+
#Extract image for Area of Interest from the composed color image
183+
print("\nCalculating area of interest...")
184+
with rio.open(object_name +'.tiff') as src:
185+
out_image, out_transform = rio.mask.mask(src, nReserve_proj.geometry,crop=True)
186+
out_meta = src.meta.copy()
187+
out_meta.update({"driver": "GTiff",
188+
"height": out_image.shape[1],
189+
"width": out_image.shape[2],
190+
"transform": out_transform})
191+
192+
with rasterio.open('./Image_tiff/' +'Masked_' + object_name +'.tif', "w", **out_meta) as dest:
193+
dest.write(out_image)
194+
195+
#jpeg processing from the extracted images
196+
scale = '-scale 0 250 0 30'
197+
options_list = [
198+
'-ot Byte',
199+
'-of JPEG',
200+
scale
201+
]
202+
203+
options_string = " ".join(options_list)
204+
205+
#Create directory for jpeg processed image
206+
print("Creating Image_jpeg...")
207+
os.makedirs('./Image_jpeg_'+object_name, exist_ok=True)
208+
209+
#Save jpeg image
210+
#https://pypi.org/project/GDAL/
211+
#GDAL Geospatial Data Abstraction Library
212+
gdal.Translate('./Image_jpeg_'+object_name +'/' + str(ingestion_date) + 'Masked_' +object_name +'.jpg',
213+
'./Image_tiff/Masked_' +object_name +'.tif',
214+
options=options_string)
215+
216+
217+
#Print the ingestion_date on the image
218+
img = Image.open('./Image_jpeg_'+object_name +'/' + str(ingestion_date) + 'Masked_' +object_name +'.jpg')
219+
#print(img.size)
220+
#print(img.size[0])
221+
x = img.size[0]/100 #x coordinate for the print position
222+
y = img.size[1]/100 #y coordinate for the print position
223+
fs = img.size[0]/50 #font size
224+
fs1 = int(fs)
225+
#print(fs1)
226+
#print(type(fs1))
227+
obj_draw = ImageDraw.Draw(img)
228+
obj_font = ImageFont.truetype(fontfile, fs1)
229+
obj_draw.text((x, y), '-- 75 Tahun INDONESIA MERDEKA! --\n' + str(ingestion_date) + 'produced from European Space Agency (ESA) remote sensing data', fill=(255, 255, 255), font=obj_font)
230+
#obj_draw.text((img.size[0]/2, img.size[1]-y - img.size[1]/20 ), 'produced from European Space Agency (ESA) remote sensing data', fill=(255, 255, 255), font=obj_font)
231+
232+
233+
img.save('./Image_jpeg_'+str(object_name) +'/' + str(ingestion_date) + 'Masked_' +object_name +'.jpg')
234+
235+
#Remove downloaded files
236+
print("\nRemoving files...")
237+
shutil.rmtree( str(product_title) + '.SAFE')
238+
os.remove(str(product_title) +'.zip')
239+
240+
print("---DONE---\n")
241+
return
242+
243+
244+
245+
## Get Sentinel satellite scene
246+
def Sentinel2_get_sorted_data(index, fontfile, object_name, footprint_geojson, start_date, end_date, resolution):
247+
print("Querying Sentinel-2...")
248+
products = api.query(footprint_geojson,
249+
date = (start_date, end_date), #Desired date for the beginning and ending time of Sentinel-2 image
250+
platformname = 'Sentinel-2',
251+
processinglevel = 'Level-2A',
252+
cloudcoverpercentage = (0,100))
253+
254+
products_gdf = api.to_geodataframe(products)
255+
256+
257+
#Sort the value of cloud coverage percentage from the small one
258+
print("Sorting data from the lowest Cloud Coverage Percentage...")
259+
products_gdf_sorted = products_gdf.sort_values(['cloudcoverpercentage'], ascending=[True])
260+
print(" Data sorted! Information as follow:")
261+
262+
#Get Sentinel-2 data
263+
Sentinel2_get_all_data(products_gdf_sorted, index, fontfile, object_name, start_date, resolution)
264+
print("Get sorted data finished.")
265+
return

0 commit comments

Comments
 (0)