Revision 445a6521
Added by Jim Regetz over 13 years ago
- ID 445a65219f854db9720bc2861d377d456587d259
terrain/dem/dem-fusion.txt | ||
---|---|---|
1 |
# Snippets of GDAL commands and R code for processing DEMs |
|
2 |
# Jim Regetz |
|
3 |
# Created on 08-Jun-2011 |
|
4 |
# |
|
5 |
# Note: Working with the original ASTERs yields this warning from GDAL: |
|
6 |
# Warning 1: TIFFReadDirectoryCheckOrder:Invalid TIFF directory; |
|
7 |
# tags are not sorted in ascending order |
|
8 |
# |
|
9 |
# I first ran gdal_translate on each of the ASTERs, then repeated the |
|
10 |
# vrt/warp on those (without warnings), but the output was the same as |
|
11 |
# when I operated on the original files (with warnings), so for the |
|
12 |
# moment I'm just going to ignore the warnings? |
|
13 |
|
|
14 |
#======================================================================= |
|
15 |
# bash -- resample source DEMs into desired grids near the 60N boundary |
|
16 |
#======================================================================= |
|
17 |
|
|
18 |
# generate strips of data along a 40-degree longitudinal extent matching |
|
19 |
# (at least one of) Rick's mosaicked CDEM grids; strips extend 150 |
|
20 |
# pixels south of border and (in case of aster) north of border |
|
21 |
|
|
22 |
# these are currently correct on vulcan |
|
23 |
export ASTDIR="/home/reeves/active_work/EandO/asterGdem" |
|
24 |
export SRTMDIR="/home/reeves/active_work/EandO/CgiarSrtm/SRTM_90m_ASCII_4_1" |
|
25 |
|
|
26 |
# SRTM (also convert to 16bit integer) |
|
27 |
gdalbuildvrt srtm.vrt $SRTMDIR/srtm_*_01.asc |
|
28 |
gdalwarp -ot Int16 -te -136 59.875 -96 60 -ts 48000 150 -r bilinear \ |
|
29 |
srtm.vrt srtm_150below.tif |
|
30 |
|
|
31 |
# ASTER |
|
32 |
gdalbuildvrt aster.vrt $ASTDIR/ASTGTM_N59*W*_dem.tif \ |
|
33 |
$ASTDIR/ASTGTM_N60*W*_dem.tif |
|
34 |
gdalwarp -te -136 59.875 -96 60 -ts 48000 150 -r bilinear \ |
|
35 |
aster.vrt aster_150below.tif |
|
36 |
gdalwarp -te -136 60 -96 60.125 -ts 48000 150 -r bilinear \ |
|
37 |
aster.vrt aster_150above.tif |
|
38 |
|
|
39 |
# note that the top 150 rows of this one are, somewhat surprisingly, |
|
40 |
# slightly different from the above! |
|
41 |
# gdalwarp -te -136 59.875 -96 60.125 -ts 48000 300 -r bilinear \ |
|
42 |
# aster.vrt aster_300straddle.tif |
|
43 |
# |
|
44 |
# and this yields an even different set of values |
|
45 |
# gdalbuildvrt aster_N60.vrt $ASTDIR/ASTGTM_N60*W*_dem.tif |
|
46 |
# gdalwarp -te -136 60 -96 60.125 -ts 48000 150 -r bilinear \ |
|
47 |
# aster_N60.vrt aster_150above.tif |
|
48 |
|
|
49 |
#======================================================================= |
|
50 |
# R -- apply several kinds of boundary fixes and write out new GeoTIFFs |
|
51 |
#======================================================================= |
|
52 |
|
|
53 |
library(raster) |
|
54 |
|
|
55 |
# load relevant SRTM and ASTER data |
|
56 |
srtm.south <- raster("srtm_150below.tif") |
|
57 |
aster.south <- raster("aster_150below.tif") |
|
58 |
aster.north <- raster("aster_150above.tif") |
|
59 |
|
|
60 |
# create difference raster for area of overlap |
|
61 |
delta.south <- srtm.south - aster.south |
|
62 |
|
|
63 |
# |
|
64 |
# OPTION 1 |
|
65 |
# |
|
66 |
|
|
67 |
# smooth to the north, by calculating the deltas _at_ the boundary, |
|
68 |
# ramping them down to zero with increasing distance from the border, |
|
69 |
# and adding them to the north ASTER values |
|
70 |
|
|
71 |
# create simple grid indicating distance (in units of pixels) north from |
|
72 |
# boundary, starting at 1 (this is used for both option 1 and option 2) |
|
73 |
aster.north.matrix <- as.matrix(aster.north) |
|
74 |
ydistN <- nrow(aster.north.matrix) + 1 - row(aster.north.matrix) |
|
75 |
|
|
76 |
# 1b. linear ramp north from SRTM edge |
|
77 |
# -- Rick is doing this -- |
|
78 |
|
|
79 |
# 2b. exponential ramp north from SRTM edge |
|
80 |
# -- Rick is also doing this, but here it is... -- |
|
81 |
r <- -0.045 |
|
82 |
w <- exp(ydistN*r) |
|
83 |
aster.north.smooth <- aster.north |
|
84 |
aster.north.smooth[] <- values(aster.north) + as.integer(round(t(w) * |
|
85 |
as.matrix(delta.south)[1,])) |
|
86 |
writeRaster(aster.north.smooth, file="aster_150above_rampexp.tif") |
|
87 |
|
|
88 |
# |
|
89 |
# OPTION 2 |
|
90 |
# |
|
91 |
|
|
92 |
# smooth to the north, by first using LOESS with values south of 60N to |
|
93 |
# model deltas as a function of observed ASTER, then applying the model |
|
94 |
# to predict pixel-wise deltas north of 60N, then ramping these |
|
95 |
# predicted deltas to zero with increasing distance from the border, and |
|
96 |
# adding them to the associated ASTER values |
|
97 |
|
|
98 |
# first fit LOESS on a random subsample of data |
|
99 |
# note: doing all the data takes too long, and even doing 50k points |
|
100 |
# seems to be too much for calculating SEs during predict step |
|
101 |
set.seed(99) |
|
102 |
samp <- sample(ncell(aster.south), 10000) |
|
103 |
sampdata <- data.frame(delta=values(delta.south)[samp], |
|
104 |
aster=values(aster.south)[samp]) |
|
105 |
lo.byaster <- loess(delta ~ aster, data=sampdata) |
|
106 |
|
|
107 |
# now create ASTER prediction grid north of 60N |
|
108 |
# TODO: deal with NAs in data (or make sure they are passed through |
|
109 |
# properly in the absence of explicit treatment)? |
|
110 |
aster.north.pdelta <- aster.north |
|
111 |
aster.north.pdelta[] <- predict(lo.byaster, values(aster.north)) |
|
112 |
# for actual north ASTER values that exceed the max value used to fit |
|
113 |
# LOESS, just use the prediction associated with the maximum |
|
114 |
aster.north.pdelta[aster.north<min(sampdata$aster)] <- predict(lo.byaster, |
|
115 |
data.frame(aster=min(sampdata$aster))) |
|
116 |
# for actual north ASTER value less than the min value used to fit |
|
117 |
# LOESS, just use the prediction associated with the minimum |
|
118 |
aster.north.pdelta[aster.north>max(sampdata$aster)] <- predict(lo.byaster, |
|
119 |
data.frame(aster=max(sampdata$aster))) |
|
120 |
|
|
121 |
# 2a: exponential distance-weighting of LOESS predicted deltas |
|
122 |
r <- -0.045 |
|
123 |
w <- exp(ydistN*r) |
|
124 |
aster.north.smooth <- aster.north |
|
125 |
aster.north.smooth[] <- values(aster.north) + as.integer(round(t(w * |
|
126 |
as.matrix(aster.north.pdelta)))) |
|
127 |
writeRaster(aster.north.smooth, file="aster_150above_predexp.tif") |
|
128 |
|
|
129 |
# 2b: gaussian distance-weighting of LOESS predicted deltas |
|
130 |
r <- -0.001 # weight drops to 0.5 at ~26 cells, ie 2.4km at 3" res |
|
131 |
w <- exp(-0.001*ydistN^2) |
|
132 |
aster.north.smooth <- aster.north |
|
133 |
aster.north.smooth[] <- values(aster.north) + as.integer(round(t(w * |
|
134 |
as.matrix(aster.north.pdelta)))) |
|
135 |
writeRaster(aster.north.smooth, file="aster_150above_predgau.tif") |
|
136 |
|
|
137 |
# |
|
138 |
# OPTION 3 |
|
139 |
# |
|
140 |
|
|
141 |
# smooth to the south, now by simply taking pixel-wise averages of the |
|
142 |
# observed SRTM and ASTER using a distance-based weighting function such |
|
143 |
# that the relative contribution of ASTER decays to zero over a few km |
|
144 |
|
|
145 |
# create simple grid indicating distance (in units of pixels) south from |
|
146 |
# boundary, starting at 1 |
|
147 |
aster.south.matrix <- as.matrix(aster.south) |
|
148 |
ydistS <- row(aster.south.matrix) |
|
149 |
|
|
150 |
# 3a: gaussian weighting function |
|
151 |
r <- -0.001 # weight drops to 0.5 at ~26 cells, or 2.4km at 3" res |
|
152 |
w <- exp(-0.001*ydistS^2) |
|
153 |
aster.south.smooth <- aster.south |
|
154 |
aster.south.smooth[] <- values(srtm.south) - as.integer(round(t(w * |
|
155 |
as.matrix(delta.south)))) |
|
156 |
aster.south.smooth[aster.south.smooth<0] <- 0 |
|
157 |
writeRaster(aster.south.smooth, file="dem_150below_blendgau.tif") |
|
158 |
|
|
159 |
|
|
160 |
#======================================================================= |
|
161 |
# bash -- fuse DEMS, generate hillshade |
|
162 |
#======================================================================= |
|
163 |
|
|
164 |
# |
|
165 |
# create simple fused layers |
|
166 |
# |
|
167 |
|
|
168 |
# uncorrected fused layer |
|
169 |
gdalwarp -ot Int16 -te -136 59.875 -96 60.125 -ts 48000 300 \ |
|
170 |
srtm_150below.tif aster_150above.tif fused_300straddle.tif |
|
171 |
|
|
172 |
# exponential ramp of boundary delta to the north |
|
173 |
gdalwarp -ot Int16 -te -136 59.875 -96 60.125 -ts 48000 300 \ |
|
174 |
srtm_150below.tif aster_150above_rampexp.tif fused_300straddle_rampexp.tif |
|
175 |
|
|
176 |
# exponential blend of predicted deltas to the north |
|
177 |
gdalwarp -ot Int16 -te -136 59.875 -96 60.125 -ts 48000 300 \ |
|
178 |
srtm_150below.tif aster_150above_predexp.tif fused_300straddle_predexp.tif |
|
179 |
|
|
180 |
# gaussian blend of predicted deltas to the north |
|
181 |
gdalwarp -ot Int16 -te -136 59.875 -96 60.125 -ts 48000 300 \ |
|
182 |
srtm_150below.tif aster_150above_predgau.tif fused_300straddle_predgau.tif |
|
183 |
|
|
184 |
# gaussian blend of SRTM/ASTER to the south |
|
185 |
gdalwarp -ot Int16 -te -136 59.875 -96 60.125 -ts 48000 300 \ |
|
186 |
dem_150below_blendgau.tif aster_150above.tif fused_300straddle_blendgau.tif |
|
187 |
|
|
188 |
# |
|
189 |
# hillshade the different fused DEMs created above |
|
190 |
# |
|
191 |
|
|
192 |
gdaldem hillshade -s 111120 fused_300straddle.tif fused_300straddle_hs.tif |
|
193 |
gdaldem hillshade -s 111120 fused_300straddle_rampexp.tif fused_300straddle_rampexp_hs.tif |
|
194 |
gdaldem hillshade -s 111120 fused_300straddle_predexp.tif fused_300straddle_predexp_hs.tif |
|
195 |
gdaldem hillshade -s 111120 fused_300straddle_predgau.tif fused_300straddle_predgau_hs.tif |
|
196 |
gdaldem hillshade -s 111120 fused_300straddle_blendgau.tif fused_300straddle_blendgau_hs.tif |
|
197 |
|
|
198 |
|
|
199 |
#======================================================================= |
|
200 |
# R -- generate some quick hillshade visuals of a 1-degree wide swath |
|
201 |
#======================================================================= |
|
202 |
|
|
203 |
library(raster) |
|
204 |
|
|
205 |
uncorrected <- raster("fused_300straddle_hs.tif") |
|
206 |
rampexp <- raster("fused_300straddle_rampexp_hs.tif") |
|
207 |
blendgau <- raster("fused_300straddle_blendgau_hs.tif") |
|
208 |
|
|
209 |
window <- extent(-135, -134, 59.875, 60.125) |
|
210 |
|
|
211 |
png("boundary-hillshade.png", height=8, width=8, units="in", res=600) |
|
212 |
par(mfrow=c(3,1)) |
|
213 |
plot(crop(uncorrected, window), main="uncorrected (hillshade)") |
|
214 |
plot(crop(rampexp, window), main="north exponential ramp (hillshade)") |
|
215 |
plot(crop(blendgau, window), main="south gaussian blend (hillshade)") |
|
216 |
dev.off() |
|
217 |
|
Also available in: Unified diff
added GDAL/R code for fusing and correcting DEMs near Canadian border