{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are a lot of satellites gathering a lot of imagery of the earth, day in day out. The government-subsidized and freely available data from Landsat-8 and Sentinel-2 missions have a maximum spatial resolution of 15m ([Landsat-8 panchromatic band](https://en.wikipedia.org/wiki/Landsat_8#Sensors)) and 10m ([Sentinel-2 R/G/B/NIR bands](https://en.wikipedia.org/wiki/Sentinel-2#Instruments)), respectively. Free imagery at such a high resolution is pretty cool!\n",
"\n",
"Sentinel-2 has a revisit time of ~5 days, meaning it will view the same plot of land at about the same angle every 5 days. However, the pointing accuracy is never perfect, so the pixels are never *exactly* in the same place. The question in my mind is: can we use multiple images over time to effectively do \"superresolution\"?\n",
"\n",
"## Getting data\n",
"I'm using [Level-2A data](https://earth.esa.int/web/sentinel/user-guides/sentinel-2-msi/product-types/level-2a) as this gives me Bottom-of-Atmosphere (BOA) reflectance, while the Level-1C product gives Top-of-Atmosphere reflectance. The TOA reflectance is basically what the satellite \"sees\", but can be much more \"hazy\" by going back up through the atmosphere. The BOA reflectance is what we'd estimate the surface reflects, which makes it look less \"hazy\" and will hopefully reduce differences in images a bit.\n",
"\n",
"![L2A illustration](/Sentinel-2-Level-1C-Level-2A-TOA.jpg)\n",
"
*Image from [ESA](https://earth.esa.int/web/sentinel/user-guides/sentinel-2-msi/product-types/level-2a)*\n",
"\n",
"\n",
"\n",
"I obtained this imagery through the app at [Copernicus Open Access Hub](https://scihub.copernicus.eu/dhus/#/home) by manually filtering for imagery with a low cloud percentage, centered over Amsterdam. I chose only full tiles where the satellite has approximately the same viewing and solar angle (the satellite is in sun-synchronous orbit, but the hub might show images one swath to the right or left of your selected location). An API is also provided and might be more convenient for downloading large amounts of data.\n",
"\n",
"I unpacked this data and put it in folder `sentinel/`. The data packages are a bit obtuse but the format is well-described ([naming conventions](https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi/naming-convention), [SAFE format](https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi/data-formats)), and they even include free banners!\n",
"\n",
"![Sentinel banner](/sentinel_banner_2.png)\n",
"
*Free banner included with the free data*"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os, re\n",
"from glob import glob\n",
"from datetime import datetime\n",
"from collections import defaultdict\n",
"\n",
"from IPython.display import Image, display\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import xarray as xr\n",
"import scipy.ndimage\n",
"\n",
"FIGSIZE = (14, 7)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
[120560400 values with dtype=uint16]
array([1])
array([5900035., 5900025., 5900015., ..., 5790265., 5790255., 5790245.])
array([600005., 600015., 600025., ..., 709775., 709785., 709795.])
array([[[[335, 295, 283, ..., 422, 425, 357],\n", " [289, 275, 272, ..., 415, 364, 265],\n", " [291, 255, 270, ..., 392, 398, 357],\n", " ...,\n", " [503, 528, 438, ..., 223, 227, 215],\n", " [502, 536, 503, ..., 208, 205, 207],\n", " [516, 505, 540, ..., 208, 239, 344]],\n", "\n", " [[567, 559, 546, ..., 725, 728, 585],\n", " [568, 540, 521, ..., 720, 644, 397],\n", " [561, 513, 521, ..., 719, 670, 570],\n", " ...,\n", " [758, 705, 651, ..., 430, 435, 448],\n", " [747, 653, 629, ..., 439, 459, 500],\n", " [664, 617, 642, ..., 437, 462, 586]],\n", "\n", " [[367, 341, 313, ..., 497, 479, 442],\n", " [301, 259, 259, ..., 467, 452, 353],\n", " [290, 270, 271, ..., 465, 471, 461],\n", " ...,\n", " [674, 684, 613, ..., 165, 179, 186],\n", " [623, 644, 625, ..., 167, 168, 234],\n", " [650, 701, 730, ..., 146, 220, 369]]],\n", "\n", "\n", " [[[416, 397, 389, ..., 483, 480, 424],\n", " [386, 396, 407, ..., 485, 450, 405],\n", " [399, 372, 401, ..., 456, 444, 441],\n", " ...,\n", " [604, 699, 645, ..., 399, 412, 405],\n", " [708, 681, 673, ..., 412, 412, 425],\n", " [672, 706, 694, ..., 427, 427, 474]],\n", "\n", " [[714, 686, 731, ..., 779, 761, 648],\n", " [753, 744, 727, ..., 776, 698, 559],\n", " [753, 722, 745, ..., 761, 734, 677],\n", " ...,\n", " [805, 838, 780, ..., 599, 607, 595],\n", " [868, 808, 774, ..., 619, 615, 610],\n", " [774, 735, 755, ..., 643, 631, 710]],\n", "\n", " [[386, 377, 375, ..., 465, 454, 415],\n", " [403, 363, 353, ..., 429, 426, 409],\n", " [397, 373, 352, ..., 434, 424, 421],\n", " ...,\n", " [634, 707, 684, ..., 297, 311, 296],\n", " [802, 748, 739, ..., 301, 319, 310],\n", " [736, 777, 821, ..., 319, 344, 469]]],\n", "\n", "\n", " [[[465, 438, 444, ..., 526, 498, 422],\n", " [435, 454, 460, ..., 533, 500, 406],\n", " [434, 465, 454, ..., 561, 569, 514],\n", " ...,\n", " [656, 639, 513, ..., 448, 451, 440],\n", " [747, 764, 656, ..., 448, 457, 469],\n", " [702, 736, 739, ..., 433, 478, 519]],\n", "\n", " [[725, 744, 741, ..., 839, 792, 673],\n", " [738, 744, 761, ..., 849, 775, 626],\n", " [744, 755, 759, ..., 864, 841, 790],\n", " ...,\n", " [897, 813, 685, ..., 718, 718, 686],\n", " [930, 827, 782, ..., 699, 693, 741],\n", " [822, 789, 774, ..., 693, 718, 814]],\n", "\n", " [[491, 456, 456, ..., 711, 627, 486],\n", " [461, 434, 463, ..., 754, 615, 445],\n", " [470, 487, 472, ..., 777, 702, 641],\n", " ...,\n", " [777, 700, 518, ..., 592, 565, 567],\n", " [856, 861, 720, ..., 573, 590, 633],\n", " [858, 841, 818, ..., 551, 683, 711]]],\n", "\n", "\n", " [[[359, 345, 346, ..., 479, 443, 375],\n", " [346, 321, 357, ..., 452, 387, 339],\n", " [342, 325, 346, ..., 451, 446, 448],\n", " ...,\n", " [553, 619, 619, ..., 335, 366, 367],\n", " [547, 598, 645, ..., 361, 371, 412],\n", " [552, 613, 637, ..., 354, 408, 436]],\n", "\n", " [[582, 539, 563, ..., 690, 656, 473],\n", " [545, 549, 569, ..., 626, 558, 398],\n", " [537, 577, 588, ..., 616, 612, 533],\n", " ...,\n", " [771, 742, 725, ..., 561, 589, 566],\n", " [720, 672, 725, ..., 598, 559, 549],\n", " [608, 600, 668, ..., 594, 571, 661]],\n", "\n", " [[425, 372, 347, ..., 601, 553, 433],\n", " [351, 314, 325, ..., 592, 527, 399],\n", " [347, 331, 370, ..., 581, 553, 511],\n", " ...,\n", " [629, 726, 751, ..., 306, 404, 415],\n", " [586, 641, 731, ..., 398, 403, 425],\n", " [576, 666, 666, ..., 420, 448, 541]]],\n", "\n", "\n", " [[[336, 325, 320, ..., 491, 465, 359],\n", " [336, 312, 287, ..., 465, 402, 326],\n", " [325, 336, 350, ..., 473, 452, 408],\n", " ...,\n", " [537, 583, 547, ..., 339, 329, 289],\n", " [577, 597, 640, ..., 290, 300, 339],\n", " [543, 591, 540, ..., 297, 341, 438]],\n", "\n", " [[579, 572, 594, ..., 729, 709, 527],\n", " [604, 589, 597, ..., 689, 581, 430],\n", " [611, 589, 612, ..., 680, 641, 581],\n", " ...,\n", " [734, 783, 739, ..., 556, 563, 540],\n", " [678, 659, 745, ..., 539, 513, 545],\n", " [641, 648, 659, ..., 551, 525, 642]],\n", "\n", " [[453, 414, 365, ..., 659, 626, 499],\n", " [379, 339, 352, ..., 655, 570, 407],\n", " [355, 345, 382, ..., 650, 623, 585],\n", " ...,\n", " [616, 708, 712, ..., 403, 393, 327],\n", " [510, 622, 766, ..., 365, 336, 350],\n", " [618, 722, 744, ..., 356, 350, 505]]],\n", "\n", "\n", " [[[280, 267, 238, ..., 416, 382, 267],\n", " [264, 281, 284, ..., 368, 329, 267],\n", " [271, 310, 316, ..., 401, 368, 372],\n", " ...,\n", " [489, 512, 458, ..., 212, 223, 220],\n", " [451, 521, 605, ..., 227, 224, 341],\n", " [552, 510, 531, ..., 238, 303, 406]],\n", "\n", " [[584, 569, 551, ..., 735, 662, 429],\n", " [576, 544, 544, ..., 670, 545, 374],\n", " [578, 559, 623, ..., 698, 670, 568],\n", " ...,\n", " [715, 726, 691, ..., 456, 443, 444],\n", " [550, 595, 727, ..., 442, 427, 504],\n", " [583, 624, 659, ..., 426, 545, 641]],\n", "\n", " [[332, 278, 246, ..., 505, 467, 337],\n", " [228, 234, 265, ..., 474, 415, 328],\n", " [214, 247, 326, ..., 522, 473, 450],\n", " ...,\n", " [590, 611, 578, ..., 217, 227, 176],\n", " [504, 631, 709, ..., 214, 199, 287],\n", " [637, 691, 630, ..., 200, 301, 457]]]], dtype=uint16)
array([5811455., 5811445., 5811435., ..., 5794975., 5794965., 5794955.])
array(['2019-04-01T10:50:29.000000000', '2019-04-21T10:50:39.000000000',\n", " '2019-07-30T10:50:39.000000000', '2020-03-26T10:46:39.000000000',\n", " '2020-04-05T10:46:19.000000000', '2020-04-15T10:46:19.000000000'],\n", " dtype='datetime64[ns]')
array([621955., 621965., 621975., ..., 640055., 640065., 640075.])
array([2, 3, 4])