Initial commit
This commit is contained in:
23
Flexbrdf/hytools/misc/__init__.py
Normal file
23
Flexbrdf/hytools/misc/__init__.py
Normal file
@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
HyTools: Hyperspectral image processing library
|
||||
Copyright (C) 2021 University of Wisconsin
|
||||
|
||||
Authors: Adam Chlus, Zhiwei Ye, Philip Townsend.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
from .misc import *
|
||||
from .geog_utm import *
|
||||
from .point import *
|
||||
258
Flexbrdf/hytools/misc/geog_utm.py
Normal file
258
Flexbrdf/hytools/misc/geog_utm.py
Normal file
@ -0,0 +1,258 @@
|
||||
|
||||
import numpy as np
|
||||
from types import SimpleNamespace
|
||||
|
||||
NAD83_WGS84_dict = {
|
||||
"a":6378137,
|
||||
"b":6356752.3142,
|
||||
"flat":1/298.257223563,
|
||||
"a_dscp":"Equatorial Radius, meters",
|
||||
"b_dscp":"Polar Radius, meters",
|
||||
"flat_dscp":"Flattening (a-b)/a",
|
||||
}
|
||||
|
||||
NAD83_WGS84_obj = SimpleNamespace(**NAD83_WGS84_dict)
|
||||
|
||||
class BasicMapObj:
|
||||
|
||||
def __init__(self,ellipsoid=NAD83_WGS84_obj,zone=None):
|
||||
|
||||
b=ellipsoid.b
|
||||
a=ellipsoid.a
|
||||
e=np.sqrt(1-b**2/a**2)
|
||||
|
||||
self.b=b
|
||||
self.a=a
|
||||
self.e=e
|
||||
self.ep2=(e*a/b)**2
|
||||
self.n=(a-b)/(a+b)
|
||||
self.k0=0.9996
|
||||
self.easting = 500000
|
||||
self.zone = zone
|
||||
#self.northing = None
|
||||
|
||||
if zone is None:
|
||||
self.lon0=None
|
||||
self.northing = None
|
||||
else:
|
||||
if zone.startswith('326'):
|
||||
zone = zone[3:5] + 'N'
|
||||
self.zone = zone
|
||||
elif zone.startswith('327'):
|
||||
zone = zone[3:5] + 'S'
|
||||
self.zone = zone
|
||||
|
||||
if str(zone)[-1:].isnumeric(): # default is N, not S
|
||||
zone_number = int(zone)
|
||||
self.northing = 0
|
||||
else:
|
||||
zone_number = int(zone[:-1])
|
||||
if zone[-1] in ('N','n'):
|
||||
self.northing = 0
|
||||
elif zone[-1] in ('S','s'):
|
||||
self.northing = 1e7
|
||||
|
||||
self.lon0 = (zone_number - 1)*6 -180 +3 # in Degrees
|
||||
|
||||
def calc_rho(self,lat_rad):
|
||||
a=self.a
|
||||
#b=self.b
|
||||
e=self.e
|
||||
|
||||
return a*(1-e**2)/((1-e**2*(np.sin(lat_rad))**2)**(3/2))
|
||||
|
||||
def calc_nu(self,lat_rad):
|
||||
a=self.a
|
||||
e=self.e
|
||||
return a / (1-(e*np.sin(lat_rad))**2)**0.5
|
||||
|
||||
def calc_p(self,lon_rad):
|
||||
return lon_rad - np.radians(self.lon0)
|
||||
|
||||
def calc_S(self,lat_rad):
|
||||
#S is the meridional arc
|
||||
a=self.a
|
||||
n=self.n
|
||||
a_p = 1 * a * (1 - n + 5/4*(n**2-n**3) + 81/64*(n**4-n**5))
|
||||
b_p = 3/2 * a * n * (1 - n + 7/8*(n**2-n**3) + 55/64*(n**4))
|
||||
c_p = 15/16 * a * (n**2) * (1 - n + 3/4*(n**2-n**3))
|
||||
d_p = 35/48 * a * (n**3) * (1 - n + 11/16*(n**2))
|
||||
e_p = 315/512*a * (n**4) * (1 - n)
|
||||
|
||||
s = a_p*lat_rad \
|
||||
- b_p*np.sin(2*lat_rad) \
|
||||
+ c_p*np.sin(4*lat_rad) \
|
||||
- d_p*np.sin(6*lat_rad) \
|
||||
+ e_p*np.sin(8*lat_rad) \
|
||||
|
||||
return s
|
||||
|
||||
def calc_K3(self,nu,lat_rad):
|
||||
k0 = self.k0
|
||||
ep2 = self.ep2
|
||||
|
||||
k_3 = k0*nu*np.sin(lat_rad)* (np.cos(lat_rad))**3 / 24
|
||||
k_3 *= 5 - (np.tan(lat_rad))**2 + 9 * ep2 * (np.cos(lat_rad))**2 + 4 * (ep2**2) * (np.cos(lat_rad))**4
|
||||
|
||||
return k_3
|
||||
|
||||
def calc_K5(self,nu,lat_rad):
|
||||
k0 = self.k0
|
||||
ep2 = self.ep2
|
||||
|
||||
k_5 = k0 * nu * (np.cos(lat_rad))**3 /6
|
||||
k_5 *= 1 - (np.tan(lat_rad))**2 + ep2 * (np.cos(lat_rad))**2
|
||||
|
||||
return k_5
|
||||
|
||||
def estimate_lon0(self, lon_deg):
|
||||
if self.lon0 is None:
|
||||
major_lon = np.median(lon_deg)
|
||||
central_meridians = np.arange(0,60,1)*6 - 180 +3
|
||||
close_meridian = central_meridians[np.argmin(np.abs(major_lon-central_meridians))]
|
||||
self.lon0 = close_meridian
|
||||
self.zone = int((close_meridian-3 +180)/6)+1 #(zone_number - 1)*6 -180 +3
|
||||
else:
|
||||
#use lon0 during initialization
|
||||
pass
|
||||
|
||||
def estimate_northing(self,lat_deg):
|
||||
if self.northing is None:
|
||||
major_lat = np.median(lat_deg)
|
||||
if major_lat>0:
|
||||
self.northing=0
|
||||
else:
|
||||
self.northing=1e7
|
||||
|
||||
def convert_xycoord(self,lat_deg,lon_deg):
|
||||
lat_rad = np.radians(lat_deg)
|
||||
lon_rad = np.radians(lon_deg)
|
||||
|
||||
self.estimate_lon0(lon_deg)
|
||||
#print(self.lon0)
|
||||
|
||||
self.estimate_northing(lat_deg)
|
||||
|
||||
s = self.calc_S(lat_rad)
|
||||
k0 = self.k0
|
||||
nu = self.calc_nu(lat_rad)
|
||||
p = self.calc_p(lon_rad)
|
||||
|
||||
k_1 = s*k0
|
||||
k_2 = k0*nu*np.sin(2*lat_rad)/4
|
||||
k_3 = self.calc_K3(nu,lat_rad)
|
||||
|
||||
y = k_1 + k_2 * (p**2) + k_3 * (p**4) + self.northing
|
||||
|
||||
k_5 = self.calc_K5(nu,lat_rad)
|
||||
k_4 = k0 * nu * np.cos(lat_rad)
|
||||
|
||||
x = k_4*p + k_5*(p**3)+ self.easting
|
||||
|
||||
return x,y
|
||||
|
||||
########################
|
||||
#https://gdal.org/en/stable/proj_list/transverse_mercator.html
|
||||
# ref: Snyder J.P. (1987) Map projections a working manual, U.S. Geological Survey Professional Paper 1395, 1987. page.61
|
||||
def convert_xycoord_gdal(self, lat_deg,lon_deg):
|
||||
lat_rad = np.radians(lat_deg)
|
||||
lon_rad = np.radians(lon_deg)
|
||||
|
||||
self.estimate_lon0(lon_deg)
|
||||
self.estimate_northing(lat_deg)
|
||||
|
||||
k0 = self.k0
|
||||
E = (self.e)**2
|
||||
p = self.calc_p(lon_rad)
|
||||
cos_lat = np.cos(lat_rad)
|
||||
sin_lat = np.sin(lat_rad)
|
||||
tan_lat = sin_lat / cos_lat
|
||||
tan2_lat = tan_lat**2
|
||||
|
||||
e_p2 = self.ep2
|
||||
|
||||
nu = self.calc_nu(lat_rad)
|
||||
#nu = self.a / np.sqrt(1 - E * sin_lat**2)
|
||||
C = e_p2 * cos_lat**2
|
||||
A = cos_lat * p
|
||||
|
||||
E2=E**2
|
||||
E3=E**3
|
||||
|
||||
M1 = 1 - E / 4 - 3 * E2 / 64 - 5 * E3 / 256
|
||||
M2 = 3 * E / 8 + 3 * E2 / 32 + 45 * E3 / 1024
|
||||
M3 = 15 * E2 / 256 + 45 * E3 / 1024
|
||||
M4 = 35 * E3 / 3072
|
||||
M = self.a * (M1 * lat_rad -
|
||||
M2 * np.sin(2 * lat_rad) +
|
||||
M3 * np.sin(4 * lat_rad) -
|
||||
M4 * np.sin(6 * lat_rad))
|
||||
|
||||
#M = a[(1 - e2/4 - 3e4/64 - 5e6/256 -....)* - (3e2/8 + 3e4/32 + 45e6/1024+....)sin2*
|
||||
#+ (15e4/256 + 45e6/1024 +.....)sin4* - (35e6/3072 + ....)sin6* + .....]
|
||||
|
||||
x = k0 * nu * (A +
|
||||
A**3 / 6 * (1 - tan2_lat + C) +
|
||||
A**5 / 120 * (5 - 18 * tan2_lat + tan2_lat**2 + 72 * C - 58 * e_p2))+ self.easting
|
||||
|
||||
y = k0 * (M + nu * tan_lat * (A**2 / 2 +
|
||||
A**4 / 24 * (5 - tan2_lat + 9 * C + 4 * C**2) +
|
||||
A**6 / 720 * (61 - 58 * tan2_lat + tan2_lat**2 + 600 * C - 330 * e_p2)))+ self.northing
|
||||
|
||||
return x,y
|
||||
|
||||
########################
|
||||
|
||||
def calc_mu(self): #calc_e1_mu(self):
|
||||
e=self.e
|
||||
a=self.a
|
||||
|
||||
mu_recip = a * (1-0.25*(e**2) -3/64*(e**4) -5/256 * (e**6))
|
||||
#e1 = (1 - eee) / (1 + eee) # same as self.n
|
||||
return mu_recip
|
||||
|
||||
# ref : Snyder J.P. (1987) Map projections a working manual, U.S. Geological Survey Professional Paper 1395, 1987. page.63
|
||||
# https://pubs.usgs.gov/pp/1395/report.pdf
|
||||
def convert_latlon(self,x,y):
|
||||
x_in = x - self.easting
|
||||
y_in = y - self.northing
|
||||
|
||||
ep2 = self.ep2
|
||||
a = self.a
|
||||
e =self.e
|
||||
|
||||
k0 = self.k0
|
||||
|
||||
M = y_in / k0
|
||||
|
||||
mu_recip = self.calc_mu() #self.calc_e1_mu()
|
||||
e1=self.n
|
||||
mu = M / mu_recip
|
||||
|
||||
J1 = 3/2 * e1 - 27/32 * (e1**3)
|
||||
J2 = 21/16*(e1**2) -55/32*(e1**4)
|
||||
J3 = 151/96 * (e1**3)
|
||||
J4 = 1097/512 * (e1**4)
|
||||
|
||||
fp = mu + J1*np.sin(2*mu) + J2*np.sin(4*mu) + J3*np.sin(6*mu) + J4*np.sin(8*mu)
|
||||
|
||||
C1 = ep2*(np.cos(fp))**2
|
||||
T1 = (np.tan(fp))**2
|
||||
R1 = a*(1-e**2) / (1-(e*np.sin(fp))**2)**1.5
|
||||
N1 = a / (1-(e*np.sin(fp))**2)**0.5
|
||||
D = x_in / N1 / k0
|
||||
|
||||
Q1 = N1*np.tan(fp)/R1
|
||||
Q2 = D**2 / 2
|
||||
Q3 = (5 + 3*T1 + 10*C1 - 4*C1**2 -9*ep2) * D**4 / 24
|
||||
Q4 = (61 + 90*T1 + 298*C1 +45*T1**2 - 3*C1**2 -252*ep2) * D**6 /720
|
||||
|
||||
lat_out = fp - Q1*(Q2-Q3+Q4)
|
||||
|
||||
Q5 = D
|
||||
Q6 = (1 + 2*T1 + C1) * D**3 / 6
|
||||
Q7 = (5 - 2*C1 + 28*T1 -3*C1**2 + 8*ep2 +24*T1**2) * D**5 / 120
|
||||
|
||||
lon_out = np.radians(self.lon0) + (Q5-Q6+Q7) / np.cos(fp)
|
||||
|
||||
return np.degrees(lat_out), np.degrees(lon_out)
|
||||
86
Flexbrdf/hytools/misc/misc.py
Normal file
86
Flexbrdf/hytools/misc/misc.py
Normal file
@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
HyTools: Hyperspectral image processing library
|
||||
Copyright (C) 2021 University of Wisconsin
|
||||
|
||||
Authors: Adam Chlus, Zhiwei Ye, Philip Townsend.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
from itertools import tee
|
||||
|
||||
def progbar(curr, total, full_progbar = 100):
|
||||
'''Display progress bar.
|
||||
|
||||
Gist from:
|
||||
|
||||
https://gist.github.com/marzukr/3ca9e0a1b5881597ce0bcb7fb0adc549
|
||||
|
||||
Args:
|
||||
curr (int, float): Current task level.
|
||||
total (int, float): Task level at completion.
|
||||
full_progbar (TYPE): Defaults to 100.
|
||||
|
||||
Returns:
|
||||
None.
|
||||
|
||||
'''
|
||||
frac = curr/total
|
||||
filled_progbar = round(frac*full_progbar)
|
||||
print('\r', '#'*filled_progbar + '-'*(full_progbar-filled_progbar), '[{:>7.2%}]'.format(frac), end='')
|
||||
|
||||
|
||||
def pairwise(iterable):
|
||||
a, b = tee(iterable)
|
||||
next(b, None)
|
||||
return zip(a, b)
|
||||
|
||||
def set_brdf(hy_obj,brdf_dict):
|
||||
hy_obj.brdf = brdf_dict
|
||||
|
||||
def set_topo(hy_obj,topo_dict):
|
||||
hy_obj.topo = topo_dict
|
||||
|
||||
def update_brdf(hy_obj,args):
|
||||
hy_obj.brdf[args['key']] = args['value']
|
||||
|
||||
def update_topo(hy_obj,args):
|
||||
hy_obj.topo[args['key']] = args['value']
|
||||
|
||||
def set_glint(hy_obj,glint_dict):
|
||||
|
||||
# If the type is hedley, need to specify deep water area
|
||||
if glint_dict['type'] == 'Hedley':
|
||||
glint_dict['deep_water_sample'] = glint_dict['deep_water_sample'][hy_obj.file_name]
|
||||
|
||||
hy_obj.glint = glint_dict
|
||||
|
||||
def update_topo_group(subgroup_dict_in):
|
||||
|
||||
subgroup_dict = {}
|
||||
group_tag_list=[]
|
||||
|
||||
for file_name in subgroup_dict_in.keys():
|
||||
group_tag = subgroup_dict_in[file_name]
|
||||
if group_tag in subgroup_dict:
|
||||
subgroup_dict[group_tag]+=[file_name]
|
||||
else:
|
||||
subgroup_dict[group_tag]=[file_name]
|
||||
group_tag_list+=[group_tag]
|
||||
|
||||
update_name_list=[]
|
||||
for group_tag in subgroup_dict.keys():
|
||||
update_name_list+=[subgroup_dict[group_tag]]
|
||||
|
||||
return update_name_list,group_tag_list
|
||||
258
Flexbrdf/hytools/misc/point.py
Normal file
258
Flexbrdf/hytools/misc/point.py
Normal file
@ -0,0 +1,258 @@
|
||||
|
||||
import pandas as pd
|
||||
from .geog_utm import *
|
||||
|
||||
def local_transform_all_point(mapobj, point_df, uid, xcoord, ycoord,point_epsg_code):
|
||||
''' Create a dataframe with image georeferenced coordinates of all points of interest
|
||||
|
||||
'''
|
||||
|
||||
if point_epsg_code is None:
|
||||
print("Default latlon")
|
||||
re_df = pd.DataFrame(point_df[[uid,xcoord,ycoord]])
|
||||
re_df.columns = [uid,'img_x','img_y']
|
||||
return re_df
|
||||
else:
|
||||
ycoord_arr = point_df[ycoord]
|
||||
xcoord_arr = point_df[xcoord]
|
||||
lat_arr,lon_arr=mapobj.convert_latlon(xcoord_arr,ycoord_arr)
|
||||
re_df = point_df[[uid, xcoord, ycoord]].join(pd.DataFrame(np.array((lat_arr,lon_arr)).T))
|
||||
re_df.columns=[uid,'img_x','img_y','lat','lon']
|
||||
return re_df
|
||||
|
||||
def get_neighbor(hyObj, point_coord_df, n_neighbor, uid, point_epsg_code,mapobj,use_glt_bool):
|
||||
''' Create a dataframe with columns and lines of all image space neighbors of points of interest
|
||||
|
||||
'''
|
||||
if use_glt_bool:
|
||||
ul_x, new_x_resolution, new_x_rot, ul_y, new_y_rot, new_y_resolution = hyObj.glt_transform
|
||||
print(hyObj.glt_projection,hyObj.glt_map_info)
|
||||
else:
|
||||
ul_x, new_x_resolution, new_x_rot, ul_y, new_y_rot, new_y_resolution = hyObj.transform
|
||||
print(hyObj.projection,hyObj.map_info)
|
||||
|
||||
transform_matrix = np.array([[new_x_resolution, new_x_rot],[new_y_rot, new_y_resolution]])
|
||||
|
||||
if hyObj.map_info[0].startswith("Geographic"):
|
||||
|
||||
if mapobj.zone is None: # Not defined, assume to be geographic from csv / point_df
|
||||
xy_coord_array = point_coord_df[['img_x','img_y']].values-np.array([[ul_x,ul_y]])
|
||||
else: # assume to has both UTM and coord in point_df
|
||||
xy_coord_array = point_coord_df[['lon','lat']].values-np.array([[ul_x,ul_y]])
|
||||
elif hyObj.map_info[0].startswith("UTM"):
|
||||
|
||||
if point_epsg_code is None: # latlon in point, but utm in image
|
||||
img_zone = hyObj.map_info[7]+hyObj.map_info[8][0]
|
||||
img_mapobj = BasicMapObj(zone=img_zone) #NAD83_WGS84_obj,
|
||||
|
||||
x_coord, y_coord = img_mapobj.convert_xycoord_gdal(point_coord_df['img_y'].values, point_coord_df['img_x'].values)
|
||||
xy_coord_array = np.stack((x_coord, y_coord)).T -np.array([[ul_x,ul_y]])
|
||||
else:
|
||||
xy_coord_array = point_coord_df[['img_x','img_y']].values-np.array([[ul_x,ul_y]])
|
||||
|
||||
|
||||
img_loc_array = (xy_coord_array@(np.linalg.inv(transform_matrix).T)).astype(np.int32) # zero-based
|
||||
|
||||
n_neighbor = max(0,n_neighbor)
|
||||
if n_neighbor>=0:
|
||||
|
||||
if n_neighbor==0:
|
||||
offset_arr_col = np.array([[1,0]])
|
||||
offset_arr_row = np.array([[1,0]])
|
||||
uid_list = np.repeat(point_coord_df[uid].values,1)
|
||||
new_uid_list = np.tile([f'_{x}' for x in range(1)],img_loc_array.shape[0])
|
||||
|
||||
if n_neighbor== 4:
|
||||
|
||||
offset_arr_col = np.array([[1,0],
|
||||
[1,0],
|
||||
[1,-1],
|
||||
[1,1],
|
||||
[1,0]])
|
||||
offset_arr_row = np.array([[1,0],
|
||||
[1,-1],
|
||||
[1,0],
|
||||
[1,0],
|
||||
[1,1]])
|
||||
|
||||
uid_list = np.repeat(point_coord_df[uid].values,5)
|
||||
new_uid_list = np.tile([f'_{x}' for x in range(5)],img_loc_array.shape[0])
|
||||
|
||||
if n_neighbor== 8:
|
||||
offset_arr_col = np.array([[1,0],
|
||||
[1,0],
|
||||
[1,-1],
|
||||
[1,1],
|
||||
[1,0],
|
||||
[1,-1],
|
||||
[1,1],
|
||||
[1,-1],
|
||||
[1,1]])
|
||||
offset_arr_row = np.array([[1,0],
|
||||
[1,-1],
|
||||
[1,0],
|
||||
[1,0],
|
||||
[1,1],
|
||||
[1,-1],
|
||||
[1,-1],
|
||||
[1,1],
|
||||
[1,1]])
|
||||
|
||||
uid_list = np.repeat(point_coord_df[uid].values,9)
|
||||
new_uid_list = np.tile([f'_{x}' for x in range(9)],img_loc_array.shape[0])
|
||||
|
||||
img_loc_array_with_nb_col = offset_arr_col@np.vstack([img_loc_array[:,0],np.ones(img_loc_array.shape[0])])
|
||||
img_loc_array_with_nb_row = offset_arr_row@np.vstack([img_loc_array[:,1],np.ones(img_loc_array.shape[0])])
|
||||
new_uid_list = uid_list+new_uid_list
|
||||
|
||||
img_loc_array_with_nb_col = img_loc_array_with_nb_col.T.ravel().astype(np.int32)
|
||||
img_loc_array_with_nb_row = img_loc_array_with_nb_row.T.ravel().astype(np.int32) # zero-based
|
||||
|
||||
return_df = pd.DataFrame({'new_uid':new_uid_list,uid:uid_list,'img_col_glt':img_loc_array_with_nb_col,'img_row_glt':img_loc_array_with_nb_row})
|
||||
|
||||
print('use_glt_bool',use_glt_bool)
|
||||
if use_glt_bool:
|
||||
valid_mask = (img_loc_array_with_nb_col>=0) & (img_loc_array_with_nb_col< hyObj.columns_glt) & (img_loc_array_with_nb_row>=0) & (img_loc_array_with_nb_row< hyObj.lines_glt)
|
||||
|
||||
if valid_mask.sum()==0:
|
||||
print("No valid GLT locations.")
|
||||
return pd.DataFrame()
|
||||
|
||||
return_df = return_df[valid_mask]
|
||||
|
||||
post_glt_col_ind = hyObj.glt_x[(img_loc_array_with_nb_row[valid_mask],img_loc_array_with_nb_col[valid_mask])]-1
|
||||
post_glt_row_ind = hyObj.glt_y[(img_loc_array_with_nb_row[valid_mask],img_loc_array_with_nb_col[valid_mask])]-1 # one-based to zero-based
|
||||
|
||||
return_df["img_col_raw"] = post_glt_col_ind.astype(np.int32)
|
||||
return_df["img_row_raw"] = post_glt_row_ind.astype(np.int32) # zero-based
|
||||
else:
|
||||
return_df["img_col_raw"] = return_df['img_col_glt']
|
||||
return_df["img_row_raw"] = return_df['img_row_glt']
|
||||
|
||||
# check whether points are within the boundary of the image or not
|
||||
return_df = return_df[(return_df['img_col_raw']>=0) & (return_df['img_col_raw']< hyObj.columns) & (return_df['img_row_raw']>=0) & (return_df['img_row_raw']< hyObj.lines)]
|
||||
return return_df
|
||||
|
||||
def add_df_lat_lon(point_coord_neighbor_df, hyObj, mapobj, offset=0.5, use_glt_bool = False):
|
||||
''' Add LAT LON of the points in the dataframe
|
||||
|
||||
'''
|
||||
|
||||
if use_glt_bool:
|
||||
ul_x, new_x_resolution, new_x_rot, ul_y, new_y_rot, new_y_resolution = hyObj.glt_transform
|
||||
else:
|
||||
ul_x, new_x_resolution, new_x_rot, ul_y, new_y_rot, new_y_resolution = hyObj.transform
|
||||
|
||||
transform_matrix = np.array([[new_x_resolution, new_x_rot],[new_y_rot, new_y_resolution]])
|
||||
|
||||
loc_array = point_coord_neighbor_df[['img_col_glt','img_row_glt']].values.transpose() # zero-based
|
||||
|
||||
img_coord_array = np.dot(transform_matrix,loc_array+offset)+np.array([[ul_x],[ul_y]])
|
||||
|
||||
if hyObj.map_info[0].startswith("Geographic"):
|
||||
point_coord_neighbor_df['lat'] = img_coord_array[1,:]
|
||||
point_coord_neighbor_df['lon'] = img_coord_array[0,:]
|
||||
elif hyObj.map_info[0].startswith("UTM"):
|
||||
lat_list,lon_list = mapobj.convert_latlon(img_coord_array[0,:],img_coord_array[1,:])
|
||||
point_coord_neighbor_df['lat'] = lat_list
|
||||
point_coord_neighbor_df['lon'] = lon_list
|
||||
|
||||
|
||||
def subset_band_list(hyObj,spec_df,use_band_list, band_list):
|
||||
|
||||
# do not subset bands, do nothing
|
||||
if use_band_list==False:
|
||||
return spec_df
|
||||
|
||||
# subset bands
|
||||
else:
|
||||
# user does not provide band list, use bad band list as default
|
||||
if len(band_list)==0:
|
||||
# no bad band list in the file, do nothing
|
||||
if not isinstance(hyObj.bad_bands,np.ndarray):
|
||||
return spec_df
|
||||
# use bad band list
|
||||
else:
|
||||
return spec_df.iloc[:,hyObj.bad_bands]
|
||||
# user provides band list
|
||||
else:
|
||||
return spec_df.iloc[:, band_list]
|
||||
|
||||
def local_point2spec(hyObj, point_csv, uid, xcoord, ycoord, point_epsg_code, n_neighbor=4, use_band_list=True, band_list=[],use_glt_bool=False):
|
||||
"""Extract spectra with points in a CSV from the hyperspectral image
|
||||
|
||||
Parameters
|
||||
----------
|
||||
hyObj : HyTools file object
|
||||
point_csv: str
|
||||
full filename of the point CSV
|
||||
uid: str
|
||||
the user specified unique point ID in the CSV
|
||||
xcoord: str
|
||||
the column name in CSV for X coordinate of the points
|
||||
ycoord: str
|
||||
the column name in CSV for Y coordinate of the points
|
||||
point_epsg_code: int
|
||||
EPSG code for the projection of the points, XY coordinates are based on this projection
|
||||
n_neighbor: int
|
||||
default is 4, other options are 0, 8
|
||||
how many neighbors in the image should be sampled from the center
|
||||
use_band_list: boolean
|
||||
default True; whether to use a subset of bands
|
||||
band_list: list or numpy array
|
||||
default is a blank list
|
||||
if it is a list, it should be one like [5,6,7,8,9, 12]
|
||||
if it is a numpy array, it should be the same size as hyObj.bad_bands with only True or False in the array
|
||||
|
||||
use_glt_bool: boolean
|
||||
default False; whether to use geo-lookup table for pixel indexing
|
||||
|
||||
Returns
|
||||
-------
|
||||
point_coord_neighbor_df: pandas dataframe
|
||||
it include all the location and spectra information for all points from the CSV
|
||||
|
||||
"""
|
||||
|
||||
point_df = pd.read_csv(point_csv, sep=',')
|
||||
if point_epsg_code is None:
|
||||
if hyObj.map_info[0].startswith("UTM"):
|
||||
img_zone = hyObj.map_info[7]+hyObj.map_info[8][0]
|
||||
parameter_obj = BasicMapObj(zone=img_zone) #NAD83_WGS84_obj,
|
||||
else:
|
||||
parameter_obj = BasicMapObj() #NAD83_WGS84_obj
|
||||
else:
|
||||
parameter_obj = BasicMapObj(zone=point_epsg_code) #NAD83_WGS84_obj,
|
||||
|
||||
# create a dataframe with image georeferenced coordinates of all points of interest
|
||||
point_coord_df = local_transform_all_point(parameter_obj, point_df, uid, xcoord, ycoord,point_epsg_code)
|
||||
|
||||
# create a dataframe with columns and lines of all image space neighbors of points of interest
|
||||
point_coord_neighbor_df = get_neighbor(hyObj, point_coord_df, n_neighbor, uid,point_epsg_code,parameter_obj,use_glt_bool)
|
||||
|
||||
if point_coord_neighbor_df.shape[0]==0:
|
||||
print("0 point within boundary!\n\n")
|
||||
return None
|
||||
else:
|
||||
# add LAT LON of the points in the dataframe
|
||||
add_df_lat_lon(point_coord_neighbor_df, hyObj,parameter_obj,use_glt_bool=use_glt_bool)
|
||||
|
||||
spec_data = hyObj.get_pixels(point_coord_neighbor_df['img_row_raw'].values,point_coord_neighbor_df['img_col_raw'].values) # zero-based
|
||||
|
||||
# determine the column names of the spectra dataframe based on wavelengths
|
||||
if hyObj.wavelength_units.lower()[:4]=='micr':
|
||||
new_band_name = ['B{:0.3f}'.format(x) for x in hyObj.wavelengths]
|
||||
elif hyObj.wavelength_units.lower()[:4]=='nano' :
|
||||
new_band_name = ['B{:04d}'.format(int(x)) for x in hyObj.wavelengths]
|
||||
else:
|
||||
new_band_name = ['B{:d}'.format(x+1) for x in range(hyObj.bands)]
|
||||
|
||||
spec_df = pd.DataFrame(spec_data, columns=new_band_name)
|
||||
|
||||
# perform the subsetting of the columns in the dataframe according to the band_list or hyObj.bad_bands
|
||||
spec_df = subset_band_list(hyObj,spec_df,use_band_list, band_list)
|
||||
|
||||
point_coord_neighbor_df=point_coord_neighbor_df.reset_index(drop=True)
|
||||
point_coord_neighbor_df = pd.concat([point_coord_neighbor_df,spec_df], axis=1, join='inner')
|
||||
|
||||
return point_coord_neighbor_df
|
||||
Reference in New Issue
Block a user