diff --git a/.gitattributes b/.gitattributes index 6f6b1096141..ed7c1989f2d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ # Do not change line endings on test data, it will change the MD5 -/tests/data/** binary +/tests/data/*/** binary diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index c529da285e5..ad63dd2f034 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -62,7 +62,7 @@ jobs: if: ${{ runner.os == 'Windows' }} - name: Install conda dependencies (Windows) run: | - conda install h5py 'rasterio>=1.0' + conda install fiona h5py 'rasterio>=1.0' conda list conda info if: ${{ runner.os == 'Windows' }} diff --git a/docs/datasets.rst b/docs/datasets.rst index 3ec879edb3a..0d138ca5dd9 100644 --- a/docs/datasets.rst +++ b/docs/datasets.rst @@ -10,6 +10,11 @@ Geospatial Datasets :class:`GeoDataset` is designed for datasets that contain geospatial information, like latitude, longitude, coordinate system, and projection. Datasets containing this kind of information can be combined using :class:`ZipDataset`. +Canadian Building Footprints +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: CanadianBuildingFootprints + Chesapeake Bay High-Resolution Land Cover Project ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/notebooks/Canadian Building Footprints Dataset.ipynb b/docs/notebooks/Canadian Building Footprints Dataset.ipynb new file mode 100644 index 00000000000..1208f4d2972 --- /dev/null +++ b/docs/notebooks/Canadian Building Footprints Dataset.ipynb @@ -0,0 +1,276 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "pediatric-slovakia", + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "%load_ext autoreload\n", + "%autoreload 2\n", + "import sys\n", + "sys.path.append(\"../..\")\n", + "import os\n", + "\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from torch.utils.data import DataLoader\n", + "from torchgeo.datasets import CanadianBuildingFootprints\n", + "from torchgeo.samplers import RandomGeoSampler\n", + "from torchgeo.datasets.utils import BoundingBox" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "threatened-coverage", + "metadata": {}, + "outputs": [], + "source": [ + "ROOT_DIR = os.path.expanduser(\"~/ssdprivate/cbf/\")" + ] + }, + { + "cell_type": "markdown", + "id": "minimal-spread", + "metadata": {}, + "source": [ + "## Visualization example" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "framed-voice", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 3min 5s, sys: 1.68 s, total: 3min 7s\n", + "Wall time: 3min 6s\n" + ] + } + ], + "source": [ + "%%time\n", + "ds = CanadianBuildingFootprints(\n", + " ROOT_DIR,\n", + " download=False,\n", + " checksum=False\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "governmental-lesson", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "BoundingBox(minx=-141.008104, maxx=-52.621493, miny=41.73535, maxy=74.773117, mint=0.0, maxt=9.223372036854776e+18)" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ds.bounds" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "sustainable-visitor", + "metadata": {}, + "outputs": [], + "source": [ + "bounds = BoundingBox(-79.69096183776855,-79.68220710754395,43.78839898848133,43.79482711775757,0,1)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "eight-teach", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ds.bounds.intersects(bounds)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "massive-pipeline", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 1min, sys: 597 ms, total: 1min\n", + "Wall time: 1min\n" + ] + } + ], + "source": [ + "%%time\n", + "sample = ds[bounds]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "assumed-engine", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([642, 875])" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sample[\"masks\"].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "special-catch", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "ds.plot(sample[\"masks\"])" + ] + }, + { + "cell_type": "markdown", + "id": "special-officer", + "metadata": {}, + "source": [ + "## DataLoader example" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "outstanding-avenue", + "metadata": {}, + "outputs": [], + "source": [ + "sampler = RandomGeoSampler(\n", + " roi=ds.bounds,\n", + " size=256,\n", + " length=48\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "unexpected-europe", + "metadata": {}, + "outputs": [], + "source": [ + "dataloader = DataLoader(ds, sampler=sampler, batch_size=32)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "brutal-shade", + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "empty range for randrange() (-141, -307, -166)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_867320/547832430.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mbatch_idx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbatch\u001b[0m \u001b[0;32min\u001b[0m \u001b[0menumerate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdataloader\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbatch\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"masks\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/conda/envs/torchgeo1/lib/python3.8/site-packages/torch/utils/data/dataloader.py\u001b[0m in \u001b[0;36m__next__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 519\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_sampler_iter\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 520\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_reset\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 521\u001b[0;31m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_next_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 522\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_num_yielded\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 523\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_dataset_kind\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0m_DatasetKind\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mIterable\u001b[0m \u001b[0;32mand\u001b[0m\u001b[0;31m \u001b[0m\u001b[0;31m\\\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/conda/envs/torchgeo1/lib/python3.8/site-packages/torch/utils/data/dataloader.py\u001b[0m in \u001b[0;36m_next_data\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 558\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 559\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_next_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 560\u001b[0;31m \u001b[0mindex\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_next_index\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# may raise StopIteration\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 561\u001b[0m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_dataset_fetcher\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfetch\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# may raise StopIteration\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 562\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_pin_memory\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/conda/envs/torchgeo1/lib/python3.8/site-packages/torch/utils/data/dataloader.py\u001b[0m in \u001b[0;36m_next_index\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 510\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 511\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_next_index\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 512\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_sampler_iter\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# may raise StopIteration\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 513\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 514\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_next_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/conda/envs/torchgeo1/lib/python3.8/site-packages/torch/utils/data/sampler.py\u001b[0m in \u001b[0;36m__iter__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 224\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__iter__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m->\u001b[0m \u001b[0mIterator\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mList\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mint\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 225\u001b[0m \u001b[0mbatch\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 226\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0midx\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msampler\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 227\u001b[0m \u001b[0mbatch\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0midx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 228\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbatch\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbatch_size\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/azurefiles/torchgeo/docs/notebooks/../../torchgeo/samplers/samplers.py\u001b[0m in \u001b[0;36m__iter__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 66\u001b[0m \"\"\"\n\u001b[1;32m 67\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0m_\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 68\u001b[0;31m \u001b[0mminx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrandom\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mroi\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mminx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mroi\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmaxx\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 69\u001b[0m \u001b[0mmaxx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mminx\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 70\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/conda/envs/torchgeo1/lib/python3.8/random.py\u001b[0m in \u001b[0;36mrandint\u001b[0;34m(self, a, b)\u001b[0m\n\u001b[1;32m 246\u001b[0m \"\"\"\n\u001b[1;32m 247\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 248\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 249\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 250\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_randbelow_with_getrandbits\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/conda/envs/torchgeo1/lib/python3.8/random.py\u001b[0m in \u001b[0;36mrandrange\u001b[0;34m(self, start, stop, step, _int)\u001b[0m\n\u001b[1;32m 224\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mistart\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_randbelow\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwidth\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 225\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mstep\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 226\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"empty range for randrange() (%d, %d, %d)\"\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mistart\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mistop\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwidth\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 227\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 228\u001b[0m \u001b[0;31m# Non-unit step argument supplied.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: empty range for randrange() (-141, -307, -166)" + ] + } + ], + "source": [ + "for batch_idx, batch in enumerate(dataloader):\n", + " print(batch[\"masks\"].shape)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "peripheral-princeton", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:torchgeo1]", + "language": "python", + "name": "conda-env-torchgeo1-py" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/environment.yml b/environment.yml index bbe99bdfe9e..b0e28bd4e34 100644 --- a/environment.yml +++ b/environment.yml @@ -3,6 +3,7 @@ channels: - conda-forge dependencies: - cudatoolkit + - fiona - h5py - numpy - pip @@ -17,6 +18,7 @@ dependencies: - black[colorama]>=21b - flake8 - isort[colors]>=4.3.5 + - jupyterlab - mypy>=0.900 - omegaconf - opencv-python diff --git a/requirements.txt b/requirements.txt index aa646de2275..1d68ade3087 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,10 @@ affine black[colorama]>=21b +fiona flake8 h5py isort[colors]>=4.3.5 +jupyterlab matplotlib mypy>=0.900 numpy diff --git a/setup.cfg b/setup.cfg index 8684a4811cb..ef8b9734dab 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,6 +26,7 @@ setup_requires = setuptools>=42 install_requires = affine + fiona matplotlib numpy pillow @@ -50,6 +51,7 @@ datasets = # Optional developer requirements docs = + jupyterlab sphinx pydocstyle[toml]>=6.1 pytorch-sphinx-theme diff --git a/spack.yaml b/spack.yaml index 27b63ce59ab..bb758ba033b 100644 --- a/spack.yaml +++ b/spack.yaml @@ -5,9 +5,11 @@ spack: - "python@3.7:+bz2" - py-affine - "py-black@21:+colorama" + - py-fiona - py-flake8 - py-h5py - "py-isort@4.3.5:+colors" + - py-jupyterlab - py-matplotlib - "py-mypy@0.900:" - py-numpy diff --git a/tests/data/README.md b/tests/data/README.md index e1a44a55e02..21713df0d94 100644 --- a/tests/data/README.md +++ b/tests/data/README.md @@ -1,9 +1,11 @@ -This directory contains fake data used to test torchgeo. Depending on the type of dataset, fake data can be created in one of two ways: +This directory contains fake data used to test torchgeo. Depending on the type of dataset, fake data can be created in multiple ways: ## GeoDataset GeoDataset data can be created like so. We first open an existing data example and use it to copy the driver/CRS/transform to the fake data. +### Raster data + ```python import os @@ -25,7 +27,21 @@ cmap = src.colormap(1) dst.write_colormap(1, cmap) ``` -If the dataset expects multiple files, you can simply copy and rename the file you created. +### Vector data + +```python +import os + +import fiona + +ROOT = "/mnt/blobfuse/adam-scratch/cbf" +FILENAME = "Ontario.geojson" + +src = fiona.open(os.path.join(ROOT, FILENAME)) +dst = fiona.open(FILENAME, "w", **src.meta) +rec = next(iter(src)) +dst.write(rec) +``` ## VisionDataset diff --git a/tests/data/cbf/Alberta.zip b/tests/data/cbf/Alberta.zip new file mode 100644 index 00000000000..88f6f05a905 Binary files /dev/null and b/tests/data/cbf/Alberta.zip differ diff --git a/tests/data/cbf/BritishColumbia.zip b/tests/data/cbf/BritishColumbia.zip new file mode 100644 index 00000000000..d7697543adf Binary files /dev/null and b/tests/data/cbf/BritishColumbia.zip differ diff --git a/tests/data/cbf/Manitoba.zip b/tests/data/cbf/Manitoba.zip new file mode 100644 index 00000000000..cd811f0ad8f Binary files /dev/null and b/tests/data/cbf/Manitoba.zip differ diff --git a/tests/data/cbf/NewBrunswick.zip b/tests/data/cbf/NewBrunswick.zip new file mode 100644 index 00000000000..c74ba8d2f5e Binary files /dev/null and b/tests/data/cbf/NewBrunswick.zip differ diff --git a/tests/data/cbf/NewfoundlandAndLabrador.zip b/tests/data/cbf/NewfoundlandAndLabrador.zip new file mode 100644 index 00000000000..775afc70d69 Binary files /dev/null and b/tests/data/cbf/NewfoundlandAndLabrador.zip differ diff --git a/tests/data/cbf/NorthwestTerritories.zip b/tests/data/cbf/NorthwestTerritories.zip new file mode 100644 index 00000000000..2f717fa9f7c Binary files /dev/null and b/tests/data/cbf/NorthwestTerritories.zip differ diff --git a/tests/data/cbf/NovaScotia.zip b/tests/data/cbf/NovaScotia.zip new file mode 100644 index 00000000000..33d5b191f5f Binary files /dev/null and b/tests/data/cbf/NovaScotia.zip differ diff --git a/tests/data/cbf/Nunavut.zip b/tests/data/cbf/Nunavut.zip new file mode 100644 index 00000000000..2e43bec937c Binary files /dev/null and b/tests/data/cbf/Nunavut.zip differ diff --git a/tests/data/cbf/Ontario.zip b/tests/data/cbf/Ontario.zip new file mode 100644 index 00000000000..b669cba3636 Binary files /dev/null and b/tests/data/cbf/Ontario.zip differ diff --git a/tests/data/cbf/PrinceEdwardIsland.zip b/tests/data/cbf/PrinceEdwardIsland.zip new file mode 100644 index 00000000000..55d24681478 Binary files /dev/null and b/tests/data/cbf/PrinceEdwardIsland.zip differ diff --git a/tests/data/cbf/Quebec.zip b/tests/data/cbf/Quebec.zip new file mode 100644 index 00000000000..05a7094f9db Binary files /dev/null and b/tests/data/cbf/Quebec.zip differ diff --git a/tests/data/cbf/Saskatchewan.zip b/tests/data/cbf/Saskatchewan.zip new file mode 100644 index 00000000000..6ea3decf76f Binary files /dev/null and b/tests/data/cbf/Saskatchewan.zip differ diff --git a/tests/data/cbf/YukonTerritory.zip b/tests/data/cbf/YukonTerritory.zip new file mode 100644 index 00000000000..d32c2fadbe9 Binary files /dev/null and b/tests/data/cbf/YukonTerritory.zip differ diff --git a/tests/datasets/test_cbf.py b/tests/datasets/test_cbf.py new file mode 100644 index 00000000000..15323edb1b6 --- /dev/null +++ b/tests/datasets/test_cbf.py @@ -0,0 +1,92 @@ +import os +import shutil +from pathlib import Path +from typing import Generator + +import matplotlib.pyplot as plt +import pytest +import torch +from _pytest.fixtures import SubRequest +from pytest import MonkeyPatch +from rasterio.crs import CRS + +import torchgeo.datasets.utils +from torchgeo.datasets import BoundingBox, CanadianBuildingFootprints, ZipDataset +from torchgeo.transforms import Identity + + +def download_url(url: str, root: str, *args: str) -> None: + shutil.copy(url, root) + + +class TestCanadianBuildingFootprints: + @pytest.fixture + def dataset( + self, + monkeypatch: Generator[MonkeyPatch, None, None], + tmp_path: Path, + request: SubRequest, + ) -> CanadianBuildingFootprints: + monkeypatch.setattr( # type: ignore[attr-defined] + torchgeo.datasets.utils, "download_url", download_url + ) + md5s = [ + "aef9a3deb3297f225d6cdb221cb48527", + "2b7872c4121116fda8f96490daf89d29", + "c71ded923e22569b62b00da2d2a61076", + "75a8f652531790c3c3aefc0655400d6d", + "89ff9c6257efa99365a8b709dde9579b", + "d4d6a36ed834df5cbf5254effca78a4d", + "cce85f6183427e3034704cf35919c985", + "0149c7ec5101c0309c79b7e695dcb394", + "b05216155725f48937804371b945f8ae", + "72d0e6d7196345ca520c825697cc4947", + "77e1c6c71ff0efbdd221b7e7d4a5f2df", + "86e32374f068c7bbb76aa81af0736733", + "5e453a3426b0bb986b2837b85e8b8850", + ] + monkeypatch.setattr( # type: ignore[attr-defined] + CanadianBuildingFootprints, "md5s", md5s + ) + url = os.path.join("tests", "data", "cbf") + os.sep + monkeypatch.setattr( # type: ignore[attr-defined] + CanadianBuildingFootprints, "url", url + ) + monkeypatch.setattr( # type: ignore[attr-defined] + plt, "show", lambda *args: None + ) + (tmp_path / "cbf").mkdir() + root = str(tmp_path) + transforms = Identity() + return CanadianBuildingFootprints( + root, transforms=transforms, download=True, checksum=True + ) + + def test_getitem(self, dataset: CanadianBuildingFootprints) -> None: + x = dataset[dataset.bounds] + assert isinstance(x, dict) + assert isinstance(x["crs"], CRS) + assert isinstance(x["masks"], torch.Tensor) + + def test_add(self, dataset: CanadianBuildingFootprints) -> None: + ds = dataset + dataset + assert isinstance(ds, ZipDataset) + + def test_already_downloaded(self, dataset: CanadianBuildingFootprints) -> None: + CanadianBuildingFootprints(root=dataset.root, download=True) + + def test_plot(self, dataset: CanadianBuildingFootprints) -> None: + query = dataset.bounds + x = dataset[query] + dataset.plot(x["masks"]) + + def test_not_downloaded(self, tmp_path: Path) -> None: + with pytest.raises(RuntimeError, match="Dataset not found or corrupted."): + CanadianBuildingFootprints(str(tmp_path)) + + def test_invalid_query(self, dataset: CanadianBuildingFootprints) -> None: + query = BoundingBox(0, 0, 0, 0, 0, 0) + with pytest.raises( + IndexError, match="query: .* is not within bounds of the index:" + ): + dataset[query] diff --git a/torchgeo/datasets/__init__.py b/torchgeo/datasets/__init__.py index 63fb85e0cf2..6a7b8e9afd2 100644 --- a/torchgeo/datasets/__init__.py +++ b/torchgeo/datasets/__init__.py @@ -1,6 +1,7 @@ """TorchGeo datasets.""" from .benin_cashews import BeninSmallHolderCashews +from .cbf import CanadianBuildingFootprints from .cdl import CDL from .chesapeake import ( Chesapeake, @@ -42,6 +43,7 @@ __all__ = ( "BeninSmallHolderCashews", "BoundingBox", + "CanadianBuildingFootprints", "CDL", "collate_dict", "Chesapeake", diff --git a/torchgeo/datasets/cbf.py b/torchgeo/datasets/cbf.py new file mode 100644 index 00000000000..64c45ba05b1 --- /dev/null +++ b/torchgeo/datasets/cbf.py @@ -0,0 +1,216 @@ +"""Canadian Building Footprints dataset.""" + +import glob +import os +import sys +from typing import Any, Callable, Dict, Optional + +import fiona +import fiona.transform +import matplotlib.pyplot as plt +import rasterio +import torch +from rasterio.crs import CRS +from rtree.index import Index, Property +from torch import Tensor + +from .geo import GeoDataset +from .utils import BoundingBox, check_integrity, download_and_extract_archive + +_crs = CRS.from_epsg(4326) + + +class CanadianBuildingFootprints(GeoDataset): + """Canadian Building Footprints dataset. + + The `Canadian Building Footprints + `_ dataset contains + 11,842,186 computer generated building footprints in all Canadian provinces and + territories in GeoJSON format. This data is freely available for download and use. + """ + + # TODO: how does one cite this dataset? + # https://github.com/microsoft/CanadianBuildingFootprints/issues/11 + + url = "https://usbuildingdata.blob.core.windows.net/canadian-buildings-v2/" + provinces_territories = [ + "Alberta", + "BritishColumbia", + "Manitoba", + "NewBrunswick", + "NewfoundlandAndLabrador", + "NorthwestTerritories", + "NovaScotia", + "Nunavut", + "Ontario", + "PrinceEdwardIsland", + "Quebec", + "Saskatchewan", + "YukonTerritory", + ] + md5s = [ + "8b4190424e57bb0902bd8ecb95a9235b", + "fea05d6eb0006710729c675de63db839", + "adf11187362624d68f9c69aaa693c46f", + "44269d4ec89521735389ef9752ee8642", + "65dd92b1f3f5f7222ae5edfad616d266", + "346d70a682b95b451b81b47f660fd0e2", + "bd57cb1a7822d72610215fca20a12602", + "c1f29b73cdff9a6a9dd7d086b31ef2cf", + "76ba4b7059c5717989ce34977cad42b2", + "2e4a3fa47b3558503e61572c59ac5963", + "9ff4417ae00354d39a0cf193c8df592c", + "a51078d8e60082c7d3a3818240da6dd5", + "c11f3bd914ecabd7cac2cb2871ec0261", + ] + + def __init__( + self, + root: str = "data", + crs: CRS = _crs, + res: float = 0.00001, + transforms: Optional[Callable[[Dict[str, Any]], Dict[str, Any]]] = None, + download: bool = False, + checksum: bool = False, + ) -> None: + """Initialize a new Canadian Building Footprints dataset. + + Args: + root: root directory where dataset can be found + crs: :term:`coordinate reference system (CRS)` to project to + res: resolution to use when rasterizing features + transforms: a function/transform that takes input sample and its target as + entry and returns a transformed version + download: if True, download dataset and store it in the root directory + checksum: if True, check the MD5 of the downloaded files (may be slow) + + Raises: + RuntimeError: if ``download=False`` and data is not found, or + ``checksum=True`` and checksums don't match + """ + self.root = root + self.crs = crs + self.res = res + self.transforms = transforms + self.checksum = checksum + + if download: + self._download() + + if not self._check_integrity(): + raise RuntimeError( + "Dataset not found or corrupted. " + + "You can use download=True to download it" + ) + + # Create an R-tree to index the dataset + self.index = Index(interleaved=False, properties=Property(dimension=3)) + fileglob = os.path.join(root, "**.geojson") + for i, filename in enumerate(glob.iglob(fileglob, recursive=True)): + with fiona.open(filename) as src: + minx, miny, maxx, maxy = src.bounds + (minx, maxx), (miny, maxy) = fiona.transform.transform( + src.crs, crs.to_dict(), [minx, maxx], [miny, maxy] + ) + mint = 0 + maxt = sys.maxsize + coords = (minx, maxx, miny, maxy, mint, maxt) + self.index.insert(i, coords, filename) + + def __getitem__(self, query: BoundingBox) -> Dict[str, Any]: + """Retrieve image and metadata indexed by query. + + Args: + query: (minx, maxx, miny, maxy, mint, maxt) coordinates to index + + Returns: + sample of labels and metadata at that index + + Raises: + IndexError: if query is not within bounds of the index + """ + if not query.intersects(self.bounds): + raise IndexError( + f"query: {query} is not within bounds of the index: {self.bounds}" + ) + + hits = self.index.intersection(query, objects=True) + filename = next(hits).object # TODO: this assumes there is only a single hit + shapes = [] + with fiona.open(filename) as src: + # We need to know the bounding box of the query in the source CRS + (minx, maxx), (miny, maxy) = fiona.transform.transform( + self.crs.to_dict(), + src.crs, + [query.minx, query.maxx], + [query.miny, query.maxy], + ) + + # Filter geometries to those that intersect with the bounding box + for feature in src.filter(bbox=(minx, miny, maxx, maxy)): + # Warp geometries to requested CRS + shape = fiona.transform.transform_geom( + src.crs, self.crs.to_dict(), feature["geometry"] + ) + shapes.append(shape) + + # Rasterize geometries + width = (query.maxx - query.minx) / self.res + height = (query.maxy - query.miny) / self.res + transform = rasterio.transform.from_bounds( + query.minx, query.miny, query.maxx, query.maxy, width, height + ) + masks = rasterio.features.rasterize( + shapes, out_shape=(int(height), int(width)), transform=transform + ) + + sample = { + "masks": torch.tensor(masks), # type: ignore[attr-defined] + "crs": self.crs, + "bbox": query, + } + + if self.transforms is not None: + sample = self.transforms(sample) + + return sample + + def _check_integrity(self) -> bool: + """Check integrity of dataset. + + Returns: + True if dataset files are found and/or MD5s match, else False + """ + for prov_terr, md5 in zip(self.provinces_territories, self.md5s): + filepath = os.path.join(self.root, prov_terr + ".zip") + if not check_integrity(filepath, md5 if self.checksum else None): + return False + return True + + def _download(self) -> None: + """Download the dataset and extract it.""" + if self._check_integrity(): + print("Files already downloaded and verified") + return + + for prov_terr, md5 in zip(self.provinces_territories, self.md5s): + download_and_extract_archive( + self.url + prov_terr + ".zip", + self.root, + md5=md5 if self.checksum else None, + ) + + def plot(self, image: Tensor) -> None: + """Plot an image on a map. + + Args: + image: the image to plot + """ + array = image.squeeze().numpy() + + # Plot the image + ax = plt.axes() + ax.imshow(array) + ax.axis("off") + plt.show() + plt.close()