├── CITATION.cff ├── LICENSE ├── 3D_differencing_python ├── README.md ├── make_list_tiles.py └── post_processing.py ├── 3D_differencing_matlab ├── README.md └── differencing_matlab.m └── README.md /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "If you use this software, please cite it as below." 3 | authors: 4 | - family-names: "Chelsea" 5 | given-names: "Scott" 6 | orcid: https://orcid.org/0000-0002-3884-4693 7 | - family-names: "Phan" 8 | given-names: "Minh" 9 | orcid: https://orcid.org/0000-0002-2806-5450 10 | - family-names: "Nandigam" 11 | given-names: "Viswanath" 12 | orcid: https://orcid.org/0000-0003-0928-9851 13 | - family-names: "Crosby" 14 | given-names: "Christopher" 15 | orcid: https://orcid.org/0000-0003-2522-4193 16 | - family-names: "Arrowsmith" 17 | given-names: "Ramon" 18 | orcid: https://orcid.org/0000-0003-1756-3697 19 | title: "On-Demand 3D topographic differencing implemented in OpenTopography" 20 | version: 1.1.0 21 | date-released: 2020-08-06 22 | repository-code: "https://github.com/OpenTopography/3D_Differencing" 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | COPYRIGHT AND LICENSE 2 | 3 | Copyright (c) 2005-2012 The Regents of the University of California. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or 7 | without modification, are permitted provided that the following 8 | conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above 14 | copyright notice, this list of conditions and the following 15 | disclaimer in the documentation and/or other materials provided 16 | with the distribution. 17 | 18 | 3. All advertising materials mentioning features or use of this 19 | software must display the following acknowledgement: This product 20 | includes software developed by the San Diego Supercomputer Center 21 | , the National Biomedical Computation Resource, and their contributors. 22 | 23 | 4. Neither the names of the Centers nor the names of the contributors 24 | may be used to endorse or promote products derived from this 25 | software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' 28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 30 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS 31 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 32 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 33 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 34 | USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 35 | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 37 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 | POSSIBILITY OF SUCH DAMAGE. 39 | -------------------------------------------------------------------------------- /3D_differencing_python/README.md: -------------------------------------------------------------------------------- 1 | Measuring change at the Earth’s surface: On-Demand vertical and 3D topographic differencing implemented in OpenTopography 2 | 3 | Chelsea Scott: cpscott1@asu.edu(corresponding author) 4 | 5 | Minh Phan, Viswanath Nandigam, Christopher Crosby, Ramon Arrowsmith 6 | 7 | This code performs 3D ICP differencing. It calculates the displacement and rotation required to align windowed subsets of point cloud topography. 8 | 9 | This code has been applied to calculate 3D displacement during the M7 Kumamoto, Japan, earthquake. The data is available here from OpenTopography: 10 | 11 | Pre earthquake topography: 12 | https://portal.opentopography.org/lidarDataset?opentopoID=OTLAS.052018.2444.2 13 | 14 | Post earthquake topography: 15 | https://portal.opentopography.org/lidarDataset?opentopoID=OTLAS.052018.2444.1 16 | 17 | 18 | Instructions: 19 | 20 | 1) Place the compare.las (pre-event) and reference.las (post-event) in the directory las_diff 21 | 22 | 2) Download lastools: https://rapidlasso.com/lastools/ 23 | Then run lastile to tile the datasets. Specify tilesize. For this example, the tile size is 51 m. 24 | 25 | lastile -i compare.las -tile_size 51 -o las_diff/compare 26 | lastile -i reference.las -tile_size 51 -buffer 15 -o las_diff/reference 27 | 28 | 29 | 3) make_list_tiles.y: This script creates tiles.txt which has x, y coordinates of the tiles in common to both datasets. 30 | 31 | 32 | 4) Download and complile LASTools - https://rapidlasso.com/lastools/ 33 | The lasreader from laslib is called in the libICP scripts. 34 | 35 | LibICP was written by Andreas Geiger (https://github.com/symao/libicp) 36 | 37 | We updated demo.cpp and CMakeLists.txt files. OpenTopography's fork of the libicp repo with updates files is here: https://github.com/OpenTopography/libicp 38 | 39 | 5) Postprocessing: post_processing.py 40 | This file reads the disp.txt and outputs geotifs and pngs of the 3D displacements and rotations. 41 | 42 | -------------------------------------------------------------------------------- /3D_differencing_matlab/README.md: -------------------------------------------------------------------------------- 1 | Matlab code and earthquake topography datasets to experiment with ICP 3D differencing 2 | 3 | Contents: Matlab code that performs windowed ICP and plots the results. There are several Matlab files listed in the included Matlab script that must be downloaded from MathWorks. 4 | 5 | To perform the ICP Differencing: 6 | 7 | Download the Matlab script differencing_matlab.m and open in Matlab. 8 | 9 | Download these functions from Mathworks: 10 | 11 | Matlab ICP File Exchange (Jacob Wilm): %https://www.mathworks.com/matlabcentral/fileexchange/27804-iterative-closest-point 12 | 13 | Lasdata File Exchange (Teemu Kumpumäki): %https://www.mathworks.com/matlabcentral/fileexchange/48073-lasdata 14 | 15 | Place the downloaded files in the same directory as differencing_matlab.m. 16 | 17 | Download already processed datasets for the Kumamoto earthquake here: https://cloud.sdsc.edu/v1/AUTH_opentopography/www/shortcourses%2FA2HRT_RCN%2FKumamoto_Lidar.zip or process your own lidar data given the links below. 18 | 19 | Put the downloaded lidar datasets in the same directory as the Matlab scripts. The Matlab ICP differencing script (differencing_matlab.m) assumes that the pre-earthquake file is called 'pre.las' and the post-earthquake file is called 'post.las'. 20 | 21 | Run differencing_matlab.m on Matlab. It will probably take 10-30 minutes depending your computer's processing speeds. When it completes, Matlab will display a vector field map indicating the 3D displacements for the 2016 M7 Kumamoto, Japan. 22 | 23 | To experiment further with ICP, change the sz parameter (Line 40). This is the window size/ resolution used in the ICP calculation. Also change the grd parameter (Line 41). This is spacing between the individual ICP measurements. 24 | 25 | The full Kumamoto datasets are available from OpenTopography here: 26 | 27 | Pre-earthquake: https://portal.opentopography.org/lidarDataset?opentopoID=OTLAS.052018.2444.2 28 | 29 | Post-earthquake: https://portal.opentopography.org/lidarDataset?opentopoID=OTLAS.052018.2444.1 30 | 31 | YouTube video about 3D differencing: https://youtu.be/NtS82yQIITA 32 | 33 | Several references for ICP differencing: 34 | 35 | Presentation slides: https://cloud.sdsc.edu/v1/AUTH_opentopography/www/shortcourses%2FA2HRT_RCN%2FICP_differncing_DEMO.pdf 36 | 37 | Scott et al: (2018): https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/2018JB015581 38 | 39 | Nissen et al: (2014): http://www.sciencedirect.com/science/article/pii/S0012821X14005378 40 | 41 | Nissen et al: (2012): http://onlinelibrary.wiley.com/doi/10.1029/2012GL052460/full 42 | 43 | Funding Acknowledgment: OpenTopography is supported by the National Science Foundation under Award Numbers 1833703, 1833643 & 1833632 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![NSF-1948997](https://img.shields.io/badge/NSF-1948997-blue.svg)](https://nsf.gov/awardsearch/showAward?AWD_ID=1948997) 2 | [![NSF-1948994](https://img.shields.io/badge/NSF-1948994-blue.svg)](https://nsf.gov/awardsearch/showAward?AWD_ID=1948994) 3 | [![NSF-1948857](https://img.shields.io/badge/NSF-1948857-blue.svg)](https://nsf.gov/awardsearch/showAward?AWD_ID=1948857) 4 | 5 | 6 | 7 | Measuring change at the Earth’s surface: On-Demand vertical and 3D topographic differencing implemented in OpenTopography 8 | 9 | Chelsea Scott: cpscott1@asu.edu(corresponding author) 10 | 11 | Minh Phan, Viswanath Nandigam, Christopher Crosby, Ramon Arrowsmith 12 | 13 | A windowed implementation of the iterative closest point (ICP) algorithm is used to calculate displacement and rotation fields from topographic point clouds 14 | that span a geologic event of interest. This technique resolves surface deformation along and adjacent to active faults where other geodetic datasets commonly 15 | lack spatial resolution. 16 | 17 | We provide two sets of codes to perform 3D ICP differencing. 18 | 19 | https://github.com/OpenTopography/3D_Differencing/tree/master/3D_differencing_matlab 20 | This option uses Matlab scripts. The Matlab script is relatively easy to set-up, although it will take a while to complete. 21 | 22 | 23 | https://github.com/OpenTopography/3D-Differencing/tree/master/3D_differencing_python 24 | This option uses Python and c++ functions to perform ICP differencing. The set-up is more involved than for the Matlab option, but the scripts will run much faster. 25 | 26 | 27 | Pre- and post- earthquake topographic datasets for the M7 Kumamoto, Japan, earthquake are available here. 28 | 29 | Pre earthquake topography: 30 | https://portal.opentopography.org/lidarDataset?opentopoID=OTLAS.052018.2444.2 31 | 32 | Post earthquake topography: 33 | https://portal.opentopography.org/lidarDataset?opentopoID=OTLAS.052018.2444.1 34 | 35 | 36 | More information about topographic differencing and the ICP implementation available in: 37 | 38 | Scott, C., Phan, M., Nandigam, V., Crosby, C., and Arrowsmith, J R., 2021, Measuring change at Earth’s surface: On-demand vertical and threedimensional topographic differencing implemented in OpenTopography: Geosphere, v. 17, no. 4, p. 1318–1332, https://doi.org/10.1130/GES02259.1. 39 | 40 | More information about ICP differencing applied to earthquakes is available in these publications: 41 | 42 | Scott, C. P., Arrowsmith, J. R., Nissen, E., Lajoie, L., Maruyama, T., & Chiba, T. (2018). 43 | The M7 2016 Kumamoto, Japan, Earthquake: 3-D Deformation Along the Fault and Within the Damage Zone Constrained From Differential Lidar Topography. Journal of Geophysical Research: Solid Earth. https://doi.org/10.1029/2018JB015581 44 | 45 | Scott, C., Champenois, J., Klinger, Y., Nissen, E., Maruyama, T., Chiba, T., & Arrowsmith, R. (2019). 46 | 2016 M7 Kumamoto, Japan, Earthquake Slip Field Derived From a Joint Inversion of Differential Lidar Topography, Optical Correlation, and InSAR Surface Displacements. 47 | Geophysical Research Letters. https://doi.org/10.1029/2019GL082202 48 | 49 | 50 | -------------------------------------------------------------------------------- /3D_differencing_matlab/differencing_matlab.m: -------------------------------------------------------------------------------- 1 | 2 | % Measuring change at the Earth�s surface: On-Demand vertical and 3D topographic differencing implemented in OpenTopography 3 | % 4 | % Chelsea Scott: cpscott1@asu.edu(corresponding author) 5 | % Minh Phan, Viswanath Nandigam, Christopher Crosby, Ramon Arrowsmith 6 | 7 | % %Copyright (c) 2007 The Regents of the University of California 8 | 9 | %Permission to use, copy, modify, and distribute this software and its documentation for educational, research and non-profit purposes, without fee, and without a written agreement is hereby granted, provided that the above copyright notice, this paragraph and the following three paragraphs appear in all copies. 10 | 11 | % Permission to make commercial use of this software may be obtained 12 | % by contacting: 13 | % Technology Transfer Office 14 | % 9500 Gilman Drive, Mail Code 0910 15 | % University of California 16 | % La Jolla, CA 92093-0910 17 | % (858) 534-5815 18 | % invent@ucsd.edu 19 | 20 | %THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 21 | 22 | %These files must be downloaded from Matlab: 23 | 24 | %Matlab ICP File Exchange (Jacob Wilm): 25 | %https://www.mathworks.com/matlabcentral/fileexchange/27804-iterative-closest-point 26 | 27 | %Lasdata File Exchange (Teemu Kumpum�ki): 28 | %https://www.mathworks.com/matlabcentral/fileexchange/48073-lasdata 29 | 30 | clear all;close all 31 | addpath('lasdata') 32 | 33 | %Edit the first 5 lines 34 | pre_dir='compare.las';%Pre-earthquake las file 35 | post_dir='reference.las';%Post-earthquake las file 36 | sz=51;%Differencing window size 37 | grd=51;%Grid spacing; make equal to sz if time allows 38 | margn=10;%Additional dimension of post-earthquake window. Must be larger than the expect surface displacement 39 | 40 | pre=lasdata(pre_dir);%Read the pre-earthquake las file 41 | pre_x=pre.x;pre_y=pre.y;pre_z=pre.z;%Extract terms from the Matlab structure 42 | 43 | post=lasdata(post_dir);%Read the post-earthquake las file 44 | post_x=post.x;post_y=post.y;post_z=post.z;%Extract terms from the Matlab structure 45 | 46 | %Construct a core point grid for differencing 47 | [core_x,core_y]=meshgrid([min(pre_x):grd:max(pre_x)],[min(pre_y):grd:max(pre_y)]); 48 | core_x=core_x(:);core_y=core_y(:); 49 | 50 | %ICP for loop 51 | for i=1:length(core_x) 52 | clear q* p p_* 53 | m=core_x(i);n=core_y(i); 54 | 55 | % Select points surrounding core point 56 | a=find(pre_x>m-sz/2&pre_xn-sz/2&pre_ym-tz/2&post_xn-tz/2&post_ycompare_las') 42 | os.system('cut -d_ -f 3 compare_las >compare_x') 43 | os.system('cut -d_ -f 4 compare_las >compare_y1') 44 | os.system('cut -d. -f 1 compare_y1 >compare_y') 45 | 46 | #get the reference coordinates of the tiles 47 | os.system('ls las_diff/reference*las >reference_las') 48 | os.system('cut -d_ -f 3 reference_las >reference_x') 49 | os.system('cut -d_ -f 4 reference_las >reference_y1') 50 | os.system('cut -d. -f 1 reference_y1 >reference_y') 51 | 52 | #load in the x, y coordinates of the compare and reference datasets 53 | a = open("compare_x", "r") 54 | compare_x = a.read().splitlines() 55 | a.close() 56 | compare_x=[int(i) for i in compare_x] 57 | 58 | a = open("compare_y", "r") 59 | compare_y = a.read().splitlines() 60 | a.close() 61 | compare_y=[int(i) for i in compare_y] 62 | 63 | a = open("reference_x", "r") 64 | reference_x = a.read().splitlines() 65 | a.close() 66 | reference_x=[int(i) for i in reference_x] 67 | 68 | a = open("reference_y", "r") 69 | reference_y = a.read().splitlines() 70 | a.close() 71 | reference_y=[int(i) for i in reference_y] 72 | 73 | # define the core points 74 | minx=min(compare_x+reference_x) 75 | maxx=max(compare_x+reference_x) 76 | miny=min(compare_y+reference_y) 77 | maxy=max(compare_y+reference_y) 78 | 79 | core_x=list(range(minx,maxx,window_compare)); 80 | core_y=list(range(maxy,miny,-window_compare)); 81 | icp_process1=[1]; 82 | 83 | #write a list of tiles common to both datasets 84 | outF = open("tiles.txt", "w") 85 | 86 | for i in range(1,len(compare_x)): 87 | compare_search_x = compare_x[i]; 88 | compare_search_y = compare_y[i]; 89 | 90 | same_x = np.where(reference_x== np.array(compare_search_x))[0]; 91 | same_y = np.where(reference_y== np.array(compare_search_y))[0]; 92 | same_element = 0; 93 | for p in same_x: 94 | pairs = np.where(p== same_y)[0]; 95 | if len(pairs)>0: 96 | same_element=1 97 | if same_element ==1: 98 | icp_process1.append([compare_search_x, compare_search_y]) 99 | outF.write(str([compare_search_x]).strip('[]')) 100 | outF.write(str(' ')) 101 | outF.write(str([compare_search_y]).strip('[]')) 102 | outF.write("\n") 103 | 104 | outF.close() 105 | -------------------------------------------------------------------------------- /3D_differencing_python/post_processing.py: -------------------------------------------------------------------------------- 1 | # Measuring change at the Earth’s surface: On-Demand vertical and 3D topographic differencing implemented in OpenTopography 2 | # 3 | # Chelsea Scotta: cpscott1@asu.edu(corresponding author) 4 | # Minh Phan, Viswanath Nandigam, Christopher Crosby, Ramon Arrowsmith 5 | 6 | # %Copyright (c) 2007 The Regents of the University of California 7 | 8 | #Permission to use, copy, modify, and distribute this software and its documentation for educational, research and non-profit purposes, without fee, and without a written agreement is hereby granted, provided that the above copyright notice, this paragraph and the following three paragraphs appear in all copies. 9 | 10 | # Permission to make commercial use of this software may be obtained 11 | # by contacting: 12 | # Technology Transfer Office 13 | # 9500 Gilman Drive, Mail Code 0910 14 | # University of California 15 | # La Jolla, CA 92093-0910 16 | # (858) 534-5815 17 | # invent@ucsd.edu 18 | 19 | #THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 20 | 21 | 22 | #!/usr/bin/env python3 23 | # -*- coding: utf-8 -*- 24 | """ 25 | @author: rockhopper 26 | """ 27 | import numpy as np 28 | import matplotlib.pyplot as plt 29 | import statistics 30 | from scipy.interpolate import griddata 31 | from scipy.spatial.transform import Rotation as R 32 | from affine import Affine 33 | import rasterio as rio 34 | from rasterio.crs import CRS 35 | 36 | window_compare=35 # THIS MUST BE DEFINED FROM BEFORE 37 | epsg = 2444; # this needs to be set for individual datasets 38 | 39 | 40 | no_data = -999 # no data value for creating the tiffs. 41 | 42 | 43 | def plot_range(data): 44 | color_range = abs(statistics.median(data)) + abs(1.5*np.percentile(data, 85)) 45 | return color_range 46 | 47 | def plot_png_3d_diff(grid_x, grid_y, points, data_to_grid,name): 48 | 49 | #grid the data. The linear grid help id nan's. 50 | nan_grid = griddata(points, data_to_grid, (grid_x, grid_y), method='linear') 51 | data_grid = griddata(points, data_to_grid, (grid_x, grid_y), method='nearest') 52 | sum_data = np.sum([nan_grid*0,data_grid], axis=0) 53 | 54 | #determine the range for plotting 55 | col_r = plot_range(data_to_grid) 56 | 57 | #make the plot 58 | fig1 = plt 59 | c1 = plt.pcolor(grid_x, grid_y, sum_data,vmin = -col_r, vmax = col_r, cmap = 'bwr_r') 60 | plt.colorbar(c1) 61 | plt.axis('equal') 62 | plt.title(name[0:len(name)-4]) 63 | plt.xlabel("Easting") 64 | plt.ylabel("Northing") 65 | plt.savefig(name) 66 | plt.close() 67 | del fig1, c1 68 | 69 | def prep_for_quiver(points,data,grid_x,grid_y,down_space): 70 | dx_grid = griddata(points, data, (grid_x, grid_y), method='nearest') 71 | dx_grid_small = dx_grid[0:-1:down_space,0:-1:down_space] 72 | dx_grid_small = dx_grid_small.flatten() 73 | return dx_grid_small 74 | 75 | def make_geotiff(grid_x, grid_y, points, data_to_grid,name,epsg_data,no_data): 76 | 77 | #grid the data. The linear grid help id nan's. 78 | nan_grid = griddata(points, data_to_grid, (grid_x, grid_y), method='linear') 79 | data_grid = griddata(points, data_to_grid, (grid_x, grid_y), method='nearest') 80 | sum_data = np.sum([nan_grid*0,data_grid], axis=0) 81 | 82 | #set areas without data and with very large displacements to the no_data value 83 | a = np.isnan(sum_data)*no_data 84 | x_list = np.arange(0,sum_data.flatten().size,1) 85 | b1 = x_list[abs(sum_data.flatten()) > np.median(abs(data_to_grid))*5]; 86 | b2 = x_list[a.flatten()==no_data]; 87 | data_grid_flatten= data_grid.flatten() 88 | data_grid_flatten[b1]=no_data 89 | data_grid_flatten[b2]=no_data 90 | 91 | 92 | #reshape, as expected for geotiffs 93 | data_grid1= data_grid_flatten.reshape( data_grid.shape) 94 | data_grid1_ta=np.rot90(data_grid1) 95 | 96 | #create the affine transform 97 | aff=Affine.translation(min(x)-window_compare/2, max(y)+window_compare/2)*Affine.scale(window_compare,-window_compare) 98 | 99 | #coordinate system for geotiffs 100 | a,b=data_grid1.shape 101 | epsg_code = 'epsg:'+str(epsg_data) 102 | c=CRS.from_dict(init=epsg_code) 103 | 104 | d = {'driver' : 'GTiff','dtype' : 'float64','nodata': no_data, 'width': a+1, 'height' : b+1,'count':1,'crs':c,'transform':aff} 105 | 106 | with rio.open(name, 'w', **d) as outf: 107 | outf.write(data_grid1_ta, 1) 108 | return 109 | 110 | #load the ICP results, saved in disp.txt 111 | disp=np.loadtxt('disp.txt',usecols=range(14)) 112 | x = disp[:,0]+window_compare/2 113 | y = disp[:,1]+window_compare/2 114 | dx = disp[:,2] 115 | dy = disp[:,3] 116 | dz = disp[:,4] 117 | rxx = disp[:,5] 118 | rxy = disp[:,6] 119 | rxz = disp[:,7] 120 | ryx = disp[:,8] 121 | ryy = disp[:,9] 122 | ryz = disp[:,10] 123 | rzx = disp[:,11] 124 | rzy = disp[:,12] 125 | rzz = disp[:,13] 126 | 127 | #make a grid of the x and y displacements 128 | grid_x, grid_y = np.mgrid[min(x):max(x):window_compare, min(y):max(y):window_compare] 129 | A = np.array([x,y]) 130 | points = np.transpose(A) 131 | 132 | #transform the 3x3 rotation matrix to the rotation in x,y,z 133 | x_rot = [] 134 | y_rot = [] 135 | z_rot = [] 136 | 137 | for i in range(len(x)): 138 | a = np.array([ [rxx[i], rxy[i], rxz[i]], [ryx[i], ryy[i], ryz[i]], [rzx[i], rzy[i], rzz[i]]]) 139 | r = R.from_dcm(a) 140 | r1 = r.as_rotvec() 141 | x_rot.append(r1[0]) 142 | y_rot.append(r1[1]) 143 | z_rot.append(r1[2]) 144 | 145 | # make a quiver plot showing the displacements 146 | dx_grid_small = prep_for_quiver(points,dx,grid_x,grid_y,5) 147 | dy_grid_small = prep_for_quiver(points,dy,grid_x,grid_y,5) 148 | dz_grid_small = prep_for_quiver(points,dz,grid_x,grid_y,5) 149 | 150 | grid_x_small = grid_x[0:-1:5,0:-1:5] 151 | grid_y_small = grid_y[0:-1:5,0:-1:5] 152 | grid_x_small = grid_x_small.flatten() 153 | grid_y_small = grid_y_small.flatten() 154 | 155 | horizontal_disp = np.sqrt(dx_grid_small**2 + dy_grid_small**2) 156 | x_list = np.arange(0,grid_x_small.size,1) 157 | a = x_list[ horizontal_disp < np.median(horizontal_disp)*5 ]; 158 | 159 | fig=plt 160 | q = plt.quiver(grid_x_small[a],grid_y_small[a],dx_grid_small[a],dy_grid_small[a]) 161 | plt.quiverkey(q, X=0.3, Y=1.1, U=10,label='Quiver key, length = 4', labelpos='E') 162 | plt.scatter(grid_x_small[a], grid_y_small[a], np.pi*4, dz_grid_small[a] , alpha=0.5,cmap = 'bwr_r') 163 | cbar=plt.colorbar() 164 | cbar.set_label("Vertical Elevation Change") 165 | plt.title("ICP displacements") 166 | plt.xlabel("Easting") 167 | plt.ylabel("Northing") 168 | plt.savefig('3D_displacements') 169 | plt.close() 170 | 171 | #make the displacement plots 172 | plot_png_3d_diff(grid_x, grid_y, points,dx, "dx.png") 173 | plot_png_3d_diff(grid_x, grid_y, points,dy, "dy.png") 174 | plot_png_3d_diff(grid_x, grid_y, points,dz, "dz.png") 175 | 176 | #make the rotation plots 177 | plot_png_3d_diff(grid_x, grid_y, points,np.array(x_rot), "x_rot.png") 178 | plot_png_3d_diff(grid_x, grid_y, points,np.array(y_rot), "y_rot.png") 179 | plot_png_3d_diff(grid_x, grid_y, points,np.array(z_rot), "z_rot.png") 180 | 181 | #make the geotiffs 182 | make_geotiff(grid_x, grid_y, points,dx, "dx.tif",epsg,no_data) 183 | make_geotiff(grid_x, grid_y, points,dy, "dy.tif",epsg,no_data) 184 | make_geotiff(grid_x, grid_y, points,dz, "dz.tif",epsg,no_data) 185 | make_geotiff(grid_x, grid_y, points,np.array(x_rot), "rot_x.tif",epsg,no_data) 186 | make_geotiff(grid_x, grid_y, points,np.array(y_rot), "rot_y.tif",epsg,no_data) 187 | make_geotiff(grid_x, grid_y, points,np.array(z_rot), "rot_z.tif",epsg,no_data) 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | --------------------------------------------------------------------------------