├── LICENSE ├── README.md ├── Session1_install_conda.md ├── Session2_lidar_io.md ├── Session3_generate_raster.md └── example_data ├── create_dsm.ipynb ├── create_ndhm.ipynb ├── in2018_29651885_12.laz └── in2018_29651885_12_dtm.img /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Geospatial Data Science Lab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LiDAR data processing using Python 2 | 3 | Written by Jinha Jung (jinha@purdue.edu), Sungchan Oh (oh231@purdue.edu), and Yuri Kim (yurikim@iu.edu). 4 | Please contact authors for any questions on this tutorial. 5 | 6 | ## Pre-requisite 7 | 8 | You need Git installed on your machine. Please follow instruction from https://git-scm.com/book/en/v2/Getting-Started-Installing-Git to install Git on your machine. 9 | 10 | Once the Git is installed on your machine, clone this repository on your local machine. 11 | 12 | ``` 13 | $ cd [YOUR_TARGET_DIRECTORY] 14 | $ git clone https://github.com/gdslab/tutorial_lidar_processing_with_python.git 15 | ``` 16 | 17 | ## LiDAR 101 (10 min) - Yuri Kim 18 | 19 | 1. What is LiDAR? 20 | 21 | ## Installing Conda/Anaconda and configuring Virtual Environments (40 min) - Jinha Jung 22 | 23 | Click [here](https://github.com/gdslab/tutorial_lidar_processing_with_python/blob/main/Session1_install_conda.md) for more detail. 24 | 25 | 1. Anaconda installation on Windows 26 | 1. Anaconda installation on Mac 27 | 1. Anaconda installation on Linux 28 | 1. Why do we need Virtual Environment? 29 | 1. Setting up a Virtual Environment for LiDAR data processing 30 | 31 | ## LiDAR file I/O using laspy (30 min) - Jinha Jung 32 | 33 | Click [here](https://github.com/gdslab/tutorial_lidar_processing_with_python/blob/main/Session2_lidar_io.md) for more detail. 34 | 35 | 1. Reading and writing las/laz file 36 | 1. Converting laz to las format 37 | 1. Converting las version 38 | 1. Visualizing las file using Cloud Compare 39 | 40 | ## Generating raster data from LiDAR (70 min) - Jinha Jung 41 | 42 | Click [here](https://github.com/gdslab/tutorial_lidar_processing_with_python/blob/main/Session3_generate_raster.md) for more detail. 43 | 44 | 1. Generating Digital Surface Model (DSM) from a las file 45 | 1. Generating Normalized Digital Height Model (NDHM) from a las fil 46 | 47 | ## Application of DSM, DTM, and NDHM (30 min) - Yuri Kim 48 | 49 | 1. 3D-visualizing DSM, DTM and NDHM using QGIS 50 | 2. Exploring and Visualizing LiDAR with contour, classification, etc. 51 | 52 | ## Things to prepare before the workshop 53 | 54 | 1. A computer or laptop (Windows/Mac/Linux) 55 | 1. HDD storage space over 2GB 56 | 1. Reliable internet connection 57 | 1. Install QGIS LTS version 58 | 1. Basic familiarity with Python 59 | -------------------------------------------------------------------------------- /Session1_install_conda.md: -------------------------------------------------------------------------------- 1 | ## Installing Conda/Anaconda and configuring Virtual Environments (50 min) 2 | 3 | We will install the latest version of Anaconda here. 4 | 5 | 6 | ### Download Anaconda 7 | 8 | Click [here](https://www.anaconda.com/products/individual) to download installation files for your operating system. If you have already installed anaconda or miniconda on your system, then you can skip this part. 9 | 10 | ### Open [Command line interface](https://docs.anaconda.com/anaconda/user-guide/getting-started/#open-anaconda-prompt) 11 | 12 | Windows: You will need to run **Anaconda Prompt(Anaconda 3)** from the start menu. 13 | 14 | OSX or Linux: You will need to open a terminal. 15 | 16 | ### Configuring conda environment 17 | 18 | You will first need to check what virtual environments are already available on your system. 19 | When you run the below command in the terminal, make it sure you have * symbol right next to the base environment. 20 | 21 | ```bash 22 | $ conda info --envs 23 | ``` 24 | 25 | You need to create a new virtual environment for this tutorial using the below command. We will use Python=3.6 version in this tutorial. 26 | 27 | ```bash 28 | $ conda create --name lidar python=3.8 29 | ``` 30 | 31 | After you create the new virtual environment, we need to activate the new environment using the below command. 32 | 33 | For Windows 34 | 35 | ```bash 36 | $ conda activate lidar 37 | ``` 38 | 39 | For OSX and Linux 40 | 41 | ```bash 42 | $ source ~/.bashrc 43 | $ conda activate lidar 44 | ``` 45 | 46 | You need to check if the new environment is activated correctly using the below command. You should see * symbol right next to the lidar environment. 47 | 48 | ```bash 49 | $ conda info --envs 50 | ``` 51 | 52 | Once the new environment is activated, you need to install below packages in the new environment that are required for this tutorial. 53 | 54 | ```bash 55 | $ conda install jupyter 56 | $ conda install numpy matplotlib 57 | $ conda install ipython 58 | $ conda install gdal 59 | $ conda install progressbar2 60 | $ conda install -c conda-forge laspy 61 | $ conda install -c conda-forge lastools 62 | $ conda install pip 63 | ``` 64 | 65 | NOTE: The above commands will install laspy 2.0 version, and we will have to install additional packages to enable laz support. 66 | 67 | ```bash 68 | $ pip install lazrs 69 | ``` 70 | 71 | If the above command does not work, then you can do below as an alternative. 72 | 73 | ```bash 74 | $ pip install laszip 75 | ``` 76 | 77 | After installing the above packages, you need to confirm the installation by running the below commands. 78 | 79 | ```bash 80 | $ conda activate lidar 81 | $ ipython 82 | ``` 83 | 84 | ```python 85 | >>> import numpy 86 | >>> import matplotlib 87 | >>> import laspy 88 | >>> from osgeo import gdal 89 | ``` 90 | 91 | Now we need to make the **lidar** virtual environment available from the jupyter notebook. Type below command in the command line. 92 | 93 | ``` 94 | ipython kernel install --user --name=lidar 95 | ``` 96 | 97 | You will also need to check jupyter notebook installation by running the below command. 98 | 99 | ```bash 100 | $ cd [YOUR GIT Clone Directory] 101 | $ jupyter notebook 102 | ``` 103 | 104 | ## Installing Google Chrome on Windows Server 2019. 105 | 106 | Open PowerShell and paste below command. 107 | 108 | ``` 109 | $Path = $env:TEMP; $Installer = “chrome_installer.exe”; Invoke-WebRequest “http://dl.google.com/chrome/chrome_installer.exe" -OutFile $Path\$Installer; Start-Process -FilePath $Path\$Installer -Args “/silent /install” -Verb RunAs -Wait; Remove-Item $Path\$Installer 110 | ``` 111 | -------------------------------------------------------------------------------- /Session2_lidar_io.md: -------------------------------------------------------------------------------- 1 | 2 | ## LiDAR file I/O using laspy (60 min) 3 | 4 | This tutorial will cover LiDAR file Input and Output using laspy module. 5 | 6 | 7 | ### Tutorial data download 8 | 9 | You will need to clone this tutorial github repository using the below command. If you don't have git installed on your machine, then you should be able to download a zip file as well. 10 | 11 | ```bash 12 | $ git clone https://github.com/gdslab/tutorial_lidar_processing_with_python.git 13 | ``` 14 | 15 | You can also download any LiDAR tiles from https://lidar.digitalforestry.org if you want. 16 | 17 | ### Activate the lidar virtual environment 18 | 19 | Open a Anaconda Prompt and run the below command to activate the lidar virtual environment you created in the previous section. 20 | 21 | For Windows 22 | 23 | ```bash 24 | $ conda activate lidar 25 | ``` 26 | 27 | For OSX or Linux 28 | 29 | Open a terminal window and run the below commands. 30 | 31 | ```bash 32 | $ source ~/.bashrc 33 | $ conda activate lidar 34 | ``` 35 | 36 | ### Converting .laz file (compressed format) into .las file (las version 1.3) 37 | 38 | First check information of the LiDAR data using below command. 39 | 40 | ```bash 41 | $ lasinfo in2018_29651885_12.laz 42 | ``` 43 | 44 | Optionally, you can convert .laz file into .las file using below commands. The reason why you may want to convert .laz file into .las (1.3 version) is because the CloudCompare software can't visualize 1.4 version las file at this moment. 45 | 46 | ```bash 47 | $ las2las -i in2018_29651885_12.laz -o in2018_29651885_12.las 48 | $ lascopy in2018_29651885_12.las in2018_29651885_12_las13.las 3 1.3 49 | ``` 50 | 51 | ### Visualizing LiDAR file 52 | 53 | Download [CloudCompare](https://www.danielgm.net/cc/) and install. Using this software, you should be able to visualize in2018_29651885_12_las13.las in 3D. 54 | 55 | ```bash 56 | $ snap install cloudcompare 57 | ``` 58 | -------------------------------------------------------------------------------- /Session3_generate_raster.md: -------------------------------------------------------------------------------- 1 | ## Generating raster data from LiDAR (60 min) 2 | 3 | This tutorial will cover how to genreate DSM (Digital Surface Model) and NDHM (Normalized Digital Height Model) from the LiDAR data. 4 | 5 | First, you need to move into the *example_data* folder using the command line window. 6 | 7 | ### Run Jupyter Notebook 8 | 9 | Run a jupyter notebook using below command. 10 | 11 | ```bash 12 | $ jupyter notebook 13 | ``` 14 | 15 | ### Hand-on programming using jupyter notebook 16 | 17 | We will write codes interactively, but you can also refer to below notebooks if needed. 18 | 19 | 1. DSM generation [notebook](https://github.com/gdslab/tutorial_lidar_processing_with_python/blob/main/example_data/create_dsm.ipynb) 20 | 1. NDHM generation [notebook](https://github.com/gdslab/tutorial_lidar_processing_with_python/blob/main/example_data/create_ndhm.ipynb) 21 | -------------------------------------------------------------------------------- /example_data/create_dsm.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "**Generate DSM**" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import sys\n", 17 | "import os\n", 18 | "import laspy\n", 19 | "import numpy as np\n", 20 | "from osgeo import gdal\n", 21 | "import time\n", 22 | "from progressbar import ProgressBar" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "# Input files, parameters\n", 32 | "las_fn = './in2018_29651885_12_las13.las'\n", 33 | "dtm_fn = './in2018_29651885_12_dtm.img'\n", 34 | "dsm_fn = './in2018_29651885_12_dsm_2_5_ft.tif'\n", 35 | "# dsm_fn = './in2018_29651885_12_dsm_5_ft.tif'\n", 36 | "out_format = 'GTiff'\n", 37 | "# scale_factor = 2.0" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "# Open LiDAR file\n", 47 | "las = laspy.file.File(las_fn, mode='r')\n", 48 | "points = np.vstack((las.x, las.y, las.z)).transpose()\n", 49 | "num_points = points.shape[0]\n", 50 | "\n", 51 | "# Open DTM file\n", 52 | "dtm = gdal.Open(dtm_fn)" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "# Check data info\n", 62 | "dtm_array = dtm.ReadAsArray()\n", 63 | "nrow = dtm_array.shape[0]\n", 64 | "ncol = dtm_array.shape[1]\n", 65 | "print('nrow and ncol:', nrow, ncol)\n", 66 | "gt = dtm.GetGeoTransform()\n", 67 | "print('Geotransform:', gt)\n", 68 | "print('Cellsize(x,y):', gt[1], gt[5])" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "**[Affine transform](http://resources.esri.com/help/9.3/arcgisengine/java/gp_toolref/coverage_tools/how_transform_coverage_works.htm)**\n", 76 | "\n", 77 | "\n", 78 | "Xgeo = gt[0] + (col \\* gt[1])\n", 79 | "\n", 80 | "Ygeo = gt[3] + (row \\* gt[5])" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": null, 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "ul_x = gt[0]\n", 90 | "ul_y = gt[3]\n", 91 | "cs_x = gt[1]\n", 92 | "cs_y = gt[5]" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": null, 98 | "metadata": { 99 | "scrolled": true 100 | }, 101 | "outputs": [], 102 | "source": [ 103 | "dtm.GetProjection()" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": null, 109 | "metadata": {}, 110 | "outputs": [], 111 | "source": [ 112 | "nrow_out = nrow\n", 113 | "ncol_out = ncol\n", 114 | "# nrow_out = int(nrow/scale_factor)\n", 115 | "# ncol_out = int(ncol/scale_factor)\n", 116 | "cs_x_out = cs_x\n", 117 | "cs_y_out = cs_y\n", 118 | "# cs_x_out = cs_x * scale_factor\n", 119 | "# cs_y_out = cs_y * scale_factor\n", 120 | "gt_out = gt\n", 121 | "# gt_out = [ul_x, cs_x_out, gt[2], ul_y, gt[4], cs_y_out]" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": null, 127 | "metadata": {}, 128 | "outputs": [], 129 | "source": [ 130 | "# Close las file\n", 131 | "las.close()" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": null, 137 | "metadata": { 138 | "scrolled": true 139 | }, 140 | "outputs": [], 141 | "source": [ 142 | "start = time.time()\n", 143 | "\n", 144 | "# Initialize DSM array\n", 145 | "dsm = np.zeros((nrow_out, ncol_out), dtype=np.float32)\n", 146 | "\n", 147 | "pbar = ProgressBar()\n", 148 | "for i in pbar(range(num_points)):\n", 149 | " # Get LiDAR point\n", 150 | " p_x = points[i,0]\n", 151 | " p_y = points[i,1]\n", 152 | " p_z = points[i,2]\n", 153 | " \n", 154 | " # Get row, col index in image of the point\n", 155 | " col = int((p_x - ul_x) / cs_x_out)\n", 156 | " row = int((p_y - ul_y) / cs_y_out)\n", 157 | " \n", 158 | " # Check points outside DTM boundary\n", 159 | " if col < 0 or col >= ncol_out:\n", 160 | " print('x out of dtm boundary', p_x)\n", 161 | " continue\n", 162 | " if row < 0 or row >= nrow_out:\n", 163 | " print('y out of dtm boundary', p_y)\n", 164 | " continue\n", 165 | "\n", 166 | " # Update DSM\n", 167 | " if dsm[row, col] < p_z:\n", 168 | " dsm[row, col] = p_z\n", 169 | "\n", 170 | "# Save output\n", 171 | "driver = gdal.GetDriverByName(out_format)\n", 172 | "dsm_ds = driver.Create(dsm_fn, xsize=ncol_out, ysize=nrow_out, bands=1, eType=gdal.GDT_Float32)\n", 173 | "dsm_ds.SetProjection(dtm.GetProjection())\n", 174 | "dsm_ds.SetGeoTransform(gt_out)\n", 175 | "dsm_ds.GetRasterBand(1).WriteArray(dsm)\n", 176 | "dsm_ds = None\n", 177 | "\n", 178 | "# Print elapsed time\n", 179 | "end = time.time()\n", 180 | "print('Elapsed time:', int(end - start))" 181 | ] 182 | } 183 | ], 184 | "metadata": { 185 | "kernelspec": { 186 | "display_name": "Python 3", 187 | "language": "python", 188 | "name": "python3" 189 | }, 190 | "language_info": { 191 | "codemirror_mode": { 192 | "name": "ipython", 193 | "version": 3 194 | }, 195 | "file_extension": ".py", 196 | "mimetype": "text/x-python", 197 | "name": "python", 198 | "nbconvert_exporter": "python", 199 | "pygments_lexer": "ipython3", 200 | "version": "3.8.3" 201 | } 202 | }, 203 | "nbformat": 4, 204 | "nbformat_minor": 2 205 | } 206 | -------------------------------------------------------------------------------- /example_data/create_ndhm.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "**Generate NDHM**" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import sys\n", 17 | "import os\n", 18 | "import laspy\n", 19 | "import numpy as np\n", 20 | "from osgeo import gdal\n", 21 | "import time\n", 22 | "from progressbar import ProgressBar" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "# Input files, parameters\n", 32 | "las_fn = './in2018_29651885_12_las13.las'\n", 33 | "dtm_fn = './in2018_29651885_12_dtm.img'\n", 34 | "ndhm_fn = './in2018_29651885_12_ndhm_5_ft.tif'\n", 35 | "out_format = 'GTiff'\n", 36 | "scale_factor = 2.0" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "# Open LiDAR file\n", 46 | "las = laspy.file.File(las_fn, mode='r')\n", 47 | "points = np.vstack((las.x, las.y, las.z)).transpose()\n", 48 | "num_points = points.shape[0]\n", 49 | "\n", 50 | "# Open DTM file\n", 51 | "dtm = gdal.Open(dtm_fn)" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": null, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "# Check data info\n", 61 | "dtm_array = dtm.ReadAsArray()\n", 62 | "nrow = dtm_array.shape[0]\n", 63 | "ncol = dtm_array.shape[1]\n", 64 | "print('nrow and ncol:', nrow, ncol)\n", 65 | "gt = dtm.GetGeoTransform()\n", 66 | "print('Geotransform:', gt)\n", 67 | "print('Cellsize(x,y):', gt[1], gt[5])" 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "metadata": {}, 73 | "source": [ 74 | "**[Affine transform](http://resources.esri.com/help/9.3/arcgisengine/java/gp_toolref/coverage_tools/how_transform_coverage_works.htm)**\n", 75 | "\n", 76 | "\n", 77 | "Xgeo = gt[0] + (col \\* gt[1])\n", 78 | "\n", 79 | "Ygeo = gt[3] + (row \\* gt[5])" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": null, 85 | "metadata": {}, 86 | "outputs": [], 87 | "source": [ 88 | "ul_x = gt[0]\n", 89 | "ul_y = gt[3]\n", 90 | "cs_x = gt[1]\n", 91 | "cs_y = gt[5]" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": null, 97 | "metadata": { 98 | "scrolled": true 99 | }, 100 | "outputs": [], 101 | "source": [ 102 | "dtm.GetProjection()" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": null, 108 | "metadata": {}, 109 | "outputs": [], 110 | "source": [ 111 | "nrow_out = int(nrow/scale_factor)\n", 112 | "ncol_out = int(ncol/scale_factor)\n", 113 | "cs_x_out = cs_x * scale_factor\n", 114 | "cs_y_out = cs_y * scale_factor\n", 115 | "gt_out = [ul_x, cs_x_out, gt[2], ul_y, gt[4], cs_y_out]" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "metadata": {}, 122 | "outputs": [], 123 | "source": [ 124 | "# Close las file\n", 125 | "las.close()" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": null, 131 | "metadata": { 132 | "scrolled": true 133 | }, 134 | "outputs": [], 135 | "source": [ 136 | "start = time.time()\n", 137 | "\n", 138 | "# Initialize DSM and NDHM array\n", 139 | "dsm = np.zeros((nrow_out, ncol_out), dtype=np.float32)\n", 140 | "ndhm = np.zeros((nrow_out, ncol_out), dtype=np.float32)\n", 141 | "\n", 142 | "pbar = ProgressBar()\n", 143 | "for i in pbar(range(num_points)):\n", 144 | " # Get LiDAR point\n", 145 | " p_x = points[i,0]\n", 146 | " p_y = points[i,1]\n", 147 | " p_z = points[i,2]\n", 148 | " \n", 149 | " # Get row, col index in image of the point\n", 150 | " col = int((p_x - ul_x) / cs_x_out)\n", 151 | " row = int((p_y - ul_y) / cs_y_out)\n", 152 | " col_dtm = int(col * scale_factor)\n", 153 | " row_dtm = int(row * scale_factor)\n", 154 | " \n", 155 | " # Check points outside DTM boundary\n", 156 | " if col < 0 or col >= ncol_out:\n", 157 | " print('x out of dtm boundary', p_x)\n", 158 | " continue\n", 159 | " if row < 0 or row >= nrow_out:\n", 160 | " print('y out of dtm boundary', p_y)\n", 161 | " continue\n", 162 | " \n", 163 | " # Update DSM, NDHM\n", 164 | " if dsm[row, col] < p_z:\n", 165 | " dsm[row, col] = p_z\n", 166 | " ndhm[row, col] = p_z - dtm_array[row_dtm, col_dtm]\n", 167 | " \n", 168 | "# Save output\n", 169 | "driver = gdal.GetDriverByName(out_format)\n", 170 | "ndhm_ds = driver.Create(ndhm_fn, xsize=ncol_out, ysize=nrow_out, bands=1, eType=gdal.GDT_Float32)\n", 171 | "ndhm_ds.SetProjection(dtm.GetProjection())\n", 172 | "ndhm_ds.SetGeoTransform(gt_out)\n", 173 | "ndhm_ds.GetRasterBand(1).WriteArray(ndhm)\n", 174 | "ndhm_ds = None\n", 175 | "\n", 176 | "# Print elapsed time\n", 177 | "end = time.time()\n", 178 | "print('Elapsed time:', int(end - start))" 179 | ] 180 | } 181 | ], 182 | "metadata": { 183 | "kernelspec": { 184 | "display_name": "Python 3", 185 | "language": "python", 186 | "name": "python3" 187 | }, 188 | "language_info": { 189 | "codemirror_mode": { 190 | "name": "ipython", 191 | "version": 3 192 | }, 193 | "file_extension": ".py", 194 | "mimetype": "text/x-python", 195 | "name": "python", 196 | "nbconvert_exporter": "python", 197 | "pygments_lexer": "ipython3", 198 | "version": "3.8.3" 199 | } 200 | }, 201 | "nbformat": 4, 202 | "nbformat_minor": 2 203 | } 204 | -------------------------------------------------------------------------------- /example_data/in2018_29651885_12.laz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gdslab/tutorial_lidar_processing_with_python/d37337b4eee4c472bc5e8d6b4d20601560be2924/example_data/in2018_29651885_12.laz -------------------------------------------------------------------------------- /example_data/in2018_29651885_12_dtm.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gdslab/tutorial_lidar_processing_with_python/d37337b4eee4c472bc5e8d6b4d20601560be2924/example_data/in2018_29651885_12_dtm.img --------------------------------------------------------------------------------