├── LICENSE.txt ├── lib ├── __init__.py ├── _algorithms.so ├── algorithms.py ├── homura_clean.py └── libgip.so ├── readme.md └── sentinel-util.py /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Development Seed 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developmentseed/sentinel-util/e5b87a6137e329eae1c2da172fc3084574318fd1/lib/__init__.py -------------------------------------------------------------------------------- /lib/_algorithms.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developmentseed/sentinel-util/e5b87a6137e329eae1c2da172fc3084574318fd1/lib/_algorithms.so -------------------------------------------------------------------------------- /lib/algorithms.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by SWIG (http://www.swig.org). 2 | # Version 3.0.12 3 | # 4 | # Do not make changes to this file unless you know what you are doing--modify 5 | # the SWIG interface file instead. 6 | 7 | from sys import version_info as _swig_python_version_info 8 | if _swig_python_version_info >= (2, 7, 0): 9 | def swig_import_helper(): 10 | import importlib 11 | pkg = __name__.rpartition('.')[0] 12 | mname = '.'.join((pkg, '_algorithms')).lstrip('.') 13 | try: 14 | return importlib.import_module(mname) 15 | except ImportError: 16 | return importlib.import_module('_algorithms') 17 | _algorithms = swig_import_helper() 18 | del swig_import_helper 19 | elif _swig_python_version_info >= (2, 6, 0): 20 | def swig_import_helper(): 21 | from os.path import dirname 22 | import imp 23 | fp = None 24 | try: 25 | fp, pathname, description = imp.find_module('_algorithms', [dirname(__file__)]) 26 | except ImportError: 27 | import _algorithms 28 | return _algorithms 29 | try: 30 | _mod = imp.load_module('_algorithms', fp, pathname, description) 31 | finally: 32 | if fp is not None: 33 | fp.close() 34 | return _mod 35 | _algorithms = swig_import_helper() 36 | del swig_import_helper 37 | else: 38 | import _algorithms 39 | del _swig_python_version_info 40 | 41 | try: 42 | _swig_property = property 43 | except NameError: 44 | pass # Python < 2.2 doesn't have 'property'. 45 | 46 | try: 47 | import builtins as __builtin__ 48 | except ImportError: 49 | import __builtin__ 50 | 51 | def _swig_setattr_nondynamic(self, class_type, name, value, static=1): 52 | if (name == "thisown"): 53 | return self.this.own(value) 54 | if (name == "this"): 55 | if type(value).__name__ == 'SwigPyObject': 56 | self.__dict__[name] = value 57 | return 58 | method = class_type.__swig_setmethods__.get(name, None) 59 | if method: 60 | return method(self, value) 61 | if (not static): 62 | if _newclass: 63 | object.__setattr__(self, name, value) 64 | else: 65 | self.__dict__[name] = value 66 | else: 67 | raise AttributeError("You cannot add attributes to %s" % self) 68 | 69 | 70 | def _swig_setattr(self, class_type, name, value): 71 | return _swig_setattr_nondynamic(self, class_type, name, value, 0) 72 | 73 | 74 | def _swig_getattr(self, class_type, name): 75 | if (name == "thisown"): 76 | return self.this.own() 77 | method = class_type.__swig_getmethods__.get(name, None) 78 | if method: 79 | return method(self) 80 | raise AttributeError("'%s' object has no attribute '%s'" % (class_type.__name__, name)) 81 | 82 | 83 | def _swig_repr(self): 84 | try: 85 | strthis = "proxy of " + self.this.__repr__() 86 | except __builtin__.Exception: 87 | strthis = "" 88 | return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) 89 | 90 | try: 91 | _object = object 92 | _newclass = 1 93 | except __builtin__.Exception: 94 | class _object: 95 | pass 96 | _newclass = 0 97 | 98 | import gippy 99 | 100 | def acca(arg1, filename, arg3, arg4, arg5=5, arg6=10, arg7=4000): 101 | """ 102 | acca(GeoImage arg1, std::string filename, float arg3, float arg4, int arg5=5, int arg6=10, int arg7=4000) -> GeoImage 103 | 104 | Parameters 105 | ---------- 106 | arg1: gip::GeoImage const & 107 | filename: std::string 108 | arg3: float 109 | arg4: float 110 | arg5: int 111 | arg6: int 112 | arg7: int 113 | 114 | """ 115 | return _algorithms.acca(arg1, filename, arg3, arg4, arg5, arg6, arg7) 116 | 117 | def fmask(geoimg, filename, arg3=3, arg4=5): 118 | """ 119 | fmask(GeoImage geoimg, std::string filename, int arg3=3, int arg4=5) -> GeoImage 120 | 121 | Parameters 122 | ---------- 123 | geoimg: gip::GeoImage const & 124 | filename: std::string 125 | arg3: int 126 | arg4: int 127 | 128 | """ 129 | return _algorithms.fmask(geoimg, filename, arg3, arg4) 130 | 131 | def cookie_cutter(*args, **kwargs): 132 | """ 133 | cookie_cutter(vector_GeoImage geoimgs, std::string filename, GeoFeature feature, bool crop=False, std::string proj, float xres=1.0, float yres=1.0, int interpolation=0) -> GeoImage 134 | 135 | Parameters 136 | ---------- 137 | geoimgs: std::vector< gip::GeoImage,std::allocator< gip::GeoImage > > const & 138 | filename: std::string 139 | feature: gip::GeoFeature 140 | crop: bool 141 | proj: std::string 142 | xres: float 143 | yres: float 144 | interpolation: int 145 | 146 | """ 147 | return _algorithms.cookie_cutter(*args, **kwargs) 148 | 149 | def indices(*args, **kwargs): 150 | """ 151 | indices(GeoImage geoimg, svector products, std::string filename) -> GeoImage 152 | 153 | Parameters 154 | ---------- 155 | geoimg: gip::GeoImage const & 156 | products: std::vector< std::string,std::allocator< std::string > > 157 | filename: std::string 158 | 159 | """ 160 | return _algorithms.indices(*args, **kwargs) 161 | 162 | def linear_transform(geoimg, coef, filename): 163 | """ 164 | linear_transform(GeoImage geoimg, CImg< float > coef, std::string filename) -> GeoImage 165 | 166 | Parameters 167 | ---------- 168 | geoimg: gip::GeoImage const & 169 | coef: CImg< float > 170 | filename: std::string 171 | 172 | """ 173 | return _algorithms.linear_transform(geoimg, coef, filename) 174 | 175 | def pansharp_brovey(*args, **kwargs): 176 | """ 177 | pansharp_brovey(GeoImage geoimg, GeoImage panimg, CImg< float > weights, std::string filename) -> GeoImage 178 | 179 | Parameters 180 | ---------- 181 | geoimg: gip::GeoImage const & 182 | panimg: gip::GeoImage const & 183 | weights: CImg< float > 184 | filename: std::string 185 | 186 | """ 187 | return _algorithms.pansharp_brovey(*args, **kwargs) 188 | 189 | def rxd(*args, **kwargs): 190 | """ 191 | rxd(GeoImage geoimg, std::string filename) -> GeoImage 192 | 193 | Parameters 194 | ---------- 195 | geoimg: gip::GeoImage const & 196 | filename: std::string 197 | 198 | """ 199 | return _algorithms.rxd(*args, **kwargs) 200 | # This file is compatible with both classic and new-style classes. 201 | 202 | 203 | -------------------------------------------------------------------------------- /lib/homura_clean.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #Custom version of homura that pretty prints the downloading message 3 | from __future__ import print_function, absolute_import 4 | import datetime 5 | import os 6 | import six 7 | import sys 8 | import time 9 | import pycurl 10 | import shutil 11 | from six.moves.urllib.parse import urlparse, unquote as _unquote 12 | from humanize import naturalsize 13 | 14 | try: 15 | import certifi 16 | except ImportError: 17 | certifi = None 18 | 19 | PY3 = sys.version_info[0] == 3 20 | STREAM = sys.stderr 21 | DEFAULT_RESOURCE = 'index.html' 22 | 23 | __version__ = '0.1.5' 24 | 25 | 26 | def eval_path(path): 27 | return os.path.abspath(os.path.expanduser(path)) 28 | 29 | 30 | def utf8_encode(s): 31 | res = s 32 | if isinstance(res, six.text_type): 33 | res = s.encode('utf-8') 34 | return res 35 | 36 | 37 | def utf8_decode(s): 38 | res = s 39 | if isinstance(res, six.binary_type): 40 | res = s.decode('utf-8') 41 | return res 42 | 43 | 44 | def unquote(s): 45 | res = s 46 | if not PY3: 47 | if isinstance(res, six.text_type): 48 | res = s.encode('utf-8') 49 | return _unquote(res) 50 | 51 | 52 | def dict_to_list(d): 53 | return ['%s: %s' % (k, v) for k, v in d.items()] 54 | 55 | 56 | def is_temp_path(path): 57 | if path is None: 58 | return True 59 | else: 60 | path = eval_path(path) 61 | if os.path.isdir(path): 62 | return True 63 | return False 64 | 65 | 66 | def get_resource_name(url): 67 | url = utf8_decode(url) # decode to unicode so PY3's urlparse won't break 68 | o = urlparse(url) 69 | resource = os.path.basename(o.path) 70 | if not resource: 71 | res = DEFAULT_RESOURCE 72 | else: 73 | res = resource 74 | return utf8_decode(unquote(res)) 75 | 76 | 77 | class Homura(object): 78 | progress_template = \ 79 | '%(percent)6d%% %(downloaded)12s %(speed)15s %(eta)18s ETA' + ' ' * 4 80 | eta_limit = 2592000 # 30 days 81 | 82 | def __init__(self, url, path=None, headers=None, session=None, 83 | show_progress=True, resume=True, auto_retry=True, 84 | max_rst_retries=5, pass_through_opts=None, cainfo=None, 85 | user_agent=None, auth=None): 86 | """ 87 | :param str url: URL of the file to be downloaded 88 | :param str path: local path for the downloaded file; if None, it will 89 | be the URL base name 90 | :param dict headers: extra headers 91 | :param session: session used to download (if you want to work with 92 | requests library) 93 | :type session: `class:requests.Session` 94 | :param bool show_progress: whether to show download progress 95 | :param bool resume: whether to resume download (by 96 | filename) 97 | :param bool auto_retry: whether to retry automatically upon closed 98 | transfer until the file's download is finished 99 | :param int max_rst_retries: number of retries upon connection reset by 100 | peer (effective only when `auto_retry` is True) 101 | :param dict pass_through_opts: a dictionary of options passed to cURL 102 | :param str cainfo: optional path to a PEM file containing the CA 103 | certificate 104 | :param str user_agent: set a custom user agent string 105 | :param tuple auth: a tuple of username and password for authentication 106 | :param _final_progress_params: the final progress output 107 | """ 108 | self.url = url # url is in unicode 109 | self.path = self._get_path(path, url) 110 | self.headers = headers 111 | self.session = session 112 | self.show_progress = show_progress 113 | self.resume = resume 114 | self.auto_retry = auto_retry 115 | self.max_rst_retries = max_rst_retries 116 | self.cainfo = cainfo 117 | self.start_time = None 118 | self.content_length = None 119 | self.downloaded = 0 120 | self.auth = None 121 | self._final_progress_params = None 122 | if session: 123 | self.auth = session.auth 124 | if auth: 125 | self.auth = auth 126 | self._path = path # Save given path 127 | self._pycurl = pycurl.Curl() 128 | self._cookie_header = self._get_cookie_header() 129 | self._last_time = 0.0 130 | self._rst_retries = 0 131 | self._pass_through_opts = pass_through_opts 132 | self._user_agent = user_agent or 'homura/' + __version__ 133 | 134 | def _get_cookie_header(self): 135 | if self.session is not None: 136 | cookie = dict(self.session.cookies) 137 | res = [] 138 | for k, v in cookie.items(): 139 | s = '%s=%s' % (k, v) 140 | res.append(s) 141 | if not res: 142 | return None 143 | return '; '.join(res) 144 | 145 | def _get_path(self, path, url): 146 | if path is None: 147 | res = get_resource_name(url) 148 | else: 149 | # decode path to unicode so that os.path.join won't break 150 | res = eval_path(utf8_decode(path)) 151 | if os.path.isdir(res): 152 | resource = get_resource_name(url) 153 | res = os.path.join(res, resource) 154 | return res 155 | 156 | def _get_pycurl_headers(self): 157 | headers = self.headers or {} 158 | if self._cookie_header is not None: 159 | headers['Cookie'] = self._cookie_header 160 | return dict_to_list(headers) or None 161 | 162 | def _fill_in_cainfo(self): 163 | """Fill in the path of the PEM file containing the CA certificate. 164 | 165 | The priority is: 1. user provided path, 2. path to the cacert.pem 166 | bundle provided by certifi (if installed), 3. let pycurl use the 167 | system path where libcurl's cacert bundle is assumed to be stored, 168 | as established at libcurl build time. 169 | """ 170 | if self.cainfo: 171 | cainfo = self.cainfo 172 | else: 173 | try: 174 | cainfo = certifi.where() 175 | except AttributeError: 176 | cainfo = None 177 | if cainfo: 178 | self._pycurl.setopt(pycurl.CAINFO, cainfo) 179 | 180 | def curl(self): 181 | """Sending a single cURL request to download""" 182 | c = self._pycurl 183 | # Resume download 184 | if os.path.exists(self.path) and self.resume: 185 | mode = 'ab' 186 | self.downloaded = os.path.getsize(self.path) 187 | c.setopt(pycurl.RESUME_FROM, self.downloaded) 188 | else: 189 | mode = 'wb' 190 | with open(self.path, mode) as f: 191 | c.setopt(c.URL, utf8_encode(self.url)) 192 | if self.auth: 193 | c.setopt(c.USERPWD, '%s:%s' % self.auth) 194 | c.setopt(c.USERAGENT, self._user_agent) 195 | c.setopt(c.WRITEDATA, f) 196 | h = self._get_pycurl_headers() 197 | if h is not None: 198 | c.setopt(pycurl.HTTPHEADER, h) 199 | c.setopt(c.NOPROGRESS, 0) 200 | c.setopt(pycurl.FOLLOWLOCATION, 1) 201 | c.setopt(c.PROGRESSFUNCTION, self.progress) 202 | self._fill_in_cainfo() 203 | if self._pass_through_opts: 204 | for key, value in self._pass_through_opts.items(): 205 | c.setopt(key, value) 206 | c.perform() 207 | 208 | def start(self): 209 | """ 210 | Start downloading, handling auto retry, download resume and path 211 | moving 212 | """ 213 | if not self.auto_retry: 214 | self.curl() 215 | return 216 | while not self.is_finished: 217 | try: 218 | self.curl() 219 | except pycurl.error as e: 220 | # transfer closed with n bytes remaining to read 221 | if e.args[0] == pycurl.E_PARTIAL_FILE: 222 | pass 223 | # HTTP server doesn't seem to support byte ranges. 224 | # Cannot resume. 225 | elif e.args[0] == pycurl.E_HTTP_RANGE_ERROR: 226 | break 227 | # Recv failure: Connection reset by peer 228 | elif e.args[0] == pycurl.E_RECV_ERROR: 229 | if self._rst_retries < self.max_rst_retries: 230 | pass 231 | else: 232 | raise e 233 | self._rst_retries += 1 234 | else: 235 | raise e 236 | self._move_path() 237 | self._done() 238 | 239 | def progress(self, download_t, download_d, upload_t, upload_d): 240 | self.content_length = self.downloaded + int(download_t) 241 | if int(download_t) == 0: 242 | return 243 | if not self.show_progress: 244 | return 245 | if self.start_time is None: 246 | self.start_time = time.time() 247 | duration = time.time() - self.start_time + 1 248 | speed = download_d / duration 249 | speed_s = naturalsize(speed, binary=True) 250 | speed_s += '/s' 251 | if speed == 0.0: 252 | eta = self.eta_limit 253 | else: 254 | eta = int((download_t - download_d) / speed) 255 | if eta < self.eta_limit: 256 | eta_s = str(datetime.timedelta(seconds=eta)) 257 | else: 258 | eta_s = 'n/a' 259 | downloaded = self.downloaded + download_d 260 | downloaded_s = naturalsize(downloaded, binary=True) 261 | percent = int(downloaded / self.content_length * 100) 262 | params = { 263 | 'downloaded': downloaded_s, 264 | 'percent': percent, 265 | 'speed': speed_s, 266 | 'eta': eta_s, 267 | } 268 | if STREAM.isatty(): 269 | p = (self.progress_template + '\r') % params 270 | STREAM.write(p) 271 | STREAM.flush() 272 | else: 273 | current_time = time.time() 274 | if self._last_time == 0.0: 275 | self._last_time = current_time 276 | 277 | else: 278 | interval = current_time - self._last_time 279 | if interval < 0.5: 280 | return 281 | self._last_time = current_time 282 | #what the final line should be 283 | params['percent']=100 284 | self._final_progress_params=params 285 | 286 | @property 287 | def is_finished(self): 288 | if os.path.exists(self.path): 289 | return self.content_length == os.path.getsize(self.path) 290 | 291 | def _done(self): 292 | p = (self.progress_template) % self._final_progress_params 293 | STREAM.write(p + '\n') 294 | STREAM.flush() 295 | 296 | def _move_path(self): 297 | """ 298 | Move the downloaded file to the authentic path (identified by 299 | effective URL) 300 | """ 301 | if is_temp_path(self._path) and self._pycurl is not None: 302 | eurl = self._pycurl.getinfo(pycurl.EFFECTIVE_URL) 303 | er = get_resource_name(eurl) 304 | r = get_resource_name(self.url) 305 | if er != r and os.path.exists(self.path): 306 | new_path = self._get_path(self._path, eurl) 307 | shutil.move(self.path, new_path) 308 | self.path = new_path 309 | 310 | 311 | def download(url, path=None, headers=None, session=None, show_progress=True, 312 | resume=True, auto_retry=True, max_rst_retries=5, 313 | pass_through_opts=None, cainfo=None, user_agent=None, auth=None): 314 | """Main download function""" 315 | hm = Homura(url, path, headers, session, show_progress, resume, 316 | auto_retry, max_rst_retries, pass_through_opts, cainfo, 317 | user_agent, auth) 318 | hm.start() 319 | -------------------------------------------------------------------------------- /lib/libgip.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developmentseed/sentinel-util/e5b87a6137e329eae1c2da172fc3084574318fd1/lib/libgip.so -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Sentinel Util 2 | Sentinel Util is a command line utility to create a mosaic from Sentinel images. 3 | 4 | ### Install 5 | 1. Install Conda (on linux, use curl -o install ) 6 | 2. Install gcc 7 | 3. Install GDAL and Gippy v1.0.0b8 (and dependencies: swig, g++, etc.) 8 | 3. Make sure the conda installation of python is the default intallation 9 | 4. Download the repo 10 | 11 | ### Use 12 | `python sentinel-util.py out bbox username password [-m mission] [-b beginning] [-e end] [-t type] [-p maxProducts]` 13 | 14 | **out** 15 | The folder where the image file will be written (i.e. ```/path/to/your/folder```). 16 | 17 | **bbox** 18 | Defines the bounding box in the form lat1,lon1,lat2,lon2, where each value is in decimal degrees. lat1 must be greater than lat2 and lon1 must be less than lon2 (i.e. the coordinate lat1,lon1 is the top left corner of the bounding box and lat2,lon2 is the bottom right corner). 19 | 20 | **username** 21 | Your username for Copernicus Open Access Hub. Can be created [here](https://scihub.copernicus.eu/dhus/#/self-registration). 22 | 23 | **password** 24 | Your password for Copernicus Open Access Hub. Can be created [here](https://scihub.copernicus.eu/dhus/#/self-registration). 25 | 26 | **-m mission** 27 | The mission to download images from. 1, 2, or 3. Defaults to 1. 28 | 29 | **-b beginning** 30 | If included, the mosaic will not incorporate images ingested before this date. Of the form yyyy-mm-dd (i.e. 1999-12-31). 31 | 32 | **-e end** 33 | If included, the mosaic will not incorporate images ingested after this date. Of the form yyyy-mm-dd (i.e. 1999-12-31). 34 | 35 | **-t type** 36 | For Sentinel-1 only, defaults to GRD. 37 | 38 | **-p maxProducts** 39 | Default 100. Must be a positive integer ≤ 100. Limits the number of products downloaded.' 40 | 41 | Alternatively, to run in the background and continue even after closing your terminal window (helpful for running on servers), run like ```nohup python sentinel-util.py [args] &``` 42 | ### What will happen 43 | 1. It will download up to 100 products that match the search criteria 44 | 2. Each of the images in the products will be reduced from 16bit to 8bit and switched to WebMercator 45 | 3. All the images will be stitched into a mosaic 46 | -------------------------------------------------------------------------------- /sentinel-util.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import zipfile 4 | 5 | import gippy 6 | import homura 7 | import requests 8 | from osgeo import gdal 9 | 10 | from gippy import algorithms 11 | 12 | MIDNIGHT = 'T00:00:00.000Z' 13 | ABS_START = '2014-01-01T00:00:00.000Z' 14 | INGESTION_KEYWORD = 'ingestiondate' 15 | FOOTPRINT_KEYWORD = 'footprint:"intersects(' 16 | POLYGON_KEYWORD = 'POLYGON((' 17 | CODE_2_MEANING = 'Code 2: invalid arguements' 18 | POINT_DELIM = ', ' 19 | URL_START = 'https://scihub.copernicus.eu/dhus/search?q=' 20 | QUERY_DELIM = ' AND ' 21 | session = requests.Session() 22 | files = [] 23 | PRODUCT_KEYWORD = 'producttype:' 24 | 25 | #TODO: create more catches for invalid agruments 26 | def main(args=None): 27 | print('started') 28 | if args is None: 29 | args = sys.argv 30 | if isinstance(args, str): 31 | args = args.split(' ') 32 | maxRows = '100' 33 | outDir = args[1] #where to put the mosaic 34 | zipDir = outDir + '/zip/' #where to put downloads 35 | unzipDir = outDir + '/unzip/' #where to put working files 36 | 37 | #create directory to store downloads, output, and working files 38 | if not os.path.isdir(outDir): 39 | os.mkdir(outDir) 40 | if not os.path.isdir(zipDir): 41 | os.mkdir(zipDir) 42 | if not os.path.isdir(unzipDir): 43 | os.mkdir(unzipDir) 44 | bbox = args[2] #corners of the bounding box 45 | username = args[3] 46 | password = args[4] 47 | product = 'GRD' 48 | mission = "1" #min sense time 49 | end = "NOW" #max sense time 50 | beginning = ABS_START 51 | 52 | i = 5 #argument index 53 | while i float(lat2): 148 | print("Latitude1 was less than Latitude2") 149 | print(CODE_2_MEANING) 150 | sys.exit(2) 151 | elif not float(lon2) > float(lon1): 152 | print("Longitude2 was less than Longitude1") 153 | print(CODE_2_MEANING) 154 | sys.exit(2) 155 | elif abs(float(lat1)-float(lat2)) > 10: 156 | print("The bbox was taller than 10 degrees") 157 | print(CODE_2_MEANING) 158 | sys.exit(2) 159 | elif abs(float(lon1)-float(lon2)) > 10: 160 | print("The bbox was wider than 10 degrees") 161 | print(CODE_2_MEANING) 162 | sys.exit(2) 163 | cords = [] 164 | cords.append(lat1 + " " + lon1) #top left 165 | cords.append(lat1 + " " + lon2) #top right 166 | cords.append(lat2 + " " + lon2) #bottom right 167 | cords.append(lat2 + " " + lon1) #bottom left 168 | return cords 169 | 170 | 171 | #change from 16bit to 8bit using gdalTranslate, project to EPSG:3857 172 | def warp(filename, dirname): 173 | tempfile = dirname + 'temp_' + filename 174 | filename = dirname + filename 175 | file = gdal.Open(filename) 176 | gdal.Warp(tempfile, file, dstSRS='EPSG:3857') 177 | file = gdal.Open(tempfile) 178 | gdal.Translate(filename, file, outputType=gdal.GDT_Byte) 179 | os.remove(tempfile) 180 | 181 | 182 | if __name__ == "__main__": 183 | try: 184 | main() 185 | except (KeyboardInterrupt): 186 | exit('Received Ctrl + C... Exiting', 1) 187 | 188 | --------------------------------------------------------------------------------