Project

General

Profile

Download (13.5 KB) Statistics
| Branch: | Revision:
1 445a6521 Jim Regetz
# 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
218 7210104d Jim Regetz
219
#=======================================================================
220
# R -- assess boundary artifacts with respect to slope
221
#=======================================================================
222
223
s.aster <- raster("aster_300straddle_s.tif")
224
s.srtm <- raster("srtm_150below_s.tif")
225
s.uncor <- raster("fused_300straddle_s.tif")
226
s.eramp <- raster("fused_300straddle_rampexp_s.tif")
227
s.bg <- raster("fused_300straddle_blendgau_s.tif")
228
s.can <- raster("cdem_300straddle_s.tif")
229
230
231
rmse <- function(r1, r2) {
232
    sqrt(rowMeans(as.matrix((r1 - r2)^2), na.rm=TRUE))
233
}
234
235
pdf("slope-rmse.pdf", height=8, width=11.5)
236
par(mfrow=c(2,3), omi=c(1,1,1,1))
237
lats300 <- yFromRow(s.aster, 1:nrow(s.aster))
238
lats150 <- yFromRow(s.srtm, 1:nrow(s.srtm))
239
# Latitudinal RMSE profiles with respect to ASTER
240
plot(lats300, rmse(s.uncor, s.aster), type="l", xlab="Latitude",
241
    ylab="RMSE", ylim=c(0, 5))
242
lines(lats150, rmse(crop(s.uncor, extent(s.srtm)), s.srtm), col="blue")
243
legend("topright", legend=c("ASTER", "SRTM"), col=c("black", "blue"),
244
    lty=c(1, 1), bty="n")
245
text(min(lats300), 4.5, pos=4, font=3, labels="uncorrected")
246
abline(v=60, col="red", lty=2)
247
mtext("Slope discrepancies with respect to separate ASTER/SRTM components",
248
    adj=0, line=2, font=2)
249
plot(lats300, rmse(s.eramp, s.aster), type="l", xlab="Latitude",
250
    ylab="RMSE", ylim=c(0, 5))
251
lines(lats150, rmse(crop(s.eramp, extent(s.srtm)), s.srtm), col="blue")
252
legend("topright", legend=c("ASTER", "SRTM"), col=c("black", "blue"),
253
    lty=c(1, 1), bty="n")
254
text(min(lats300), 4.5, pos=4, font=3, labels="exponential ramp")
255
abline(v=60, col="red", lty=2)
256
plot(lats300, rmse(s.bg, s.aster), type="l", xlab="Latitude",
257
    ylab="RMSE", ylim=c(0, 5))
258
lines(lats150, rmse(crop(s.bg, extent(s.srtm)), s.srtm), col="blue")
259
legend("topright", legend=c("ASTER", "SRTM"), col=c("black", "blue"),
260
    lty=c(1, 1), bty="n")
261
text(min(lats300), 4.5, pos=4, font=3, labels="gaussian blend")
262
abline(v=60, col="red", lty=2)
263
264
# Latitudinal RMSE profiles with respect to CDEM
265
plot(lats300, rmse(s.uncor, s.can), type="l", xlab="Latitude",
266
    ylab="RMSE", ylim=c(0, 5))
267
text(min(lats300), 4.5, pos=4, font=3, labels="uncorrected")
268
abline(v=60, col="red", lty=2)
269
mtext("Slope discrepancies with respect to Canada DEM",
270
    adj=0, line=2, font=2)
271
plot(lats300, rmse(s.eramp, s.can), type="l", xlab="Latitude",
272
    ylab="RMSE", ylim=c(0, 5))
273
text(min(lats300), 4.5, pos=4, font=3, labels="exponential ramp")
274
abline(v=60, col="red", lty=2)
275
plot(lats300, rmse(s.bg, s.can), type="l", xlab="Latitude",
276
    ylab="RMSE", ylim=c(0, 5))
277
text(min(lats300), 4.5, pos=4, font=3, labels="gaussian blend")
278
abline(v=60, col="red", lty=2)
279
dev.off()
280
281
282
####
283
corByLat <- function(r1, r2, rows) {
284
    if (missing(rows)) {
285
        rows <- 1:nrow(r1)
286
    }
287
    m1 <- as.matrix(r1)
288
    m2 <- as.matrix(r2)
289
    sapply(rows, function(row) cor(m1[row,], m2[row,],
290
        use="pairwise.complete.obs"))
291
}
292
293
pdf("slope-corr.pdf", height=8, width=11.5)
294
par(mfrow=c(2,3), omi=c(1,1,1,1))
295
lats300 <- yFromRow(s.aster, 1:nrow(s.aster))
296
lats150 <- yFromRow(s.srtm, 1:nrow(s.srtm))
297
ylim <- c(0.65, 1)
298
# Latitudinal RMSE profiles with respect to ASTER
299
plot(lats300, corByLat(s.uncor, s.aster), type="l", xlab="Latitude",
300
    ylab="Correlation", ylim=ylim)
301
lines(lats150, corByLat(crop(s.uncor, extent(s.srtm)), s.srtm), col="blue")
302
legend("bottomright", legend=c("ASTER", "SRTM"), col=c("black", "blue"),
303
    lty=c(1, 1), bty="n")
304
text(min(lats300), min(ylim), pos=4, font=3, labels="uncorrected")
305
abline(v=60, col="red", lty=2)
306
mtext("Slope correlations with separate ASTER/SRTM components",
307
    adj=0, line=2, font=2)
308
plot(lats300, corByLat(s.eramp, s.aster), type="l", xlab="Latitude",
309
    ylab="Correlation", ylim=ylim)
310
lines(lats150, corByLat(crop(s.eramp, extent(s.srtm)), s.srtm), col="blue")
311
legend("bottomright", legend=c("ASTER", "SRTM"), col=c("black", "blue"),
312
    lty=c(1, 1), bty="n")
313
text(min(lats300), min(ylim), pos=4, font=3, labels="exponential ramp")
314
abline(v=60, col="red", lty=2)
315
plot(lats300, corByLat(s.bg, s.aster), type="l", xlab="Latitude",
316
    ylab="Correlation", ylim=ylim)
317
lines(lats150, corByLat(crop(s.bg, extent(s.srtm)), s.srtm), col="blue")
318
legend("bottomright", legend=c("ASTER", "SRTM"), col=c("black", "blue"),
319
    lty=c(1, 1), bty="n")
320
text(min(lats300), min(ylim), pos=4, font=3, labels="gaussian blend")
321
abline(v=60, col="red", lty=2)
322
323
# Latitudinal correlation profiles with respect to CDEM
324
plot(lats300, corByLat(s.uncor, s.can), type="l", xlab="Latitude",
325
    ylab="Correlation", ylim=ylim)
326
text(min(lats300), min(ylim), pos=4, font=3, labels="uncorrected")
327
abline(v=60, col="red", lty=2)
328
mtext("Slope correlations with Canada DEM",
329
    adj=0, line=2, font=2)
330
plot(lats300, corByLat(s.eramp, s.can), type="l", xlab="Latitude",
331
    ylab="Correlation", ylim=ylim)
332
text(min(lats300), min(ylim), pos=4, font=3, labels="exponential ramp")
333
abline(v=60, col="red", lty=2)
334
plot(lats300, corByLat(s.bg, s.can), type="l", xlab="Latitude",
335
    ylab="Correlation", ylim=ylim)
336
text(min(lats300), min(ylim), pos=4, font=3, labels="gaussian blend")
337
abline(v=60, col="red", lty=2)
338
dev.off()