-
Notifications
You must be signed in to change notification settings - Fork 19
/
gdal-tools.Rmd
2068 lines (1412 loc) · 99.8 KB
/
gdal-tools.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
---
title: "Mastering GDAL Tools (Full Course)"
subtitle: "A practical hands-on introduction to GDAL and OGR command-line programs"
author: "Ujaval Gandhi"
fontsize: 12pt
output:
html_document:
df_print: paged
toc: yes
toc_depth: 3
highlight: pygments
includes:
after_body: comment.html
# pdf_document:
# latex_engine: xelatex
# toc: yes
# toc_depth: 3
# word_document:
# toc: yes
# toc_depth: '3'
header-includes:
- \usepackage{fancyhdr}
- \pagestyle{fancy}
- \renewcommand{\footrulewidth}{0.4pt}
- \fancyhead[LE,RO]{\thepage}
- \geometry{left=1in,top=0.75in,bottom=0.75in}
- \fancyfoot[CE,CO]{{\includegraphics[height=0.5cm]{images/cc-by-nc.png}} Ujaval Gandhi http://www.spatialthoughts.com}
classoption: a4paper
---
\newpage
***
```{r echo=FALSE, fig.align='center', out.width='250pt'}
knitr::include_graphics('images/spatial_thoughts_logo.png')
```
***
\newpage
# Introduction
[GDAL](https://gdal.org/) is an open-source library for raster and vector geospatial data formats. The library comes with a vast collection of utility programs that can perform many geoprocessing tasks. This class introduces GDAL and OGR utilities with example workflows for processing raster and vector data. The class also shows how to use these utility programs to build Spatial ETL pipelines and do batch processing.
[![Watch the video](https://img.youtube.com/vi/72WVyc8Jtz4/mqdefault.jpg)](https://www.youtube.com/watch?v=72WVyc8Jtz4&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=2){target="_blank"}
[Watch the Video ↗](https://www.youtube.com/watch?v=72WVyc8Jtz4&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=2){target="_blank"}
[Access the Presentation ↗](https://docs.google.com/presentation/d/1JvGjb5eNM9F--zfyTFAeAk0R5UG6weFpOUVDVkJSnho/edit?usp=sharing){target="_blank"}
# Setting up the Environment
This course requires installing the GDAL package. Along with GDAL, we highly recommend installing QGIS to view the result of the command-line operations. You will find installation instructions for both the software below.
## Install GDAL
The preferred method for installing the GDAL Tools is via Anaconda. Follow these steps to install Anaconda and the GDAL library.
[Download the Anaconda Installer](https://www.anaconda.com/products/individual) for Python 3.7 (or a higher version) for your operating system. Once downloaded, double click the installer and install it into the default suggested directory.
*Note: If your username has spaces, or non-English characters, it causes problems. In that case, you can install it to a path such as `C:\anaconda`.*
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/conda.png')
```
### Windows
Once Anaconda installed, search for *Anaconda Prompt* in the Start Menu and launch a new window.
1. Create a new environment named `gdal`. When prompted to confirm, type `y` and press *Enter*.
```
conda create --name gdal
```
> Note: You can select *Right Click → Paste* to paste commands in Anaconda Prompt.
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/condawin1.png')
```
2. Activate the environment and install the `gdal` package along with the jp2 format driver `libgdal-jp2openjpeg`. . When prompted to confirm, type `y` and press *Enter*.
```
conda activate gdal
conda install -c conda-forge gdal libgdal-jp2openjpeg
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/condawin2.png')
```
3. Once the installation finishes, verify if you are able to run the GDAL tools. Type the following command and check if a version number is printed.
```
gdalinfo --version
```
> The version number displayed for you may be slightly different. As long as you do not get a `command not found` error, you should be set for the class.
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/condawin3.png')
```
### Mac/Linux
Once Anaconda is installed, launch a *Terminal* window.
1. Create a new environment named `gdal`. When prompted to confirm, type `y` and press *Enter*.
```
conda create --name gdal
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/condamac1.png')
```
2. Activate the environment and install the `gdal` package, along with the jp2 format driver `libgdal-jp2openjpeg`. When prompted to confirm, type `y` and press *Enter*.
```
conda activate gdal
conda install -c conda-forge gdal libgdal-jp2openjpeg
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/condamac2.png')
```
3. Once the installation finishes, verify if you are able to run the GDAL tools. Type the following command and check if a version number is printed.
```
gdalinfo --version
```
> The version number displayed for you may be slightly different. As long as you do not get a `command not found` error, you should be set for the class.
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/condamac3.png')
```
### Google Colab Notebook [Optional]
We also provide a Google Colab Notebook for the course that allows you to run all the workflows in the cloud without the need to install any packages or download any datasets. You may use this as an alternative environment if you cannot install the software on your machine due to security restrictions.
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/spatialthoughts/courses/blob/master/code/gdal/mastering_gdal_tools.ipynb){target="_blank"}
## Install QGIS
This course uses QGIS LTR version for visualization of results. It is not mandatory to install QGIS, but highly recommended.
Please review [QGIS-LTR Installation Guide](install-qgis-ltr.html) for step-by-step instructions.
# Download the Data Package
The code examples in this class use a variety of datasets. All the required datasets are supplied to you in the ``gdal_tools.zip`` file. Unzip this file to the `Downloads` directory. All commands below assume the data is available in the ``<home folder>/Downloads/gdal_tools/`` directory.
Download [gdal-tools.zip](https://github.com/spatialthoughts/courses/releases/download/data/gdal-tools.zip).
> Note: Certification and Support are only available for participants in our paid instructor-led classes.
# Get the Course Videos
The course is accompanied by a set of videos covering the all the modules. These videos are recorded from our live instructor-led classes and are edited to make them easier to consume for self-study. We have 2 versions of the videos:
## YouTube
We have created a YouTube Playlist with separate videos for each section and exercise to enable effective online-learning. [Access the YouTube Playlist ↗](https://www.youtube.com/playlist?list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK){target="_blank"}
## Vimeo
We are also making combined full-length video for each module available on Vimeo. These videos can be downloaded for offline learning. [Access the Vimeo Playlist ↗](https://vimeo.com/showcase/11112911){target="_blank"}
# Getting Familiar with the Command Prompt
All the commands in the exercises below are expected to be run from the *Anaconda Prompt* on Windows or a *Terminal* on Mac/Linux. We will now cover basic terminal commands that will help you get comfortable with the environment
### Windows
| **Command** | **Description** | **Example** |
|:-----------------|:------------------------------------|:---------------------|
| `cd` | Change directory | `cd Downloads\gdal-tools` |
| `cd ..` | Change to the parent directory | `cd ..` |
| `dir` | List files in the current directory | `dir` |
| `del` | Delete a file | `del test.txt` |
| `rmdir` | Delete a directory | `rmdir /s test` |
| `mkdir` | Create a directory | `mkdir test` |
| `type` | Print the contents of a file | `type test.txt` |
| `> output.txt` | Redirect the output to a file | `dir /b > test.txt` |
| `cls` | Clear screen | `cls` |
### Mac/Linux
| **Command** | **Description** | **Example** |
|:-----------------|:------------------------------------|:---------------------|
| `cd` | Change directory | `cd Downloads/gdal-tools` |
| `cd ..` | Change to the parent directory | `cd ..` |
| `ls` | List files in the current directory | `ls` |
| `rm ` | Delete a file | `rm test.txt` |
| `rm -R` | Delete a directory | `rm -R test` |
| `mkdir` | Create a directory | `mkdir test` |
| `cat` | Print the contents of a file | `cat test.txt` |
| `> output.txt` | Redirect the output to a file | `ls > test.txt` |
| `clear` | Clear screen | `clear` |
# 1. GDAL Tools
[![Start Module Videos](https://img.youtube.com/vi/QMJR6JCogDk/mqdefault.jpg)](https://www.youtube.com/watch?v=QMJR6JCogDk&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=6){target="_blank"}
[Start Module Videos ↗](https://www.youtube.com/watch?v=QMJR6JCogDk&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=6){target="_blank"}
## 1.1 Basic Raster Processing
We will start learning the basic GDAL commands by processing elevation rasters from SRTM. In the *Command Prompt* window, use the `cd` command to change to the `srtm` directory which 4 individual SRTM tiles around the Mt. Everest region.
```
cd srtm
```
Use the `gdalinfo` command to check the information about a single image.
```
gdalinfo N28E086.hgt
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/gdalinfo1.png')
```
A useful parameter is `-stats` which computes and displays image statistics. Run it on the raster to get some statistics of pixel values in the image.
```
gdalinfo -stats N28E086.hgt
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/gdalinfo2.png')
```
### 1.1.1 Merging Tiles
We will now merge the 4 neighboring SRTM tiles into 1 raster so we can work with them together. GDAL provides a useful format called [Virtual Raster](https://gdal.org/drivers/raster/vrt.html) that allows us to create a *Virtual* file with `.vrt` extension that is a pointer to multiple source files. A `.vrt` file is just a text file, so it doesn't consume any disk space but allows us to run any GDAL command as if it was a raster file.
First we need to create a text file containing all the files we want to merge. We can use the `dir` command on Command prompt to list the files matching the pattern `*.hgt` and redirect the output to a file. Here the `/b` option runs the command in the *Bare* mode which excludes all info except file names.
**Windows**
```
dir /b *.hgt > filelist.txt
```
For Mac/Linux systems, the same can be achieved using the `ls` command.
**Mac/Linux**
```
ls *.hgt > filelist.txt
```
Once the command finishes, verify that the `filelist.txt` has the names of the source tiles.
```{r echo=FALSE, fig.align='center', out.width='50%'}
knitr::include_graphics('images/gdal/merging1.png')
```
We can now use the `gdalbuildvrt` program to create a virtual raster from the source files in the `filelist.txt`.
```
gdalbuildvrt -input_file_list filelist.txt merged.vrt
```
```{r echo=FALSE, fig.align='center', out.width='100%'}
knitr::include_graphics('images/gdal/merging2.png')
```
> Note: We could have done this operation in a single step using the command `gdalbuildvrt merged.vrt *.hgt`. However, some versions of GDAL on Windows do not expand the `*` wildcard correctly and the command results in an error. It is recommended to use a file list instead of wildcards with GDAL commands on Windows to avoid unexpected results.[[reference](https://github.com/OSGeo/gdal/issues/1749)]
### Exercise 1
Can you find what is the highest elevation value in the merged raster? Since these rasters are around the Mt.Everest region, the *MAXIMUM* value will be the elevation of the summit.
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/exercise1.png')
```
### 1.1.2 Converting Formats
Let's convert the *Virtual Raster* to a GeoTIFF file. `gdal_translate` program allows us to convert between any of the hundreds of data formats supported by GDAL. The format is recognized from the file extension. Alternatively, you can also specify it using the `-of` option with the [short name of the format](https://gdal.org/drivers/raster/index.html) such a **GTiff**.
```
gdal_translate -of GTiff merged.vrt merged.tif
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/compression1.png')
```
### 1.1.3 Compressing Output
[![Watch the video](https://img.youtube.com/vi/9iG7uormxPk/mqdefault.jpg)](https://www.youtube.com/watch?v=9iG7uormxPk&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=11){target="_blank"}
[Watch the Video ↗](https://www.youtube.com/watch?v=9iG7uormxPk&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=11){target="_blank"}
[Access the Presentation ↗](https://docs.google.com/presentation/d/1WMl2nkUS4fl2qJjPsi5s2X_ST1BXuEFiVQhg0BRf1EI/edit?usp=sharing){target="_blank"}
The default output GeoTIFF file is uncompressed - meaning each pixel's value is stored on the disk without any further processing. For large rasters, this can consume a lot of disk space. A smart approach is to use a lossless compression algorithm to reduce the size of the raster while maintaining full fidelity of the original data. GDAL supports many compression algorithms out-of-the-box and can be specified with GDAL commands using the `-co` option. The most popular loss-less compression algorithms are **DEFLATE**, **LZW** and **PACKBITS**. We can try the `DEFLATE` algorithm on our dataset.
```
gdal_translate -of GTiff merged.vrt merged.tif -co COMPRESS=DEFLATE
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/compression2.png')
```
The uncompressed file size was **100+ MB**. After applying the *DEFLATE* compression, the file size was reduced to **75MB**. We can further reduce the file size by specifying additional options. The `PREDICTOR` option helps compress data better when the neighboring values are correlated. For elevation data, this is definitely the case. The `TILED` option will compress the data in blocks rather than line-by-line.
> Note: You can split long commands into multiple lines using the line-continuation character. Windows shell uses `^` as the line-continuation, while Mac/Linux shells use `\` as the line continuation.
**Windows**
```
gdal_translate -of GTiff merged.vrt merged.tif ^
-co COMPRESS=DEFLATE -co TILED=YES -co PREDICTOR=2
```
**Mac/Linux**
```
gdal_translate -of GTiff merged.vrt merged.tif \
-co COMPRESS=DEFLATE -co TILED=YES -co PREDICTOR=2
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/compression3.png')
```
The resulting file now comes out much smaller at **39MB**. Check this article [GeoTIFF compression and optimization with GDAL](https://kokoalberti.com/articles/geotiff-compression-optimization-guide/) to learn more about various options and compression algorithms.
### 1.1.4 Setting NoData Values
The output from `gdalinfo` program shows that the original data has a *NoData* Value set to `-32768`. We can set a new *NoData* value. The `-a_nodata` option allows us to specify a new value.
**Windows**
```
gdal_translate -of GTiff merged.vrt merged.tif ^
-co COMPRESS=DEFLATE -co TILED=YES -co PREDICTOR=2 -a_nodata -9999
```
**Mac/Linux**
```
gdal_translate -of GTiff merged.vrt merged.tif \
-co COMPRESS=DEFLATE -co TILED=YES -co PREDICTOR=2 -a_nodata -9999
```
After running the command, you can verify the results using the `gdalinfo` command.
### 1.1.5 Writing Cloud-Optimized GeoTIFF (COG)
[![Watch the video](https://img.youtube.com/vi/vHrT9pKmQgQ/mqdefault.jpg)](https://www.youtube.com/watch?v=vHrT9pKmQgQ&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=12){target="_blank"}
[Watch the Video ↗](https://www.youtube.com/watch?v=vHrT9pKmQgQ&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=12){target="_blank"}
[Access the Presentation ↗](https://docs.google.com/presentation/d/1Wbx3ru3lQM5h_vw53OpPx5192IX3cwwXkyszfT2ZeO8/edit?usp=sharing){target="_blank"}
A new format called [Cloud-Optimized GeoTIFF (COG)](https://www.cogeo.org/) is making access to such a vast amount of imagery easier to access and analyze. A *Cloud-optimized* GeoTIFF is behaving just like a regular GeoTIFF imagery, but instead of downloading the entire image locally, you can access *portions* of imagery hosted on a cloud server streamed to clients like QGIS. This makes it very efficient to access this data and even analyze it - without downloading large files. GDAL makes it very easy to create COG files by specifying the `-of COG` option. Specifying the `-co NUM_THREADS=ALL_CPUS` helps speed up the creation process by using all available CPUs for compression and creating internal overviews.
The [GDAL COG Driver](https://gdal.org/drivers/raster/cog.html) has the following creation options `-co` enabled by default.
* Has internal tiling (i.e. `-co TILED=YES`)
* LZW Compression (i.e. `-co COMPRESS=LZW`)
* Automatic Selection of Predictor (i.e. `-co PREDICTOR=YES` chooses appropriate predictor for data type)
**Windows**
```
gdal_translate -of COG merged.vrt merged_cog.tif ^
-co COMPRESS=DEFLATE -co PREDICTOR=YES -co NUM_THREADS=ALL_CPUS ^
-a_nodata -9999
```
**Mac/Linux**
```
gdal_translate -of COG merged.vrt merged_cog.tif \
-co COMPRESS=DEFLATE -co PREDICTOR=YES -co NUM_THREADS=ALL_CPUS \
-a_nodata -9999
```
## 1.2 Processing Elevation Data
GDAL comes with the `gdaldem` utility that provides a suite of tools for visualizing and analyzing Digital Elevation Models (DEM). The tool supports the following modes
* Hillshade
* Slope
* Aspect
* Color-relief
* Terrain Ruggedness Index (TRI)
* Topographic Position Index (TPI)
* Roughness
Am important point to note is that the x, y and z units of the DEM should be of same unit. If you are using data in a Geographic CRS (like EPSG:4326) and the height units are in meters, you must specify a scale value using `-s` option.
### 1.2.1 Creating Hillshade
Let's create a hillshade map from the merged SRTM dataset. The `hillshade` mode creates an 8-bit raster with a nice shaded relief effect. This dataset has X and Y units in degrees and Z units in meters. So we specify `111120` as the scale value.
```
gdaldem hillshade merged.tif hillshade.tif -s 111120
```
`gdaldem` supports multiple hillshading algorithms. Apart from the default, it currently includes the following algorithms.
* Combined shading (`-combined`): A combination of slope and oblique shading.
* Multidirectional shading (`-multidirectional`): A combination of hillshading illuminated from 225 deg, 270 deg, 315 deg, and 360 deg azimuth.
Let's create a hillshade map with the `-multidirectional` option.
```
gdaldem hillshade merged.tif hillshade_combined.tif -s 111120 -multidirectional
```
```{r echo=FALSE, fig.align='center', out.width='100%'}
knitr::include_graphics('images/gdal/hillshade.png')
```
> Creating hillshade that is representative of a terrain is more of an 'art' than science. The best hand-drawn relief shading is still done manually by cartographers. Recent advances in Deep Learning have shown promise to reproduce the state-of-the-art relief shading using automated techniques. Learn more about [Cartographic Relief Shading with Neural Networks](https://arxiv.org/pdf/2010.01256.pdf){target="_blank"} and the accompanying software [Eduard](https://eduard.earth/){target="_blank"}.
### 1.2.2 Creating Color Relief
A color relief map is an elevation map where different ranges of elevations are colored differently. The `color-relief` mode can create a color relief map with the colors and elevation ranges supplied in a text file.
We need to supply the colormap using a text file. Create a new file called `colormap.txt` with the following content and save it in the same directory as `merged.tif`. The format of the text file is `elevation, red, green, blue` values.
```{bash eval=FALSE, code=readLines('code/gdal/colormap.txt')}
```
We can supply this file to create a colorized elevation map.
```
gdaldem color-relief merged.tif colormap.txt colorized.tif
```
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Color Relief'}
knitr::include_graphics('images/gdal/colorized.png')
```
### Exercise 2
Save the color relief in the PNG format.
## 1.3 Processing Aerial Imagery
Use the `cd` command to change to the `naip` directory which contains individual aerial imagery tiles in the **JPEG2000** format.
```
cd naip
```
### 1.3.1 Create a preview image from source tiles
The source imagery is heavily compressed and covers a large region. Instead of loading the full resolution tiles in a viewer, it is a good practice to create a preview mosaic that can help us assess the coverage and quality of the data.
We first create a *Virtual Raster* mosaic from all the `.jp2` tiles. We can create a text file containing all the files we want to merge.
**Windows**
```
dir /b *.jp2 > filelist.txt
```
**Mac/Linux**
```
ls *.jp2 > filelist.txt
```
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='Text File with the List of Images'}
knitr::include_graphics('images/gdal/aoi_textfile.png')
```
We are working with Photometric RGB tiles and want to apply JPEG compression on the result. To avoid JPEG artifact and maintain nodata values, it is a good practice to add an Alpha band which will contain the mask containing all valid pixels. We use the `-addalpha` option to create an alpha band.
```
gdalbuildvrt -addalpha -input_file_list filelist.txt naip.vrt
```
We can use the `-outsize` option and specify a percentage to generate a smaller size preview. The below command generates a 2% preview image in JPEG format. Since we have a 4-band image, we specify which bands to be used for generating the JPG image using the `-b` option.
```
gdal_translate -b 1 -b 2 -b 3 -of JPEG -outsize 2% 2% naip.vrt naip_preview.jpg
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/naip_preview.jpg')
```
### 1.3.2 Create a Tile Index
When working with large amounts of imagery tiles, it is useful to generate a tile index. A tile index layer is a polygon layer with the bounding box of each tile. An index layer allows us to check the coverage of the source data and locate specific tiles. It is a simple but effective way to catalog raster data from a hard drive or from a folder on your computer.
`gdaltindex` program creates a tile index from a list of input files. Here we can use the `--optfile` option to supply the list of files via a file.
```
gdaltindex -write_absolute_path index.shp --optfile filelist.txt
```
### 1.3.3 Mosaic and clip to AOI
Let's say we want to mosaic all the source tiles into a single image. We also want to clip the mosaic to a given AOI.
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/aoiselection.png')
```
We can use the `gdalwarp` utility to clip the raster using the `-cutline` option.
```
gdalwarp -cutline aoi.shp -crop_to_cutline naip.vrt aoi_cut.tif -co COMPRESS=DEFLATE -co TILED=YES
```
We can also add JPEG compression to the output file to reduce the file size. Refer to the post [GeoTiff Compression for Dummies](https://blog.cleverelephant.ca/2015/02/geotiff-compression-for-dummies.html) by Paul Ramsey that gives more insights into compression imagery. Note that JPEG is a lossy compression method and can cause edge artifacts for image mosaics. To prevent this, we specify the `--config GDAL_TIFF_INTERNAL_MASK YES` option that uses the mask from the alpha band.
**Windows**
```
gdal_translate aoi_cut.tif aoi.tif ^
-co COMPRESS=JPEG -co TILED=YES -co PHOTOMETRIC=YCBCR -co JPEG_QUALITY=75 ^
-b 1 -b 2 -b 3 -mask 4 --config GDAL_TIFF_INTERNAL_MASK YES
```
**Mac/Linux**
```
gdal_translate aoi_cut.tif aoi.tif \
-co COMPRESS=JPEG -co TILED=YES -co PHOTOMETRIC=YCBCR -co JPEG_QUALITY=75 \
-b 1 -b 2 -b 3 -mask 4 --config GDAL_TIFF_INTERNAL_MASK YES
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/mosaic.png')
```
### 1.3.4 Creating Overviews
If you try loading the resulting raster into a viewer, you will notice that it takes a lot of time for it to render. Zoom/Pan operations are quite slow as well. This is because the viewer is rendering all the pixels at native resolution. Since this is a very high-resolution dataset, it requires processing a lot of pixels, even if you are zoomed out. A common solution to this problem is to create *Pyramid Tiles* or *Overviews*. This process creates low-resolution versions of the image by averaging pixel values from higher resolution pixels. If the pyramid tiles are present, imagery viewers can use it to speed up the rendering process. GDAL provides the utility `gdaladdo` to create overview tiles. GeoTIFF format supports storing the overviews within the file itself. For other formats, the program generates external overviews in the `.ovr` format.
You can run the `gdaladdo` (**GDAL**-**Add**-**O**verview) command with default options to create internal overviews. Once the overviews are created, try opening the `aoi.tif` in QGIS. You will see that it renders much faster and zoom/pan operations are very smooth.
```
gdaladdo aoi.tif
```
The default overviews use the nearest neighbor resampling. We can pick any resampling method from the many available algorithms. We can try the bilinear interpolation using the `-r bilinear` option. Since the source imagery is JPEG compressed, we will compress the overviews with the same compression.
```
gdaladdo -r bilinear --config COMPRESS_OVERVIEW JPEG aoi.tif
```
## 1.4 Processing Satellite Imagery
This section shows how to use the satellite data from Landsat-8 and create various derived products. Use the `cd` command to switch to the `landsat8` directory which contains Landsat-8 imagery. This directory has 5 individual GeoTIFF files for 5 different bands from a single landsat-8 scene.
| **Band Number** |**Band Name** |
|:----------------|:-------------|
| B2 | Blue |
| B3 | Green |
| B4 | Red |
| B5 | Near Infrared|
| B8 | Panchromatic |
```
cd landsat8
```
### 1.4.1 Merging individual bands into RGB composite
Let's create an RGB composite image by combining three 3 different bands - Red, Green and Blue - into a single image. Here we must use the `-separate` option which tells the command to place each image in a separate band.
> Note: GDAL tools also have a `gdal_merge.py` script that can also merge rasters into an image. But this script loads all rasters into memory before merging them. This can lead to excessive RAM usage and out of memory errors when working with large files. `gdal_merge.py` can also be slower than using `gdal_translate` - when you have large files. So a preferred approach for merging large files would be using the virtual raster as shown here.
**Windows**
```
gdalbuildvrt -o rgb.vrt -separate ^
RT_LC08_L1TP_137042_20190920_20190926_01_T1_2019-09-20_B4.tif ^
RT_LC08_L1TP_137042_20190920_20190926_01_T1_2019-09-20_B3.tif ^
RT_LC08_L1TP_137042_20190920_20190926_01_T1_2019-09-20_B2.tif
```
**Mac/Linux**
```
gdalbuildvrt -o rgb.vrt -separate \
RT_LC08_L1TP_137042_20190920_20190926_01_T1_2019-09-20_B4.tif \
RT_LC08_L1TP_137042_20190920_20190926_01_T1_2019-09-20_B3.tif \
RT_LC08_L1TP_137042_20190920_20190926_01_T1_2019-09-20_B2.tif
```
Then use `gdal_translate` to merge them.
```
gdal_translate rgb.vrt rgb.tif -co PHOTOMETRIC=RGB -co COMPRESS=DEFLATE
```
Once the command finishes, you can view the result in QGIS.
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/rgb.png')
```
### 1.4.2 Apply Histogram Stretch and Color Correction
The resulting composite appears quite dark and has low-contrast. QGIS applies a default contrast stretch based on the minimum and maximum values in the image. Due to the presence of clouds and cloud-shadows - there are outlier pixels that make the default contrast stretch not optimal.
Here's what the histogram of the RGB composite looks like.
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/histogram.png')
```
We can apply a histogram stretch to increase the contrast. This is done using the `-scale` option. Since most of the pixels have a value between 0 and 0.3, we can choose these are minimum and maximum values and apply a contrast stretch to make them go from 0 to 255. The resulting image will be an 8-bit color image where the input pixel values are linearly scaled to the target value.
> Note: Scaling the image will alter the pixel values. The resulting image is suitable for visualization, but they should never be used for analysis. Scientific analysis should always use the un-scaled pixel values.
```
gdal_translate -scale 0 0.3 0 255 -ot Byte rgb.tif rgb_stretch.tif
```
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='RGB Composite with Linear Stretch'}
knitr::include_graphics('images/gdal/rgb_stretch_linear.png')
```
We can also apply a non-linear stretch. `gdal_translate` has a `-exponent` option that scales the input values using the following formula. Choosing an exponent value between 0 and 1 will enhance low intensity values - resulting in a brighter image. [Learn more](https://homepages.inf.ed.ac.uk/rbf/HIPR2/pixexp.htm)
Let's try exponent value of **0.5**. The result is a much better looking output.
```
gdal_translate -scale 0 0.3 0 255 -exponent 0.5 -ot Byte rgb.tif rgb_stretch.tif
```
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='RGB Composite with Exponential Stretch'}
knitr::include_graphics('images/gdal/rgb_stretch_exponent.png')
```
### 1.4.3 Raster Algebra
[![Watch the video](https://img.youtube.com/vi/P3WwxzhcZrA/mqdefault.jpg)](https://www.youtube.com/watch?v=P3WwxzhcZrA&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=26){target="_blank"}
[Watch the Video ↗](https://www.youtube.com/watch?v=P3WwxzhcZrA&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=26){target="_blank"}
[Access the Presentation ↗](https://docs.google.com/presentation/d/1_MRRAlTLsfaiTmVTvpFP0nKv7Kbm75X82teMztZjwHY/edit?usp=sharing){target="_blank"}
For raster algebra operations, GDAL provides a raster calculator program `gdal_calc.py`. The input rasters are specified using any letters from A-Z. These letters can be then referenced in the expression. The expression is specified using the `--calc` option and it supports NumPy syntax and [functions](https://numpy.org/doc/stable/reference/routines.math.html#).
```
gdalinfo -stats RT_LC08_L1TP_137042_20190920_20190926_01_T1_2019-09-20_B4.tif
```
It is important to set NoData value. As seen from the output above, NoData is set to **-999**.
> Note that Windows users need to specify the full path to the GDAL scripts and run it with the python command as shown below. Mac/Linux users can just type the script name directly but if you get an error, you can also specify the full path on Mac/Linux as `python $CONDA_PREFIX/bin/gdal_merge.py`
**Windows**
```
python %CONDA_PREFIX%\Scripts\gdal_calc.py ^
-A RT_LC08_L1TP_137042_20190920_20190926_01_T1_2019-09-20_B5.tif ^
-B RT_LC08_L1TP_137042_20190920_20190926_01_T1_2019-09-20_B4.tif ^
--outfile ndvi.tif --calc="(A-B)/(A+B)" --NoDataValue=-999
```
**Mac/Linux**
```
gdal_calc.py -A RT_LC08_L1TP_137042_20190920_20190926_01_T1_2019-09-20_B5.tif \
-B RT_LC08_L1TP_137042_20190920_20190926_01_T1_2019-09-20_B4.tif \
--outfile ndvi.tif --calc="(A-B)/(A+B)" --NoDataValue=-999
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/ndvi.png')
```
### Exercise 3
Create an NRG Composite image with Near Infrared, Red and Green bands. Apply a contrast stretch to the result and save it as a PNG image.
```{r echo=FALSE, fig.align='center', out.width='75%', fig.cap='NRG Composite'}
knitr::include_graphics('images/gdal/nrg_stretch.png')
```
### 1.4.4 Pan Sharpening
[![Watch the video](https://img.youtube.com/vi/RqlKS6iT488/mqdefault.jpg)](https://www.youtube.com/watch?v=RqlKS6iT488&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=28){target="_blank"}
[Watch the Video ↗](https://www.youtube.com/watch?v=RqlKS6iT488&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=28){target="_blank"}
[Access the Presentation ↗](https://docs.google.com/presentation/d/1Gav3_0P1BsOrdrYk-Hi2D4gbLHt1cJakAlARqjsGYzg/edit?usp=sharing){target="_blank"}
Most satellite and airborne sensors capture images in the *Pan-chromatic* band along with other spectral bands. The *Red*, *Green*, and *Blue* bands capture signals in the *Red*, *Green*, and *Blue* portions of the electromagnetic spectrum respectively. But the *Pan*-band captures the data across the entire range of wavelengths in the visible spectrum. This allows the sensor to capture the data in a higher spatial resolution than other bands which capture the signal from a subset of this wavelength range.
Landsat-8 satellite produces images at a **30m** spatial resolution in the *Red*, *Green*, *Blue* bands and at a **15m** spatial resolution in the *Panchromatic* band. We can use the higher spatial resolution of the *Panchromatic* band to improve the resolution of the other bands, resulting in a sharper image with more details. This process is called *Pan-Sharpening*.
GDAL comes with a script `gdal_pansharpen.py` that implements the [Brovey algorithm](https://gdal.org/drivers/raster/vrt.html#gdal-vrttut-pansharpen) to compute the pansharpened output. In the example below we fuse the 15m resolution panchromatic band (B8) with the RGB composite created in the previous step.
**Windows**
```
python %CONDA_PREFIX%\Scripts\gdal_pansharpen.py RT_LC08_L1TP_137042_20190920_20190926_01_T1_2019-09-20_B8.tif ^
rgb.tif pansharpened.tif -r bilinear -co COMPRESS=DEFLATE -co PHOTOMETRIC=RGB
```
**Mac/Linux**
```
gdal_pansharpen.py RT_LC08_L1TP_137042_20190920_20190926_01_T1_2019-09-20_B8.tif \
rgb.tif pansharpened.tif -r bilinear -co COMPRESS=DEFLATE -co PHOTOMETRIC=RGB
```
We can apply the same contrast stretch as before and compare the output. You will notice that the resulting composite is much sharper and can resolve the details in the scene much better.
**Windows**
```
gdal_translate -scale 0 0.3 0 255 -exponent 0.5 -ot Byte -a_nodata 0 ^
pansharpened.tif pansharpened_stretch.tif
```
**Mac/Linux**
```
gdal_translate -scale 0 0.3 0 255 -exponent 0.5 -ot Byte -a_nodata 0 \
pansharpened.tif pansharpened_stretch.tif
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/pansharpen_before.png')
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/pansharpen_after.png')
```
## 1.5 Processing WMS Layers
GDAL supports reading from a variety of web services, including [Web Map Services (WMS)](https://gdal.org/drivers/raster/wms.html) layers.
### 1.5.1 Listing WMS Layers
NASA's Socioeconomic Data and Applications Center (SEDAC) provides many useful data layers though [WMS Services](https://sedac.ciesin.columbia.edu/maps/services). We can pick the URL for the appropriate service and list all available layers using `gdalinfo`.
```
gdalinfo "WMS:https://sedac.ciesin.columbia.edu/geoserver/ows?version=1.3.0"
```
```{r echo=FALSE, fig.align='center', out.width='100%'}
knitr::include_graphics('images/gdal/wms1.png')
```
We can get more information about a particular layer by specifying the output from the command above. Let's get more info about the [Global Reservoir and Dam (GRanD), v1](https://sedac.ciesin.columbia.edu/data/set/grand-v1-reservoirs-rev01) layer.
```
gdalinfo "WMS:https://sedac.ciesin.columbia.edu/geoserver/ows?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=grand-v1%3Agrand-v1-reservoirs-rev01&CRS=CRS:84&BBOX=-153.037,-45.881,176.825,70.398"
```
### 1.5.2 Creating a Service Description File
GDAL can also create a Service Description XML file from a WMS layer. Many GIS programs, including QGIS recognize these XML files as valid raster layers. This allows users to easily drag-and-drop them into their favorite viewer to access a WMS service without any configuration. `gdal_translate` can write the WMS XML files by specifying `-of WMS` option.
```
gdal_translate -of WMS "WMS:https://sedac.ciesin.columbia.edu/geoserver/ows?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=grand-v1%3Agrand-v1-reservoirs-rev01&CRS=CRS:84&BBOX=-153.037,-45.881,176.825,70.398" reservoirs.xml
```
### 1.5.3 Downloading WMS Layers
Some applications require offline access to WMS layers. If you want to use a WMS layer as a reference map for field-data collection, or use the layer on a system with low-bandwidth, you can create a georeferenced raster from a WMS layer. Depending on the server configuration, WMS layers can serve data for resolutions exceeding their native resolution, so one should explicitly specify the output resolution. We can use `gdalwarp` with the `-tr` option to specify the output resolution you need for the offline raster. In the example below, we create a 0.1 degree resolution raster from the WMS layer.
```
gdalwarp -tr 0.1 0.1 reservoirs.xml reservoirs.tif -co COMPRESS=DEFLATE -co TILED=YES
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/wms4.png')
```
We can also extract a higher resolution extract for a specific region by specifying the extent using the `-te` option.
```
gdalwarp -tr 0.005 0.005 -te 68.106 6.762 97.412 37.078 reservoirs.xml reservoirs_india.tif -co COMPRESS=DEFLATE -co TILED=YES
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/wms5.png')
```
Learn more about offline WMS and comparison between different formats in this article [Offline WMS – Benchmarking raster formats for QField](https://www.opengis.ch/2020/06/09/offline-wms-benchmarking-raster-formats-for-qfield/) by OpenGIS.ch.
### Exercise 4
Instead of specifying the resolution in degrees, we want to download the layer at a specific resolution in meters. We can re-project the layer to a projected CRS and specify the output resolution in the units of the target CRS.
Create a command that takes the `reservoirs.xml` file and creates a GeoTiff file called `reservoirs_india_reprojected.tif `for the India region at 500m resolution in the CRS **WGS 84 / India NSF LCC (EPSG:7755)**.
You can use the hints below to construct your command.
* Specify the extent using `-te` option as `68.106 6.762 97.412 37.078` in the `xmin ymin xmax ymax` order.
* The extent coordinates are in WGS84 Lat/Lon coordinates. So specify the CRS of the extent coordinates using `-te_srs`.
* Use the `-t_srs` option to specify the target CRS as `EPSG:7755`.
* Use the `-tr` option to specify the X and Y pixel resolution.
## 1.6 Georeferencing
GDAL command-line utilities are extremely useful in batch georeferencing tasks. We will learn 2 different techniques for georeferencing/warping images.
### 1.6.1 Georeferencing Images with Bounding Box Coordinates
Often you get images from web portals that are maps but lack georeferencing information. Data from weather satellites, output from simulations, exports from photo editing software etc. can contain images that reference a fixed frame on the earth but are given in regular image formats such as JPEG or PNG. If the bounding box coordinates and the CRS used in creating these images are known, use `gdal_translate` command to assign georeference information. The `-a_ullr` option allows you to specify the bounding box coordinates using the Upper-Left (UL) and Lower-Right (LR) coordinates.
Your data package contains the image file `earth_at_night.jpg`. This is a beautifully rendered image of the earth captured at night time. You will see that this is a plain JPEG image without any georeference information.
```
gdalinfo earth_at_night.jpg
```
Since this is a global image, we know the corner coordinates. We can assign the CRS **EPSG:4326** using the `-a_srs` option and specify the bounding box coordinates in the following order `<ulx> <uly> <lrx> <lry>`.
**Windows**
```
gdal_translate -a_ullr -180 90 180 -90 -a_srs EPSG:4326 ^
earth_at_night.jpg earth_at_night.tif ^
-co COMPRESS=JPEG -co TILED=YES -co PHOTOMETRIC=RGB
```
**Mac/Linux**
```
gdal_translate -a_ullr -180 90 180 -90 -a_srs EPSG:4326 \
earth_at_night.jpg earth_at_night.tif \
-co COMPRESS=JPEG -co TILED=YES -co PHOTOMETRIC=RGB
```
The resulting file `earth_at_night.tif` is a GeoTiff file with the correct georeference information and can now be used in GIS software.
```
gdalinfo earth_at_night.tif
```
```{r echo=FALSE, fig.align='center'}
knitr::include_graphics('images/gdal/earth_at_night.png')
```
### 1.6.2 Georeferencing with GCPs
Another option for georeferencing images it by using Ground Control Points (GCPs) or Tie-Points. A GCP specifies the real-world coordinates for a given pixel in the image. The GCPs can be obtained by reading the map markings or locating landmarks from a georeferenced source. Given a set of GCPs, `gdalwarp` can georeference the image using a variety of transformation types.
Your data package contain an old scanned map called `1870_southern_india.jpg`.
```{r echo=FALSE, fig.align='center'}
knitr::include_graphics('images/gdal/scanned_map.png')
```
The map has graticule lines with latitude and longitude markings. To obtain the GCPs, we can read the coordinate values at the grid intersections and find the pixel's image coordinates. You can use an image viewer or the *Georeferencer* tool in QGIS to obtain GCPs like below.
| **pixel (column)** | **line (row)** | **X (Longitude)** | **Y (Latitude)** |
|:---------------|:---------|:--------------------|:----------------|
| 418 | 893 | 70 | 15 |
| 380 | 2432 | 70 | 5 |
| 3453 | 2434 | 90 | 5 |
| 3407 | 895 | 90 | 15 |
| 2662 | 911 | 85 | 15 |
The first step is to store these GCPs in the image metadata using utility `gdal_translate`.
**Windows**
```
gdal_translate -gcp 418 893 70 15 -gcp 380 2432 70 5 -gcp 3453 2434 90 5 ^
-gcp 3407 895 90 15 -gcp 2662 911 85 15 ^
1870_southern-india.jpg india-with-gcp.tif
```
**Mac/Linux**
```
gdal_translate -gcp 418 893 70 15 -gcp 380 2432 70 5 -gcp 3453 2434 90 5 \
-gcp 3407 895 90 15 -gcp 2662 911 85 15 \
1870_southern-india.jpg india-with-gcp.tif
```
Now that the GCPs are stored in the image, we are ready to do the georeferencing. Assuming the CRS of the map is a Geographic CRS based on the Everest 1830 datum, we choose **EPSG:4042** as the target CRS.
Next, we need to choose the transformation type. `gdalwarp` supports the following transformation types
* *Polynomial 1,2 or 3* using `-order` option
* *Thin Plate Spline* using the `-tps` option
Let's try **Polynomial 1** transformation and check the results.
**Windows**
```
gdalwarp -t_srs EPSG:4042 -order 1 -tr 0.005 0.005 ^
india-with-gcp.tif india-reprojected-polynomial.tif ^
-co COMPRESS=JPEG -co JPEG_QUALITY=50 -co PHOTOMETRIC=YCBCR
```
**Mac/Linux**
```
gdalwarp -t_srs EPSG:4042 -order 1 -tr 0.005 0.005 \
india-with-gcp.tif india-reprojected-polynomial.tif \
-co COMPRESS=JPEG -co JPEG_QUALITY=50 -co PHOTOMETRIC=YCBCR
```
```{r echo=FALSE, fig.align='center'}
knitr::include_graphics('images/gdal/georeference_gcp.png')
```
### Exercise 5
Try the Thin-plate-spline transformation on the `india-with-gcp.tif` file and save the results as `india-reprojected-tps.tif` file. Note the Thin-Place-Splie option is available at `-tps` with the `gdalwarp` command.
## Assignment
UK’s Department of Environment Food & Rural Affairs (DEFRA) provides country-wide LiDAR data and products via the [Defra Data Services Platform](https://environment.data.gov.uk/DefraDataDownload/?Mode=survey) under an open license.
Your data package contains a folder `london_1m_dsm`. This folder contains 1m resolution Digital Surface Model (DSM) tiles for central London generated from a LIDAR survey. The tiles are in the [Arc/Info ASCII Grid](https://gdal.org/drivers/raster/aaigrid.html) format with the `.asc` extension. The tiles do not contain any projection information but the [metadata](https://environment.data.gov.uk/dataset/6f51a299-351f-4e30-a5a3-2511da9688f7) contains the information that the CRS for the dataset is **EPSG:27700 British National Grid**.
Apply the skills you learnt in this module to create an output product suitable for analysis. The result should be a single georeferenced mosaic in the GeoTIFF format with appropriate compression.
* Hint: Use the `gdal_translate` program with the `-a_srs` option to assign a CRS.
# 2. OGR Tools
We will now learn to process vector data using OGR Tools. These are a suite of tools that are part of the GDAL package and follow the same convention. In addition to format translation, the OGR tools also support running Spatial SQL queries - making them very powerful to build Spatial ETL pipelines.
[![Start Module Videos](https://img.youtube.com/vi/3g6fOVYor4c/mqdefault.jpg)](https://www.youtube.com/watch?v=3g6fOVYor4c&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=35){target="_blank"}
[Start Module Videos ↗](https://www.youtube.com/watch?v=3g6fOVYor4c&list=PLppGmFLhQ1HLVaHVf4TsnJ4HXZBSfxLOK&index=35){target="_blank"}
## 2.1 ETL Basics
In this section, we will see how we can build an Extract-Transform-Load (ETL) process in a step-by-step manner. The example workflow will show you how to
1. Read a CSV data source
2. Convert it to point data layer
3. Assign it a CRS
4. Extract a subset
5. Change the data type of a column
6. Write the results to a GeoPackage.
### 2.1.1 Read a CSV data source
Your data package has a CSV file called `worldcities.csv`. This file contains basic information about major cities in the world along with their coordinates.
Let's use the `ogrinfo` command to inspect the dataset.
```
ogrinfo worldcities.csv
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/ogr_csv01.png')
```
The program can open and read the file successfully, but it doesn't show any other info. We can use the `-al` option to actually read all the lines from the file and combine it with the `-so` option to print a summary.
```
ogrinfo -so -al worldcities.csv
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/ogr_csv02.png')
```
### 2.1.2 Convert it to point data layer
We now get a summary with the total number of features in the file along with columns and their types. This is a plain CSV file. Let's turn it into a spatial data layer using the X and Y coordinates supplied in the `lng` and `lat` fields. The `-oo` option allows us to specify format-specific options. The [OGR CSV Driver](https://gdal.org/drivers/vector/csv.html#reading-csv-containing-spatial-information) allows specifying a list of column names or a name pattern (such as `Lat*`) s using the `X_POSSIBLE_NAMES` and `Y_POSSIBLE_NAMES` options to specify which columns contain geometry information.
```
ogrinfo -so -al worldcities.csv -oo X_POSSIBLE_NAMES=lng -oo Y_POSSIBLE_NAMES=lat
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/ogr_csv03.png')
```
OGR is now able to recognize this layer as Point geometry layer. Let's write this to a spatial data format. We can use the `ogr2ogr` utility to translate between different formats. The following command creates a new GeoPackage file called `worldcities.gpkg` from the CSV file.
**Windows**
```
ogr2ogr -f GPKG worldcities.gpkg worldcities.csv ^
-oo X_POSSIBLE_NAMES=lng -oo Y_POSSIBLE_NAMES=lat
```
**Mac/Linux**
```
ogr2ogr -f GPKG worldcities.gpkg worldcities.csv \
-oo X_POSSIBLE_NAMES=lng -oo Y_POSSIBLE_NAMES=lat
```
```{r echo=FALSE, fig.align='center', out.width='75%'}
knitr::include_graphics('images/gdal/ogr_csv04.png')
```