commit 06af1dbb7c4f93c561e7b00d14335b73a1730350 Author: Inex Code Date: Fri Dec 3 23:09:15 2021 +0300 initial commit diff --git a/sat.py b/sat.py new file mode 100644 index 0000000..7fa2228 --- /dev/null +++ b/sat.py @@ -0,0 +1,53 @@ +from PIL import Image +import requests +from sat7_pointer import * + +# Load Landsat 7 band 1, 2, 3 TIF images and create a composite image +# from the three bands. +# +# The composite image is a greyscale image with a red, green and blue +# channel. +# +# The red channel is the red channel of band 3, the green channel is the +# green channel of band 2 and the blue channel is the blue channel of band 1. +# +# The composite image is saved as a PNG file. + +band1 = Image.open('LE07_L1TP_177025_20210723_20210818_02_T1_B1.TIF') +band2 = Image.open('LE07_L1TP_177025_20210723_20210818_02_T1_B2.TIF') +band3 = Image.open('LE07_L1TP_177025_20210723_20210818_02_T1_B3.TIF') + +composite = Image.merge('RGB', (band3, band2, band1)) + +# Load corner coordinates of the image. +# +# The coordinates are stored in a MTL text file. + +mtl_data = load_metadata('LE07_L1TP_177025_20210723_20210818_02_T1_MTL.txt') + +# Fetch coordinates of a city. +# +# The coordinates of a city are fetched from the OpenStreetMap API. +# +# The coordinates are used to calculate the corner coordinates of the +# composite image. +# +# # City is Belgorod, Russia. + +url = 'http://nominatim.openstreetmap.org/search?q=Belgorod,+Russia&format=json' +response = requests.get(url) +data = response.json() + +# Convert bounding box coordinates to image coordinates. + +x0, y1 = lat_lot_to_pixel(data[0]['boundingbox'][0], data[0]['boundingbox'][2], mtl_data) +x1, y0 = lat_lot_to_pixel(data[0]['boundingbox'][1], data[0]['boundingbox'][3], mtl_data) + +print(x0, y0) +print(x1, y1) +print(composite.size) +# Crop the image to the bounding box coordinates. + +cropped = composite.crop((x0, y0, x1, y1)) + +cropped.save('cropped.png') diff --git a/sat7_pointer/__init__.py b/sat7_pointer/__init__.py new file mode 100644 index 0000000..f29beb3 --- /dev/null +++ b/sat7_pointer/__init__.py @@ -0,0 +1,81 @@ +import os +import re +import csv +import pyproj +import math +import numpy as np + +def load_metadata(mtl_file): + mtl_data = {} + with open(mtl_file) as f: + mtl = csv.reader(f, delimiter='=') + try: + for row in mtl: + mtl_data[row[0].strip()] = row[1] + except IndexError: + pass + + mtl_data['width'] = float(mtl_data['REFLECTIVE_SAMPLES']) + mtl_data['height'] = float(mtl_data['REFLECTIVE_LINES']) + + mtl_data['lat_lon_corners'] = np.array([ + [float(mtl_data['CORNER_UL_LAT_PRODUCT']), float(mtl_data['CORNER_UL_LON_PRODUCT']), 0], + [float(mtl_data['CORNER_UR_LAT_PRODUCT']), float(mtl_data['CORNER_UR_LON_PRODUCT']), 0], + [float(mtl_data['CORNER_LR_LAT_PRODUCT']), float(mtl_data['CORNER_LR_LON_PRODUCT']), 0], + [float(mtl_data['CORNER_LL_LAT_PRODUCT']), float(mtl_data['CORNER_LL_LON_PRODUCT']), 0] + ]) + + mtl_data['ecef'] = pyproj.Proj(proj='geocent', ellps='WGS84', datum='WGS84') + mtl_data['lla'] = pyproj.Proj(proj='latlong', ellps='WGS84', datum='WGS84') + + x, y, z = pyproj.transform(mtl_data['lla'], mtl_data['ecef'], + mtl_data['lat_lon_corners'][:, 1], + mtl_data['lat_lon_corners'][:, 0], + mtl_data['lat_lon_corners'][:, 2], + radians=False) + + mtl_data['ecef_corners'] = np.array([x, y, z]).T + + vector_a = mtl_data['vector_a'] = mtl_data['ecef_corners'][1, :] - mtl_data['ecef_corners'][0, :] + vector_b = mtl_data['vector_b'] = mtl_data['ecef_corners'][2, :] - mtl_data['ecef_corners'][0, :] + vector_c = mtl_data['vector_c'] = mtl_data['ecef_corners'][3, :] - mtl_data['ecef_corners'][0, :] + + altitude = mtl_data['altitude'] = 710e3 + vector_s = mtl_data['vector_s'] = (vector_a + vector_c) / 2 - altitude * np.cross(vector_a, vector_c) / np.linalg.norm(np.cross(vector_a, vector_c)) + + b = np.array([vector_b - (vector_a + vector_c)]) + A = np.array([vector_a - vector_s, vector_c - vector_s, vector_b - vector_s]) + mnt = np.linalg.solve(A.T, b.T) + print(mnt) + mtl_data['mu'], mtl_data['nu'] = mnt[0][0], mnt[1][0] + + return mtl_data + +def lat_lot_to_pixel(lat, lon, mtl_data): + target_vector = np.array([lat, lon, 0]) + + x1, y1, z1 = pyproj.transform(mtl_data['lla'], mtl_data['ecef'], + target_vector[1], target_vector[0], target_vector[2], radians=False) + x2, y2, z2 = pyproj.transform(mtl_data['lla'], mtl_data['ecef'], + mtl_data['lat_lon_corners'][0, 1], mtl_data['lat_lon_corners'][0, 0], mtl_data['lat_lon_corners'][0, 2], radians=False) + + x = np.array([x1-x2, y1-y2, z1-z2]) + v = np.cross(mtl_data['vector_c'], mtl_data['vector_a']) + xh = np.divide(np.dot(v.T, x), np.linalg.norm(v)) + x1, y1, z1 = pyproj.transform(mtl_data['lla'], mtl_data['ecef'], + target_vector[1], target_vector[0], -xh, radians=False) + x = np.array([x1-x2, y1-y2, z1-z2]) + A = np.array([ + (1+mtl_data['mu'])*mtl_data['vector_a'] - mtl_data['mu']*mtl_data['vector_s'], + (1+mtl_data['nu'])*mtl_data['vector_c'] - mtl_data['nu']*mtl_data['vector_s'], + x-mtl_data['vector_s'] + ]).T + z = np.linalg.solve(A, x.T) + + k = round(z[0], 4) + r = round(z[1], 4) + + target_x = min([max([1, round(k*mtl_data['width'] + 0.5)]), mtl_data['width']]) + target_y = min([max([1, round(r*mtl_data['height'] + 0.5)]), mtl_data['height']]) + + return target_x, target_y