├── .coveragerc ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .isort.cfg ├── .pre-commit-config.yaml ├── .readthedocs.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE.txt ├── README-ES.md ├── README.md ├── docs ├── Makefile ├── _static │ └── .gitignore ├── changelog.md ├── conf.py ├── index.md ├── installation.md ├── readme.md └── requirements.txt ├── poetry.lock ├── pyproject.toml ├── tests ├── conftest.py ├── data │ ├── gt_basurales_4326.geojson │ ├── results │ │ ├── 0000054272-0000054272_13_37.tif │ │ ├── 0000054272-0000054272_13_38.tif │ │ ├── 0000054272-0000054272_13_39.tif │ │ ├── 0000054272-0000054272_13_40.tif │ │ ├── 0000054272-0000054272_14_37.tif │ │ ├── 0000054272-0000054272_14_38.tif │ │ ├── 0000054272-0000054272_14_39.tif │ │ ├── 0000054272-0000054272_14_40.tif │ │ ├── 0000054272-0000054272_15_37.tif │ │ ├── 0000054272-0000054272_15_38.tif │ │ ├── 0000054272-0000054272_15_39.tif │ │ ├── 0000054272-0000054272_15_40.tif │ │ ├── 0000054272-0000054272_16_37.tif │ │ ├── 0000054272-0000054272_16_38.tif │ │ ├── 0000054272-0000054272_16_39.tif │ │ ├── 0000054272-0000054272_16_40.tif │ │ ├── 0000054272-0000054272_17_37.tif │ │ ├── 0000054272-0000054272_17_38.tif │ │ ├── 0000054272-0000054272_17_39.tif │ │ └── 0000054272-0000054272_17_40.tif │ └── train │ │ ├── extent │ │ ├── 0000054272-0000054272_13_37.tif │ │ ├── 0000054272-0000054272_13_38.tif │ │ ├── 0000054272-0000054272_13_39.tif │ │ ├── 0000054272-0000054272_13_40.tif │ │ ├── 0000054272-0000054272_14_37.tif │ │ ├── 0000054272-0000054272_14_38.tif │ │ ├── 0000054272-0000054272_14_39.tif │ │ ├── 0000054272-0000054272_14_40.tif │ │ ├── 0000054272-0000054272_15_37.tif │ │ ├── 0000054272-0000054272_15_38.tif │ │ ├── 0000054272-0000054272_15_39.tif │ │ ├── 0000054272-0000054272_15_40.tif │ │ ├── 0000054272-0000054272_16_37.tif │ │ ├── 0000054272-0000054272_16_38.tif │ │ ├── 0000054272-0000054272_16_39.tif │ │ ├── 0000054272-0000054272_16_40.tif │ │ ├── 0000054272-0000054272_17_37.tif │ │ ├── 0000054272-0000054272_17_38.tif │ │ ├── 0000054272-0000054272_17_39.tif │ │ └── 0000054272-0000054272_17_40.tif │ │ └── images │ │ ├── 0000054272-0000054272_13_37.tif │ │ ├── 0000054272-0000054272_13_38.tif │ │ ├── 0000054272-0000054272_13_39.tif │ │ ├── 0000054272-0000054272_13_40.tif │ │ ├── 0000054272-0000054272_14_37.tif │ │ ├── 0000054272-0000054272_14_38.tif │ │ ├── 0000054272-0000054272_14_39.tif │ │ ├── 0000054272-0000054272_14_40.tif │ │ ├── 0000054272-0000054272_15_37.tif │ │ ├── 0000054272-0000054272_15_38.tif │ │ ├── 0000054272-0000054272_15_39.tif │ │ ├── 0000054272-0000054272_15_40.tif │ │ ├── 0000054272-0000054272_16_37.tif │ │ ├── 0000054272-0000054272_16_38.tif │ │ ├── 0000054272-0000054272_16_39.tif │ │ ├── 0000054272-0000054272_16_40.tif │ │ ├── 0000054272-0000054272_17_37.tif │ │ ├── 0000054272-0000054272_17_38.tif │ │ ├── 0000054272-0000054272_17_39.tif │ │ └── 0000054272-0000054272_17_40.tif ├── test_evaluate.py ├── test_postprocess.py ├── test_predict.py └── test_train.py └── unetseg ├── __init__.py ├── console ├── predict.py └── train.py ├── evaluate.py ├── postprocess.py ├── predict.py ├── train.py └── utils.py /.coveragerc: -------------------------------------------------------------------------------- 1 | # .coveragerc to control coverage.py 2 | [run] 3 | branch = True 4 | source = unetseg 5 | # omit = bad_file.py 6 | 7 | [paths] 8 | source = 9 | src/ 10 | */site-packages/ 11 | 12 | [report] 13 | # Regexes for lines to exclude from consideration 14 | exclude_lines = 15 | # Have to re-enable the standard pragma 16 | pragma: no cover 17 | 18 | # Don't complain about missing debug-only code: 19 | def __repr__ 20 | if self\.debug 21 | 22 | # Don't complain if tests don't hit defensive assertion code: 23 | raise AssertionError 24 | raise NotImplementedError 25 | 26 | # Don't complain if non-runnable code isn't run: 27 | if 0: 28 | if __name__ == .__main__.: 29 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the workflow will run 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the main branch 8 | push: 9 | branches: [main] 10 | pull_request: 11 | branches: [main] 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | jobs: 17 | test: 18 | runs-on: ${{ matrix.os }} 19 | strategy: 20 | matrix: 21 | python-version: ["3.8", "3.9", "3.10"] 22 | os: [ubuntu-latest] 23 | 24 | steps: 25 | - name: Install dependencies (GDAL) 26 | run: | 27 | sudo apt install libgdal-dev gdal-bin 28 | gdal-config --version 29 | shell: bash 30 | 31 | - uses: actions/checkout@v2 32 | - name: Install Poetry 33 | run: | 34 | pip3 install poetry 35 | shell: bash 36 | 37 | - name: Install dependencies 38 | run: | 39 | poetry install 40 | 41 | - name: Run tests 42 | run: | 43 | poetry run pytest 44 | 45 | - name: "Upload coverage to Codecov" 46 | uses: codecov/codecov-action@v2 47 | with: 48 | fail_ci_if_error: true 49 | token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Temporary and binary files 2 | *~ 3 | *.py[cod] 4 | *.so 5 | *.cfg 6 | !.isort.cfg 7 | !setup.cfg 8 | *.orig 9 | *.log 10 | *.pot 11 | __pycache__/* 12 | .cache/* 13 | .*.swp 14 | */.ipynb_checkpoints/* 15 | .DS_Store 16 | 17 | # Project files 18 | .ropeproject 19 | .project 20 | .pydevproject 21 | .settings 22 | .idea 23 | .vscode 24 | tags 25 | 26 | # Package files 27 | *.egg 28 | *.eggs/ 29 | .installed.cfg 30 | *.egg-info 31 | 32 | # Unittest and coverage 33 | htmlcov/* 34 | .coverage 35 | .coverage.* 36 | .tox 37 | junit*.xml 38 | coverage.xml 39 | .pytest_cache/ 40 | 41 | # Build and docs folder/files 42 | build/* 43 | dist/* 44 | sdist/* 45 | docs/api/* 46 | docs/_rst/* 47 | docs/_build/* 48 | cover/* 49 | MANIFEST 50 | 51 | # Per-project virtualenvs 52 | .venv*/ 53 | .conda*/ 54 | -------------------------------------------------------------------------------- /.isort.cfg: -------------------------------------------------------------------------------- 1 | [settings] 2 | profile = black 3 | known_first_party = unetseg 4 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | exclude: "^docs/conf.py" 2 | 3 | repos: 4 | - repo: git://github.com/pre-commit/pre-commit-hooks 5 | rev: v3.4.0 6 | hooks: 7 | - id: trailing-whitespace 8 | - id: check-added-large-files 9 | - id: check-ast 10 | - id: check-json 11 | - id: check-merge-conflict 12 | - id: check-xml 13 | - id: check-yaml 14 | - id: debug-statements 15 | - id: end-of-file-fixer 16 | - id: requirements-txt-fixer 17 | - id: mixed-line-ending 18 | args: ["--fix=auto"] # replace 'auto' with 'lf' to enforce Linux/Mac line endings or 'crlf' for Windows 19 | 20 | ## If you want to avoid flake8 errors due to unused vars or imports: 21 | # - repo: https://github.com/myint/autoflake.git 22 | # rev: v1.4 23 | # hooks: 24 | # - id: autoflake 25 | # args: [ 26 | # --in-place, 27 | # --remove-all-unused-imports, 28 | # --remove-unused-variables, 29 | # ] 30 | 31 | - repo: https://github.com/pycqa/isort 32 | rev: 5.8.0 33 | hooks: 34 | - id: isort 35 | 36 | - repo: https://github.com/psf/black 37 | rev: 20.8b1 38 | hooks: 39 | - id: black 40 | language_version: python3 41 | 42 | ## If like to embrace black styles even in the docs: 43 | # - repo: https://github.com/asottile/blacken-docs 44 | # rev: v1.9.1 45 | # hooks: 46 | # - id: blacken-docs 47 | # additional_dependencies: [black] 48 | - repo: https://gitlab.com/pycqa/flake8 49 | rev: 3.9.1 50 | hooks: 51 | - id: flake8 52 | args: ["--ignore=E501"] 53 | ## You can add flake8 plugins via `additional_dependencies`: 54 | # additional_dependencies: [flake8-bugbear] 55 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Build documentation in the docs/ directory with Sphinx 8 | sphinx: 9 | configuration: docs/conf.py 10 | fail_on_warning: true 11 | 12 | # Build documentation with MkDocs 13 | #mkdocs: 14 | # configuration: mkdocs.yml 15 | 16 | # Optionally build your docs in additional formats such as PDF 17 | formats: 18 | - pdf 19 | 20 | python: 21 | version: 3.8 22 | install: 23 | - requirements: docs/requirements.txt 24 | 25 | build: 26 | apt_packages: 27 | - libgdal-dev 28 | - gdal-bin 29 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [0.2.4] - 2023-06-29 9 | 10 | ### Changed 11 | 12 | * Use field from dataclasses for `class_weights` default value 13 | 14 | ## [0.2.3] - 2023-04-11 15 | 16 | ### Added 17 | 18 | * Save Tensorboard and CSV logs when training 19 | 20 | ## [0.2.1] - 2022-02-02 21 | 22 | ### Changed 23 | 24 | - fix(evaluate): Change `masks` to `extent` 25 | 26 | ## [0.2.0] - 2022-01-13 27 | 28 | ### Added 29 | 30 | - New `masks_path` training config attribute for specifying a custom directory for masks 31 | 32 | ### Changed 33 | 34 | - Upgrade to Tensorflow 2+ 35 | - Support for satproc >= 0.1.8 36 | - Depend on Python >= 3.7 37 | 38 | ## [0.1.10] - 2022-01-11 39 | 40 | ### Changed 41 | 42 | - Force requirement to Python < 3.8 (caused by dependency to TF 1.15) 43 | - Add missing dependencies 44 | - Update docstrings 45 | 46 | ## [0.1.5] - 2021-08-18 47 | 48 | ### Added 49 | 50 | - New model Unet++ and setting `model_architecture` on training config object 51 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | damian@dymaxionlabs.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README-ES.md: -------------------------------------------------------------------------------- 1 | _Esta herramienta digital forma parte del catálogo de herramientas del **Banco Interamericano de Desarrollo**. Puedes conocer más sobre la iniciativa del BID en [code.iadb.org](https://code.iadb.org)_ 2 | 3 |

4 | 5 |

6 | 7 |

unetseg

8 | 9 |

10 | Segmentación semántica U-Net para imágenes de satélite 11 |

12 | 13 |

14 | 15 | 16 | 17 |

18 | 19 |

• 20 | Descripción • 21 | Contribuyendo • 22 | Autores • 23 | Licencia • 24 |

25 | 26 |
27 | 28 | ## :information_source: Descripción 29 | 30 | Paquete de Python de la implementación de un modelo de _deep learning_ para segmentación semántica basada en la arquitectura U-Net. Utiliza [Tensorflow](https://www.tensorflow.org/) y [Keras](https://keras.io/) para definir y entrenar el modelo. 31 | 32 | Sirve para cualquier caso de uso donde se quiera delimitar el contorno de un objeto de interés, y está especialmente afinado para imágenes multiespectrales de satelitales, aéreas y de drones, de distinta resolución espacial. 33 | 34 |
35 | 36 | ## :handshake: Contribuyendo 37 | 38 | Informes de bugs y pull requests son bienvenidos en GitHub en la [página de issues](https://github.com/dymaxionlabs/unetseg/issues). Este proyecto está destinado a ser un espacio seguro y acogedor para la colaboración, y se espera que los colaboradores sigan el código de conducta de [Contributor Covenant](http://contributor-covenant.org). 39 | 40 |
41 | 42 | ## :man_technologist: Autores 43 | 44 | - Damián Silvani: 45 | - María Roberta Devesa: 46 | - Gessica Paniagua: 47 | - Federico Bayle: 48 | - Alan Toris 49 | 50 |
51 | 52 | ## :page_facing_up: Licencia 53 | 54 | Este proyecto tiene licencia de Apache 2.0. Ver [LICENSE.txt](LICENSE.txt). 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # unetseg 2 | 3 | U-Net semantic segmentation for satellite imagery 4 | 5 | [![Pypi](https://img.shields.io/pypi/v/unetseg.svg)](https://pypi.python.org/pypi/unetseg) 6 | [![CI](https://github.com/dymaxionlabs/unetseg/actions/workflows/main.yml/badge.svg)](https://github.com/dymaxionlabs/unetseg/actions/workflows/main.yml) 7 | [![codecov](https://codecov.io/gh/dymaxionlabs/unetseg/branch/main/graph/badge.svg?token=M092LPM03I)](https://codecov.io/gh/dymaxionlabs/unetseg) 8 | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=dymaxionlabs_unetseg&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=dymaxionlabs_unetseg) 9 | [![Issues](https://img.shields.io/github/issues-closed/dymaxionlabs/unetseg)](https://github.com/dymaxionlabs/unetseg/issues) 10 | [![License](https://img.shields.io/github/license/dymaxionlabs/unetseg)](https://github.com/dymaxionlabs/unetseg/blob/main/LICENSE.txt) 11 | [![Join the chat at https://gitter.im/dymaxionlabs/unetseg](https://badges.gitter.im/dymaxionlabs/unetseg.svg)](https://gitter.im/dymaxionlabs/unetseg?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 12 | 13 | _This digital tool is part of the catalog of tools of the **Inter-American Development Bank**. You can learn more about the IDB initiative at [code.iadb.org](https://code.iadb.org)_ 14 | 15 | ## Description 16 | 17 | A set of classes and CLI tools for training a semantic segmentation model based 18 | on the U-Net architecture, using [Tensorflow](https://www.tensorflow.org/) and [Keras](https://keras.io/). 19 | 20 | This implementation is tuned specifically for satellite imagery and other 21 | geospatial raster data. 22 | 23 | ## Documentation 24 | 25 | * [Stable](https://unetseg.readthedocs.io/en/stable/) 26 | * [Latest](https://unetseg.readthedocs.io/en/latest/) 27 | 28 | ## Bugs / Questions 29 | 30 | * [Report bugs/feature requests](https://github.com/dymaxionlabs/unetseg/issues) 31 | * [Ask questions in our chat room](https://gitter.im/dymaxionlabs/satproc) 32 | 33 | ## Contributing 34 | 35 | Bug reports and pull requests are welcome on GitHub at the [issues 36 | page](https://github.com/dymaxionlabs/unetseg/issues). This project is intended to be 37 | a safe, welcoming space for collaboration, and contributors are expected to 38 | adhere to the [Contributor Covenant](http://contributor-covenant.org) code of 39 | conduct. 40 | 41 | 42 | 43 | 44 | 45 | Made with [contrib.rocks](https://contrib.rocks). 46 | 47 | The current roadmap is available at GitHub at the 48 | [projects page](https://github.com/dymaxionlabs/unetseg/projects/1). 49 | 50 | ## License 51 | 52 | This project is licensed under Apache 2.0. Refer to 53 | [LICENSE.txt](https://github.com/dymaxionlabs/unetseg/blob/main/LICENSE.txt). 54 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | AUTODOCDIR = api 11 | 12 | # User-friendly check for sphinx-build 13 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $?), 1) 14 | $(error "The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/") 15 | endif 16 | 17 | .PHONY: help clean Makefile 18 | 19 | # Put it first so that "make" without argument is like "make help". 20 | help: 21 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 22 | 23 | clean: 24 | rm -rf $(BUILDDIR)/* $(AUTODOCDIR) 25 | 26 | # Catch-all target: route all unknown targets to Sphinx using the new 27 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 28 | %: Makefile 29 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 30 | -------------------------------------------------------------------------------- /docs/_static/.gitignore: -------------------------------------------------------------------------------- 1 | # Empty directory 2 | -------------------------------------------------------------------------------- /docs/changelog.md: -------------------------------------------------------------------------------- 1 | ../CHANGELOG.md -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # This file is execfile()d with the current directory set to its containing dir. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | # 7 | # All configuration values have a default; values that are commented out 8 | # serve to show the default. 9 | 10 | import os 11 | import sys 12 | import inspect 13 | import shutil 14 | import sphinx_rtd_theme 15 | 16 | # -- Path setup -------------------------------------------------------------- 17 | 18 | __location__ = os.path.join( 19 | os.getcwd(), os.path.dirname(inspect.getfile(inspect.currentframe())) 20 | ) 21 | 22 | # If extensions (or modules to document with autodoc) are in another directory, 23 | # add these directories to sys.path here. If the directory is relative to the 24 | # documentation root, use os.path.abspath to make it absolute, like shown here. 25 | sys.path.insert(0, os.path.join(__location__, "..")) 26 | 27 | # -- Run sphinx-apidoc ------------------------------------------------------- 28 | # This hack is necessary since RTD does not issue `sphinx-apidoc` before running 29 | # `sphinx-build -b html . _build/html`. See Issue: 30 | # https://github.com/rtfd/readthedocs.org/issues/1139 31 | # DON'T FORGET: Check the box "Install your project inside a virtualenv using 32 | # setup.py install" in the RTD Advanced Settings. 33 | # Additionally it helps us to avoid running apidoc manually 34 | 35 | try: # for Sphinx >= 1.7 36 | from sphinx.ext import apidoc 37 | except ImportError: 38 | from sphinx import apidoc 39 | 40 | output_dir = os.path.join(__location__, "api") 41 | module_dir = os.path.join(__location__, "../unetseg") 42 | try: 43 | shutil.rmtree(output_dir) 44 | except FileNotFoundError: 45 | pass 46 | 47 | try: 48 | import sphinx 49 | 50 | cmd_line_template = ( 51 | "sphinx-apidoc --implicit-namespaces -f -o {outputdir} {moduledir}" 52 | ) 53 | cmd_line = cmd_line_template.format(outputdir=output_dir, moduledir=module_dir) 54 | 55 | args = cmd_line.split(" ") 56 | if tuple(sphinx.__version__.split(".")) >= ("1", "7"): 57 | # This is a rudimentary parse_version to avoid external dependencies 58 | args = args[1:] 59 | 60 | apidoc.main(args) 61 | except Exception as e: 62 | print("Running `sphinx-apidoc` failed!\n{}".format(e)) 63 | 64 | # -- General configuration --------------------------------------------------- 65 | 66 | # If your documentation needs a minimal Sphinx version, state it here. 67 | # needs_sphinx = '1.0' 68 | 69 | # Add any Sphinx extension module names here, as strings. They can be extensions 70 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 71 | extensions = [ 72 | "sphinx.ext.autodoc", 73 | "sphinx.ext.intersphinx", 74 | "sphinx.ext.todo", 75 | "sphinx.ext.autosummary", 76 | "sphinx.ext.viewcode", 77 | "sphinx.ext.coverage", 78 | "sphinx.ext.doctest", 79 | "sphinx.ext.ifconfig", 80 | "sphinx.ext.mathjax", 81 | "sphinx.ext.napoleon", 82 | "sphinx_rtd_theme", 83 | ] 84 | 85 | # Add any paths that contain templates here, relative to this directory. 86 | templates_path = ["_templates"] 87 | 88 | 89 | # Configure AutoStructify 90 | # https://recommonmark.readthedocs.io/en/latest/auto_structify.html 91 | def setup(app): 92 | from recommonmark.transform import AutoStructify 93 | 94 | params = { 95 | "enable_auto_toc_tree": True, 96 | "auto_toc_tree_section": "Contents", 97 | "auto_toc_maxdepth": 2, 98 | "enable_eval_rst": True, 99 | "enable_math": True, 100 | "enable_inline_math": True, 101 | } 102 | app.add_config_value("recommonmark_config", params, True) 103 | app.add_transform(AutoStructify) 104 | 105 | 106 | # Enable markdown 107 | extensions.append("recommonmark") 108 | 109 | # The suffix of source filenames. 110 | source_suffix = [".rst", ".md"] 111 | 112 | # The encoding of source files. 113 | # source_encoding = 'utf-8-sig' 114 | 115 | # The master toctree document. 116 | master_doc = "index" 117 | 118 | # General information about the project. 119 | project = "unetseg" 120 | copyright = "2021, Dymaxion Labs" 121 | 122 | # The version info for the project you're documenting, acts as replacement for 123 | # |version| and |release|, also used in various other places throughout the 124 | # built documents. 125 | # 126 | # The short X.Y version. 127 | version = "" # Is set by calling `setup.py docs` 128 | # The full version, including alpha/beta/rc tags. 129 | release = "" # Is set by calling `setup.py docs` 130 | 131 | # The language for content autogenerated by Sphinx. Refer to documentation 132 | # for a list of supported languages. 133 | # language = None 134 | 135 | # There are two options for replacing |today|: either, you set today to some 136 | # non-false value, then it is used: 137 | # today = '' 138 | # Else, today_fmt is used as the format for a strftime call. 139 | # today_fmt = '%B %d, %Y' 140 | 141 | # List of patterns, relative to source directory, that match files and 142 | # directories to ignore when looking for source files. 143 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".venv"] 144 | 145 | # The reST default role (used for this markup: `text`) to use for all documents. 146 | # default_role = None 147 | 148 | # If true, '()' will be appended to :func: etc. cross-reference text. 149 | # add_function_parentheses = True 150 | 151 | # If true, the current module name will be prepended to all description 152 | # unit titles (such as .. function::). 153 | # add_module_names = True 154 | 155 | # If true, sectionauthor and moduleauthor directives will be shown in the 156 | # output. They are ignored by default. 157 | # show_authors = False 158 | 159 | # The name of the Pygments (syntax highlighting) style to use. 160 | pygments_style = "sphinx" 161 | 162 | # A list of ignored prefixes for module index sorting. 163 | # modindex_common_prefix = [] 164 | 165 | # If true, keep warnings as "system message" paragraphs in the built documents. 166 | # keep_warnings = False 167 | 168 | 169 | # -- Options for HTML output ------------------------------------------------- 170 | 171 | # The theme to use for HTML and HTML Help pages. See the documentation for 172 | # a list of builtin themes. 173 | html_theme = "sphinx_rtd_theme" 174 | 175 | # Theme options are theme-specific and customize the look and feel of a theme 176 | # further. For a list of options available for each theme, see the 177 | # documentation. 178 | html_theme_options = {} 179 | 180 | # Add any paths that contain custom themes here, relative to this directory. 181 | # html_theme_path = [] 182 | 183 | # The name for this set of Sphinx documents. If None, it defaults to 184 | # " v documentation". 185 | try: 186 | from unetseg import __version__ as version 187 | except ImportError: 188 | pass 189 | else: 190 | release = version 191 | 192 | # A shorter title for the navigation bar. Default is the same as html_title. 193 | # html_short_title = None 194 | 195 | # The name of an image file (relative to this directory) to place at the top 196 | # of the sidebar. 197 | # html_logo = "" 198 | 199 | # The name of an image file (within the static path) to use as favicon of the 200 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 201 | # pixels large. 202 | # html_favicon = None 203 | 204 | # Add any paths that contain custom static files (such as style sheets) here, 205 | # relative to this directory. They are copied after the builtin static files, 206 | # so a file named "default.css" will overwrite the builtin "default.css". 207 | html_static_path = ["_static"] 208 | 209 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 210 | # using the given strftime format. 211 | # html_last_updated_fmt = '%b %d, %Y' 212 | 213 | # If true, SmartyPants will be used to convert quotes and dashes to 214 | # typographically correct entities. 215 | # html_use_smartypants = True 216 | 217 | # Custom sidebar templates, maps document names to template names. 218 | # html_sidebars = {} 219 | 220 | # Additional templates that should be rendered to pages, maps page names to 221 | # template names. 222 | # html_additional_pages = {} 223 | 224 | # If false, no module index is generated. 225 | # html_domain_indices = True 226 | 227 | # If false, no index is generated. 228 | # html_use_index = True 229 | 230 | # If true, the index is split into individual pages for each letter. 231 | # html_split_index = False 232 | 233 | # If true, links to the reST sources are added to the pages. 234 | # html_show_sourcelink = True 235 | 236 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 237 | # html_show_sphinx = True 238 | 239 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 240 | # html_show_copyright = True 241 | 242 | # If true, an OpenSearch description file will be output, and all pages will 243 | # contain a tag referring to it. The value of this option must be the 244 | # base URL from which the finished HTML is served. 245 | # html_use_opensearch = '' 246 | 247 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 248 | # html_file_suffix = None 249 | 250 | # Output file base name for HTML help builder. 251 | htmlhelp_basename = "unetseg-doc" 252 | 253 | 254 | # -- Options for LaTeX output ------------------------------------------------ 255 | 256 | latex_elements = { 257 | # The paper size ("letterpaper" or "a4paper"). 258 | # "papersize": "letterpaper", 259 | # The font size ("10pt", "11pt" or "12pt"). 260 | # "pointsize": "10pt", 261 | # Additional stuff for the LaTeX preamble. 262 | # "preamble": "", 263 | } 264 | 265 | # Grouping the document tree into LaTeX files. List of tuples 266 | # (source start file, target name, title, author, documentclass [howto/manual]). 267 | latex_documents = [ 268 | ("index", "user_guide.tex", "unetseg Documentation", "Dymaxion Labs", "manual") 269 | ] 270 | 271 | # The name of an image file (relative to this directory) to place at the top of 272 | # the title page. 273 | # latex_logo = "" 274 | 275 | # For "manual" documents, if this is true, then toplevel headings are parts, 276 | # not chapters. 277 | # latex_use_parts = False 278 | 279 | # If true, show page references after internal links. 280 | # latex_show_pagerefs = False 281 | 282 | # If true, show URL addresses after external links. 283 | # latex_show_urls = False 284 | 285 | # Documents to append as an appendix to all manuals. 286 | # latex_appendices = [] 287 | 288 | # If false, no module index is generated. 289 | # latex_domain_indices = True 290 | 291 | # -- External mapping -------------------------------------------------------- 292 | python_version = ".".join(map(str, sys.version_info[0:2])) 293 | intersphinx_mapping = { 294 | "sphinx": ("http://www.sphinx-doc.org/en/stable", None), 295 | "python": ("https://docs.python.org/" + python_version, None), 296 | "matplotlib": ("https://matplotlib.org", None), 297 | "numpy": ("https://docs.scipy.org/doc/numpy", None), 298 | "sklearn": ("https://scikit-learn.org/stable", None), 299 | "pandas": ("https://pandas.pydata.org/pandas-docs/stable", None), 300 | "scipy": ("https://docs.scipy.org/doc/scipy/reference", None), 301 | "pyscaffold": ("https://pyscaffold.org/en/stable", None), 302 | } 303 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Welcome to Unetseg documentation 2 | 3 | ## Contents 4 | 5 | * [Overview](readme) 6 | * [Installation](installation) 7 | * [API Documentation](api/modules) 8 | * [Changelog](changelog) 9 | 10 | ## Indices and tables 11 | 12 | ```eval_rst 13 | * :ref:`genindex` 14 | * :ref:`modindex` 15 | * :ref:`search` 16 | ``` 17 | -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Stable release 4 | 5 | Use pip to install from PyPI: 6 | 7 | Install from pip: 8 | 9 | ``` 10 | pip install unetseg 11 | ``` 12 | 13 | ## From source 14 | 15 | The source for satproc can be installed from the GitHub repo. 16 | 17 | ``` 18 | python -m pip install git+https://github.com/dymaxionlabs/unetseg.git 19 | ``` 20 | 21 | To install for local development, you can clone the repository: 22 | 23 | ``` 24 | git clone https://github.com/dymaxionlabs/unetseg.git 25 | ``` 26 | 27 | If you don't have [Poetry](https://python-poetry.org/) installed, follow 28 | [these instructions](https://python-poetry.org/docs/master/#installing-with-the-official-installer) first. 29 | 30 | Then, install all dependencies. Poetry will automatically create a virtual environment for you: 31 | 32 | ``` 33 | cd unetseg 34 | poetry install 35 | ``` 36 | 37 | Whenever you want to bring the latest changes, just run `git pull` from the 38 | cloned repository. 39 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | # Requirements file for ReadTheDocs, check .readthedocs.yml. 2 | # To build the module reference correctly, make sure every external package 3 | # under `install_requires` in `setup.cfg` is also listed here! 4 | # sphinx_rtd_theme 5 | albumentations==1.1.0 6 | attrs==21.4.0 7 | matplotlib==3.5.1 8 | opencv-python==4.5.5.62 9 | rasterio==1.2.10 10 | recommonmark==0.7.1 11 | scikit-image==0.19.2 12 | scikit-learn==1.0.2 13 | sphinx==4.4.0 14 | sphinx_rtd_theme==1.0.0 15 | tensorflow==2.8.0 16 | tifffile==2022.2.9 17 | tqdm==4.62.3 18 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "unetseg" 3 | version = "0.2.4" 4 | description = "U-Net semantic segmentation for satellite imagery" 5 | authors = ["Damián Silvani "] 6 | license = "Apache-2.0" 7 | 8 | [tool.poetry.dependencies] 9 | python = ">=3.8,<3.11" 10 | albumentations = "^1.1.0" 11 | rasterio = "^1.3.6" 12 | matplotlib = "^3.5.1" 13 | scikit-image = "^0.19.2" 14 | scikit-learn = "^1.0.2" 15 | tensorflow = ">=2.4" 16 | tifffile = "^2022.2.9" 17 | tqdm = "^4.62.3" 18 | opencv-python = "^4.5.5" 19 | 20 | [tool.poetry.dev-dependencies] 21 | pytest = "^7.0.1" 22 | pytest-cov = "^3.0.0" 23 | black = "^22.1.0" 24 | pytest-datadir = "^1.3.1" 25 | pre-commit = "^2.17.0" 26 | Sphinx = "^4.4.0" 27 | sphinx-rtd-theme = "^1.0.0" 28 | recommonmark = "^0.7.1" 29 | 30 | [tool.pytest.ini_options] 31 | addopts = "--exitfirst --failed-first --cov=unetseg --cov-report html --cov-report xml --cov-report term" 32 | 33 | [build-system] 34 | requires = ["poetry-core>=1.0.0"] 35 | build-backend = "poetry.core.masonry.api" 36 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dummy conftest.py for unetseg. 3 | 4 | If you don't know what this is for, just leave it empty. 5 | Read more about conftest.py under: 6 | - https://docs.pytest.org/en/stable/fixture.html 7 | - https://docs.pytest.org/en/stable/writing_plugins.html 8 | """ 9 | 10 | # import pytest 11 | -------------------------------------------------------------------------------- /tests/data/gt_basurales_4326.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "name": "gt_basurales_4326", 4 | "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, 5 | "features": [ 6 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.220065251899328, -34.276064564382871 ], [ -60.218641679658816, -34.274140818111917 ], [ -60.218064555777531, -34.273794543783147 ], [ -60.219180328614684, -34.272640296020576 ], [ -60.217910656075858, -34.27144757333258 ], [ -60.215255886221939, -34.273525219305213 ], [ -60.215986909804904, -34.274525567366105 ], [ -60.215909959954061, -34.274948791545718 ], [ -60.216602508611608, -34.275795239904937 ], [ -60.216140809506577, -34.275910664681192 ], [ -60.215217411296521, -34.275025741396554 ], [ -60.214332488011884, -34.275795239904937 ], [ -60.217179632492893, -34.278373059908013 ], [ -60.220065251899328, -34.276064564382871 ] ] ] ] } }, 7 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.864172191772809, -34.44743188219946 ], [ -59.862440820128953, -34.448586129962038 ], [ -59.865057115057446, -34.451356324592211 ], [ -59.864172191772809, -34.44743188219946 ] ] ] ] } }, 8 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.702769879639774, -34.756385533314699 ], [ -59.701384782324681, -34.757578256002688 ], [ -59.702077330982227, -34.758155379883974 ], [ -59.702308180534743, -34.758078430033137 ], [ -59.702654454863513, -34.758386229436489 ], [ -59.702654454863513, -34.758770978690684 ], [ -59.703308528595635, -34.759425052422806 ], [ -59.704501251283631, -34.758578604063587 ], [ -59.704270401731115, -34.757655205853524 ], [ -59.702769879639774, -34.756385533314699 ] ] ] ] } }, 9 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.21702394622384, -34.956147346090582 ], [ -59.21867836801686, -34.958071092361536 ], [ -59.219524816376079, -34.957070744300637 ], [ -59.218101244135575, -34.955531747283878 ], [ -59.21702394622384, -34.956147346090582 ] ] ] ] } }, 10 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -58.715435962266639, -35.035944341409753 ], [ -58.714570276444711, -35.036694602455427 ], [ -58.714262477041359, -35.03746410096381 ], [ -58.712761954950011, -35.038368261711156 ], [ -58.714204764653232, -35.039176235144957 ], [ -58.715339774953094, -35.037887325143416 ], [ -58.715724524207282, -35.037348676187548 ], [ -58.715570624505602, -35.036752314843554 ], [ -58.715474437192057, -35.036675364992718 ], [ -58.715743761669991, -35.036309853201239 ], [ -58.715435962266639, -35.035944341409753 ] ] ] ] } }, 11 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -58.710145660021517, -35.036021291260596 ], [ -58.709683960916486, -35.036502227828329 ], [ -58.710722783902803, -35.037329438724839 ], [ -58.711800081814538, -35.036175190962268 ], [ -58.710838208679064, -35.035482642304729 ], [ -58.710145660021517, -35.036021291260596 ] ] ] ] } }, 12 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -57.640908245162997, -36.310147302706994 ], [ -57.641235282029058, -36.309589416288411 ], [ -57.641908593223889, -36.309762553452799 ], [ -57.641966305612023, -36.309339329273193 ], [ -57.640331121281704, -36.30878144285461 ], [ -57.639965609490226, -36.30891610509358 ], [ -57.640061796803771, -36.309608653751127 ], [ -57.640908245162997, -36.310147302706994 ] ] ] ] } }, 13 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.816722990003491, -37.694301982123264 ], [ -59.81610739119678, -37.695071480631647 ], [ -59.81610739119678, -37.695225380333319 ], [ -59.816761464928909, -37.696148778543382 ], [ -59.816684515078073, -37.697957100038082 ], [ -59.816530615376394, -37.698611173770203 ], [ -59.817261638959359, -37.699072872875234 ], [ -59.816492140450976, -37.699573046905684 ], [ -59.817877237766062, -37.700496445115746 ], [ -59.821109131501274, -37.697918625112663 ], [ -59.819069960454058, -37.696572002722988 ], [ -59.81806961239316, -37.697418451082214 ], [ -59.817530963437292, -37.697033701828019 ], [ -59.817800287915226, -37.696110303617964 ], [ -59.818338936871093, -37.695725554363769 ], [ -59.816722990003491, -37.694301982123264 ] ] ] ] } }, 14 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.266841142482036, -38.407934898797464 ], [ -60.265340620390688, -38.409204571336296 ], [ -60.266033169048235, -38.410243394322613 ], [ -60.264801971434821, -38.411666966563118 ], [ -60.266956567258291, -38.413398338206981 ], [ -60.268610989051318, -38.411859341190215 ], [ -60.26926506278344, -38.412321040295247 ], [ -60.27072710994937, -38.411936291041052 ], [ -60.272458481593233, -38.411089842681832 ], [ -60.271573558308589, -38.409820170143 ], [ -60.26891878845467, -38.410243394322613 ], [ -60.266841142482036, -38.407934898797464 ] ] ] ] } }, 15 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -62.396062752639963, -37.5546764777772 ], [ -62.394292906070682, -37.556446324346481 ], [ -62.393494551368242, -37.557437053676026 ], [ -62.394764223907075, -37.558706726214858 ], [ -62.396033896445907, -37.557706378153959 ], [ -62.396399408237386, -37.556244330988029 ], [ -62.396072371371325, -37.55574415695758 ], [ -62.396062752639963, -37.5546764777772 ] ] ] ] } }, 16 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -62.981564548937101, -36.762083395411551 ], [ -62.985488991329852, -36.759005401378019 ], [ -62.984488643268953, -36.758351327645897 ], [ -62.982449472221738, -36.759851849737238 ], [ -62.98060267580162, -36.759159301079698 ], [ -62.979679277591558, -36.75981337481182 ], [ -62.979833177293237, -36.760736773021883 ], [ -62.981564548937101, -36.762083395411551 ] ] ] ] } }, 17 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.013245076882015, -34.5713884731652 ], [ -61.012533290761759, -34.570542024805981 ], [ -61.011629130014406, -34.569984138387404 ], [ -61.010532594639962, -34.570984486448303 ], [ -61.010494119714544, -34.571330760777073 ], [ -61.009686146280742, -34.571311523314364 ], [ -61.008974360160487, -34.571119148687266 ], [ -61.011071243595829, -34.569772526297598 ], [ -61.010763444192477, -34.56923387734173 ], [ -61.008685798219844, -34.570638212119526 ], [ -61.008089436875849, -34.570657449582235 ], [ -61.007435363143721, -34.569772526297598 ], [ -61.005588566723603, -34.571138386149975 ], [ -61.007319938367466, -34.572658145704033 ], [ -61.008820460458814, -34.571523135404171 ], [ -61.009166734787584, -34.571965597046486 ], [ -61.008493423592746, -34.572985182570093 ], [ -61.01187921702963, -34.573158319734482 ], [ -61.013245076882015, -34.5713884731652 ] ] ] ] } }, 18 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.521304680472895, -35.123234328451929 ], [ -60.52334385152011, -35.122580254719807 ], [ -60.523305376594692, -35.122003130838515 ], [ -60.524305724655591, -35.121579906658908 ], [ -60.523613175998044, -35.120310234120076 ], [ -60.52057365688993, -35.121041257703041 ], [ -60.521304680472895, -35.123234328451929 ] ] ] ] } }, 19 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -58.843018814958668, -34.810615940690077 ], [ -58.842460928540092, -34.810981452481556 ], [ -58.844038400482276, -34.811924088154328 ], [ -58.844846373916077, -34.811443151586587 ], [ -58.843018814958668, -34.810615940690077 ] ] ] ] } }, 20 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.542379320871234, -33.926846903812418 ], [ -60.54261017042375, -33.927462502619129 ], [ -60.543956792813418, -33.926077405304035 ], [ -60.546765462369017, -33.926616054259902 ], [ -60.546880887145271, -33.924576883212687 ], [ -60.543879842962582, -33.924692307988948 ], [ -60.543187294305035, -33.925654181124429 ], [ -60.542379320871234, -33.926846903812418 ] ] ] ] } }, 21 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.175126539014208, -35.453416519667662 ], [ -60.174299328117698, -35.453782031459141 ], [ -60.174299328117698, -35.454147543250627 ], [ -60.174510940207504, -35.454205255638755 ], [ -60.174587890058341, -35.454590004892943 ], [ -60.175780612746337, -35.455186366236944 ], [ -60.176203836925943, -35.454686192206495 ], [ -60.176126887075107, -35.454128305787918 ], [ -60.175126539014208, -35.453416519667662 ] ] ] ] } }, 22 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.607467489380255, -38.378915186300091 ], [ -59.607294352215867, -38.379126798389898 ], [ -59.607294352215867, -38.379319173016995 ], [ -59.606832653110843, -38.379665447345765 ], [ -59.607621389081935, -38.380011721674542 ], [ -59.608102325649668, -38.379857821972863 ], [ -59.608487074903863, -38.37956926003222 ], [ -59.607467489380255, -38.378915186300091 ] ] ] ] } }, 23 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.096791590860882, -38.049358212622444 ], [ -60.095945142501662, -38.050435510534186 ], [ -60.096060567277917, -38.050858734713792 ], [ -60.096099042203335, -38.051397383669659 ], [ -60.095137169067861, -38.052166882178042 ], [ -60.094483095335733, -38.052897905761007 ], [ -60.094367670559478, -38.053782829045652 ], [ -60.095560393247467, -38.054129103374422 ], [ -60.096560741308366, -38.05332112994062 ], [ -60.09632989175585, -38.052628581283074 ], [ -60.096868540711718, -38.05201298247637 ], [ -60.097561089369265, -38.051897557700109 ], [ -60.09813821325055, -38.051166534117144 ], [ -60.098022788474296, -38.050781784862956 ], [ -60.096868540711718, -38.050512460385022 ], [ -60.096560741308366, -38.050473985459604 ], [ -60.097214815040495, -38.049781436802057 ], [ -60.096791590860882, -38.049358212622444 ] ] ] ] } }, 24 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -62.160115272507184, -38.768877792885789 ], [ -62.159384248924219, -38.768800843034953 ], [ -62.160115272507184, -38.767608120346956 ], [ -62.158961024744606, -38.767992869601152 ], [ -62.157883726832871, -38.768916267811207 ], [ -62.155844555785656, -38.769147117363723 ], [ -62.15068891577949, -38.77295613498022 ], [ -62.155652181158558, -38.776957527223807 ], [ -62.156691004144875, -38.776842102447553 ], [ -62.158537800565, -38.7757263296104 ], [ -62.159191874297122, -38.7739180081157 ], [ -62.15923034922254, -38.771263238261781 ], [ -62.159922897880087, -38.770147465424621 ], [ -62.160346122059693, -38.768800843034953 ], [ -62.160115272507184, -38.768877792885789 ] ] ] ] } }, 25 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.32644058852523, -37.935972607412253 ], [ -61.325651852554138, -37.935626333083484 ], [ -61.324651504493239, -37.936030319800388 ], [ -61.324362942552597, -37.936626681144382 ], [ -61.324478367328858, -37.936934480547734 ], [ -61.324863116583046, -37.937261517413795 ], [ -61.32478616673221, -37.937627029205281 ], [ -61.324016668223827, -37.937934828608633 ], [ -61.323824293596729, -37.938435002639082 ], [ -61.324285992701761, -37.938915939206822 ], [ -61.325363290613495, -37.938550427415336 ], [ -61.325594140166011, -37.937857878757796 ], [ -61.325671090016847, -37.937550079354445 ], [ -61.326786862854, -37.937184567562959 ], [ -61.327190849570904, -37.936780580846062 ], [ -61.326902287630261, -37.936126507113933 ], [ -61.328229672557221, -37.93520310890387 ], [ -61.328037297930123, -37.934395135470069 ], [ -61.327363986735293, -37.934472085320913 ], [ -61.326844575242134, -37.934549035171749 ], [ -61.326825337779425, -37.934953021888646 ], [ -61.327036949869225, -37.93520310890387 ], [ -61.326402113599812, -37.935741757859745 ], [ -61.32644058852523, -37.935972607412253 ] ] ] ] } }, 26 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.324247517776342, -37.939166026222047 ], [ -61.323728106283184, -37.939358400849137 ], [ -61.323304882103571, -37.939319925923719 ], [ -61.323112507476473, -37.939069838908495 ], [ -61.323131744939182, -37.93895441413224 ], [ -61.323401069417116, -37.938685089654307 ], [ -61.32367039389505, -37.938511952489918 ], [ -61.323612681506923, -37.938242628011984 ], [ -61.323170219864608, -37.938223390549275 ], [ -61.322708520759576, -37.937973303534051 ], [ -61.32234300896809, -37.938088728310312 ], [ -61.322189109266418, -37.93860813980347 ], [ -61.322189109266418, -37.938935176669531 ], [ -61.322131396878291, -37.939281450998301 ], [ -61.322227584191836, -37.939877812342296 ], [ -61.322708520759576, -37.940108661894811 ], [ -61.323150982401891, -37.939743150103332 ], [ -61.324189805388208, -37.939723912640623 ], [ -61.324247517776342, -37.939166026222047 ] ] ] ] } }, 27 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.58827812032748, -33.825965649363447 ], [ -59.588662869581668, -33.825253863243191 ], [ -59.589220756000245, -33.824484364734808 ], [ -59.589971017045919, -33.823984190704358 ], [ -59.590047966896755, -33.823560966524752 ], [ -59.589740167493403, -33.823310879509528 ], [ -59.589990254508628, -33.822599093389272 ], [ -59.588797531820639, -33.821637220253791 ], [ -59.588335832715607, -33.82181035741818 ], [ -59.588258882864764, -33.822233581597793 ], [ -59.588066508237674, -33.822387481299465 ], [ -59.587412434505545, -33.822483668613017 ], [ -59.58681607316155, -33.822945367718042 ], [ -59.585834962563361, -33.823560966524752 ], [ -59.585758012712525, -33.824041903092493 ], [ -59.58827812032748, -33.825965649363447 ] ] ] ] } }, 28 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.635352191577788, -33.710069555269641 ], [ -59.63633330217597, -33.709896418105252 ], [ -59.636544914265777, -33.709665568552744 ], [ -59.636737288892874, -33.709396244074803 ], [ -59.637275937848742, -33.709319294223967 ], [ -59.637391362625003, -33.708934544969779 ], [ -59.636948900982681, -33.708588270641002 ], [ -59.636910426057263, -33.708395896013911 ], [ -59.637256700386033, -33.707914959446171 ], [ -59.637737636953773, -33.707607160042819 ], [ -59.637641449640228, -33.707280123176751 ], [ -59.637179750535196, -33.707395547953013 ], [ -59.636679576504747, -33.707491735266558 ], [ -59.636006265309909, -33.707010798698818 ], [ -59.635467616354042, -33.706953086310691 ], [ -59.635121342025272, -33.707183935863206 ], [ -59.635005917249011, -33.708222758849523 ], [ -59.635313716652369, -33.708819120193517 ], [ -59.635332954115079, -33.708973019895197 ], [ -59.635717703369266, -33.709146157059585 ], [ -59.635813890682812, -33.709473193925646 ], [ -59.635544566204878, -33.709665568552744 ], [ -59.635352191577788, -33.710069555269641 ] ] ] ] } }, 29 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.636987375908099, -33.703509580485679 ], [ -59.636025502772618, -33.703855854814449 ], [ -59.635448378891333, -33.703567292873807 ], [ -59.635044392174436, -33.704394503770317 ], [ -59.634794305159211, -33.704779253024512 ], [ -59.634755830233786, -33.705260189592252 ], [ -59.634044044113537, -33.705202477204118 ], [ -59.633082170978057, -33.705567988995604 ], [ -59.633582345008506, -33.706164350339598 ], [ -59.632158772767994, -33.706856898997145 ], [ -59.632889796350959, -33.707607160042819 ], [ -59.634063281576246, -33.707049273624236 ], [ -59.634274893666053, -33.706953086310691 ], [ -59.63502515471172, -33.706837661534436 ], [ -59.635871603070946, -33.706222062727726 ], [ -59.635275241726944, -33.705721888697276 ], [ -59.635256004264235, -33.705337139443088 ], [ -59.635467616354042, -33.705202477204118 ], [ -59.635794653220103, -33.705587226458313 ], [ -59.636217877399716, -33.706048925563344 ], [ -59.638103148745252, -33.704798490487221 ], [ -59.636987375908099, -33.703509580485679 ] ] ] ] } }, 30 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -57.866640632597232, -38.236683005756888 ], [ -57.866871482149747, -38.234990109038449 ], [ -57.867948780061482, -38.234566884858836 ], [ -57.86910302782406, -38.233720436499617 ], [ -57.867910305136064, -38.232797038289554 ], [ -57.866525207820978, -38.233720436499617 ], [ -57.865140110505884, -38.233720436499617 ], [ -57.864716886326278, -38.234182135604648 ], [ -57.865294010207563, -38.234566884858836 ], [ -57.866294358268462, -38.235259433516383 ], [ -57.866640632597232, -38.236683005756888 ] ] ] ] } }, 31 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -57.650892488309381, -38.071798712873175 ], [ -57.64877636741133, -38.069913441527639 ], [ -57.647506694872497, -38.070413615558088 ], [ -57.646814146214957, -38.071452438544405 ], [ -57.647006520842048, -38.072914485710335 ], [ -57.648660942635075, -38.072760586008656 ], [ -57.650892488309381, -38.071798712873175 ] ] ] ] } }, 32 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -57.646940454626687, -38.072412382473594 ], [ -57.647006520842048, -38.072914485710335 ], [ -57.648200467384534, -38.072803420915683 ], [ -57.646940454626687, -38.072412382473594 ] ] ] ] } }, 33 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -57.648814842336748, -38.06975954182596 ], [ -57.650122989800998, -38.068605294063389 ], [ -57.649969090099326, -38.068105120032939 ], [ -57.651354187414412, -38.067143246897459 ], [ -57.649122641740107, -38.065527300029856 ], [ -57.647160420543727, -38.066181373761985 ], [ -57.645813798154059, -38.067143246897459 ], [ -57.648814842336748, -38.06975954182596 ] ] ] ] } }, 34 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -57.650738588607709, -38.06856681913797 ], [ -57.649661290695974, -38.069451742422608 ], [ -57.651123337861897, -38.070298190781834 ], [ -57.652316060549893, -38.069798016751385 ], [ -57.652162160848214, -38.06925936779551 ], [ -57.651777411594026, -38.068682243914225 ], [ -57.650738588607709, -38.06856681913797 ] ] ] ] } }, 35 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -57.648200467384534, -38.072803420915683 ], [ -57.646940454626687, -38.072412382473594 ], [ -57.647006520842048, -38.072914485710335 ], [ -57.648200467384534, -38.072803420915683 ] ] ] ] } }, 36 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -57.646698721438696, -38.072337361829042 ], [ -57.646083122631993, -38.073029910486589 ], [ -57.64696804591663, -38.073645509293293 ], [ -57.648930267113009, -38.073029910486589 ], [ -57.646698721438696, -38.072337361829042 ] ] ] ] } }, 37 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -56.967731712567179, -37.195840085855608 ], [ -56.967962562119695, -37.196224835109803 ], [ -56.968270361523047, -37.19578237346748 ], [ -56.968385786299308, -37.194858975257418 ], [ -56.968789773016205, -37.19447422600323 ], [ -56.969424609285625, -37.194512700928648 ], [ -56.970328770032971, -37.195070587347224 ], [ -56.970925131376973, -37.194647363167618 ], [ -56.971098268541354, -37.193185316001689 ], [ -56.971406067944713, -37.19364701510672 ], [ -56.972175566453089, -37.193704727494847 ], [ -56.971656154959931, -37.192588954657694 ], [ -56.971155980929488, -37.191896406000147 ], [ -56.970251820182135, -37.191434706895116 ], [ -56.969270709583945, -37.191511656745952 ], [ -56.968231886597628, -37.191934880925565 ], [ -56.968270361523047, -37.193166078538979 ], [ -56.968616635851824, -37.193069891225427 ], [ -56.968558923463696, -37.193550827793167 ], [ -56.968847485404339, -37.193974051972781 ], [ -56.968443498687435, -37.194281851376132 ], [ -56.967924087194277, -37.195012874959097 ], [ -56.967731712567179, -37.195840085855608 ] ] ] ] } }, 38 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.12087099126331, -34.298097748847127 ], [ -59.120743215442438, -34.298245182486589 ], [ -59.120772702170335, -34.298657996677079 ], [ -59.121382094546775, -34.298372958307453 ], [ -59.121676961825699, -34.298716970132865 ], [ -59.121952171286033, -34.298520391946916 ], [ -59.122138920562683, -34.298117406665718 ], [ -59.122276525292847, -34.29803877539134 ], [ -59.122374814385822, -34.297812710477501 ], [ -59.122650023846148, -34.29745886974279 ], [ -59.122935062215774, -34.297183660282457 ], [ -59.122876088759995, -34.296731530454778 ], [ -59.122502590206686, -34.296584096815316 ], [ -59.122020973651111, -34.296426834266555 ], [ -59.12183422437446, -34.296318716264281 ], [ -59.121568843823425, -34.296387518629366 ], [ -59.121244489816611, -34.29649563663164 ], [ -59.12070389980525, -34.29687896409424 ], [ -59.120576123984385, -34.297173831373165 ], [ -59.12067441307736, -34.297478527561381 ], [ -59.12108722726785, -34.297429383014894 ], [ -59.121126542905039, -34.297616132291552 ], [ -59.12087099126331, -34.298097748847127 ] ] ] ] } }, 39 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.122846602032098, -34.295650350432055 ], [ -59.122158578381274, -34.295984533348168 ], [ -59.122306012020736, -34.29629905844569 ], [ -59.123043180218048, -34.296731530454778 ], [ -59.123583770229409, -34.296279400627093 ], [ -59.123446165499246, -34.296014020076058 ], [ -59.123141469311022, -34.296014020076058 ], [ -59.122846602032098, -34.295650350432055 ] ] ] ] } }, 40 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -56.722210246508332, -36.701343829498221 ], [ -56.72384619360497, -36.700897037223925 ], [ -56.723997415605503, -36.700787057587178 ], [ -56.724011163060098, -36.700656456768542 ], [ -56.723956173241724, -36.700381507676667 ], [ -56.723832446150375, -36.700134053493983 ], [ -56.723688097877144, -36.700092811130197 ], [ -56.72339252760338, -36.700147800948578 ], [ -56.723206936966371, -36.700092811130197 ], [ -56.723172568329886, -36.699927841675077 ], [ -56.723365032694197, -36.699996578948046 ], [ -56.723763708877414, -36.699920967947783 ], [ -56.724004289332797, -36.699824735765624 ], [ -56.724066152878471, -36.699522291764566 ], [ -56.724004289332797, -36.699267963854588 ], [ -56.723880562241455, -36.698896782580555 ], [ -56.723811824968486, -36.698566843670314 ], [ -56.723770582604708, -36.698381253033297 ], [ -56.723591865694992, -36.698085682759533 ], [ -56.723509380967428, -36.697913839577119 ], [ -56.723330664057713, -36.697796986213071 ], [ -56.723124452238807, -36.697796986213071 ], [ -56.722945735329091, -36.697741996394697 ], [ -56.722725776055597, -36.697721375212808 ], [ -56.722684533691812, -36.697824481122261 ], [ -56.722498943054802, -36.697831354849555 ], [ -56.722320226145087, -36.697858849758738 ], [ -56.722223993962928, -36.69803069294116 ], [ -56.722127761780776, -36.698016945486565 ], [ -56.721935297416465, -36.697968829395492 ], [ -56.721845938961607, -36.698113177668723 ], [ -56.721811570325123, -36.698326263214923 ], [ -56.721790949143227, -36.698539348761123 ], [ -56.721646600869995, -36.698862413944077 ], [ -56.721756580506742, -36.699584155310241 ], [ -56.721914676234569, -36.70000345267534 ], [ -56.721942171143759, -36.700285275494508 ], [ -56.722093393144291, -36.700285275494508 ], [ -56.722388963418048, -36.700257780585325 ], [ -56.722567680327771, -36.70019591703965 ], [ -56.722718902328296, -36.700113432312094 ], [ -56.722897619238012, -36.700037821311824 ], [ -56.722980103965575, -36.700154674675872 ], [ -56.722986977692869, -36.700305896676404 ], [ -56.722986977692869, -36.700360886494778 ], [ -56.722973230238281, -36.700546477131788 ], [ -56.722925114147202, -36.700594593222867 ], [ -56.722863250601527, -36.700525855949898 ], [ -56.72277389214667, -36.700422750040445 ], [ -56.722547059145874, -36.700374633949366 ], [ -56.722464574418318, -36.700374633949366 ], [ -56.722210246508332, -36.700395255131262 ], [ -56.722182751599149, -36.700587719495573 ], [ -56.722223993962928, -36.700821426223662 ], [ -56.722265236326706, -36.701110122770125 ], [ -56.722265236326706, -36.70128883967984 ], [ -56.722210246508332, -36.701343829498221 ] ] ] ] } }, 41 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -56.722684533691812, -36.701398819316594 ], [ -56.72280138705586, -36.701570662499009 ], [ -56.723069462420433, -36.701598157408199 ], [ -56.723186315784481, -36.701845611590883 ], [ -56.723261926784744, -36.701900601409257 ], [ -56.72384619360497, -36.70179062177251 ], [ -56.724079900333066, -36.701776874317915 ], [ -56.724237996060893, -36.701598157408199 ], [ -56.724506071425466, -36.701426314225778 ], [ -56.724485450243577, -36.701089501588235 ], [ -56.724327354515751, -36.700793931314472 ], [ -56.724011163060098, -36.700835173678257 ], [ -56.72363310805877, -36.701096375315537 ], [ -56.723296295421228, -36.701130743952014 ], [ -56.723103831056918, -36.701309460861737 ], [ -56.723069462420433, -36.701446935407667 ], [ -56.722938861601797, -36.701481304044151 ], [ -56.722684533691812, -36.701398819316594 ] ] ] ] } }, 42 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -58.828340911429045, -38.516110941762228 ], [ -58.828120952155551, -38.516303406126539 ], [ -58.828258426701488, -38.51652336540004 ], [ -58.828395901247418, -38.516578355218414 ], [ -58.82856774442984, -38.516722703491645 ], [ -58.828753335066857, -38.516715829764351 ], [ -58.828684597793888, -38.516805188219209 ], [ -58.828602113066324, -38.516908294128662 ], [ -58.828416522429315, -38.517059516129187 ], [ -58.828423396156609, -38.51716262203864 ], [ -58.828560870702546, -38.517306970311871 ], [ -58.828663976611999, -38.517245106766204 ], [ -58.828815198612524, -38.51713512712945 ], [ -58.829124516340883, -38.517045768674592 ], [ -58.829179506159257, -38.517142000856751 ], [ -58.829220748523035, -38.517279475402688 ], [ -58.829310106977893, -38.517196990675124 ], [ -58.829488823887608, -38.517265727948093 ], [ -58.829509445069505, -38.51737570758484 ], [ -58.829626298433546, -38.517568171949151 ], [ -58.829619424706252, -38.517650656676715 ], [ -58.829585056069767, -38.517767510040755 ], [ -58.829646919615435, -38.517891237132098 ], [ -58.829777520434078, -38.517918732041288 ], [ -58.829942489889198, -38.517719393949683 ], [ -58.830128080526215, -38.517726267676977 ], [ -58.830134954253509, -38.517575045676452 ], [ -58.830024974616762, -38.517506308403483 ], [ -58.8297362780703, -38.517286349129982 ], [ -58.829420086614647, -38.517018273765409 ], [ -58.829578182342473, -38.517128253402156 ], [ -58.829701909433815, -38.517196990675124 ], [ -58.829963111071088, -38.517361960130245 ], [ -58.8301624491627, -38.517568171949151 ], [ -58.830506135527536, -38.517671277858604 ], [ -58.830712347346442, -38.517561298221857 ], [ -58.831111023529658, -38.517231359311609 ], [ -58.831104149802357, -38.517100758492973 ], [ -58.831028538802094, -38.516853304310281 ], [ -58.830815453255894, -38.516695208582455 ], [ -58.83061611516429, -38.516578355218414 ], [ -58.830389282163495, -38.516420259490587 ], [ -58.830148701708104, -38.516220921398983 ], [ -58.829839383979746, -38.515842866397655 ], [ -58.829605677251656, -38.515746634215503 ], [ -58.829371970523567, -38.515760381670091 ], [ -58.829200127341146, -38.515884108761433 ], [ -58.829062652795209, -38.515987214670886 ], [ -58.828870188430898, -38.516097194307633 ], [ -58.828650229157404, -38.516303406126539 ], [ -58.828499007156871, -38.516269037490055 ], [ -58.828340911429045, -38.516110941762228 ] ] ] ] } }, 43 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -58.831475331076383, -38.518489251406919 ], [ -58.8314478361672, -38.518619852225562 ], [ -58.831557815803947, -38.518743579316904 ], [ -58.831743406440964, -38.518812316589873 ], [ -58.831922123350679, -38.518984159772295 ], [ -58.83203897671472, -38.519217866500384 ], [ -58.832279557170111, -38.519293477500646 ], [ -58.832582001171168, -38.519252235136868 ], [ -58.832911940081416, -38.519032275863367 ], [ -58.832987551081679, -38.518805442862572 ], [ -58.83296692989979, -38.518626725952856 ], [ -58.832808834171963, -38.518406766679362 ], [ -58.832712601989812, -38.518331155679093 ], [ -58.832492642716311, -38.518104322678305 ], [ -58.832217693624443, -38.517932479495883 ], [ -58.832032102987426, -38.517925605768582 ], [ -58.831812143713933, -38.517959974405066 ], [ -58.831715911531774, -38.518083701496408 ], [ -58.831853386077711, -38.518269292133425 ], [ -58.831867133532306, -38.518420514133958 ], [ -58.831832764895822, -38.51846863022503 ], [ -58.831674669167995, -38.518502998861514 ], [ -58.831475331076383, -38.518489251406919 ] ] ] ] } }, 44 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -58.830361787254304, -38.517767510040755 ], [ -58.83056799907321, -38.518014964223447 ], [ -58.830746715982926, -38.518021837950741 ], [ -58.830918559165347, -38.517987469314257 ], [ -58.831062907438579, -38.517918732041288 ], [ -58.831117897256952, -38.518021837950741 ], [ -58.831310361621263, -38.518324281951799 ], [ -58.831434088712605, -38.518221176042346 ], [ -58.831454709894494, -38.517966848132367 ], [ -58.831399720076121, -38.517808752404541 ], [ -58.831324109075858, -38.517568171949151 ], [ -58.831035412529388, -38.517575045676452 ], [ -58.831028538802094, -38.517760636313461 ], [ -58.830918559165347, -38.51780187867724 ], [ -58.830849821892379, -38.517746888858866 ], [ -58.830767337164815, -38.517630035494825 ], [ -58.830581746527805, -38.517685025313199 ], [ -58.830361787254304, -38.517767510040755 ] ] ] ] } }, 45 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.256007354975665, -38.694037372839844 ], [ -61.255842385520538, -38.694167973658487 ], [ -61.25553994151948, -38.694126731294702 ], [ -61.255423088155432, -38.69421608974956 ], [ -61.255347477155169, -38.694277953295234 ], [ -61.255230623791128, -38.694374185477386 ], [ -61.255065654336001, -38.694491038841434 ], [ -61.25494880097196, -38.694546028659808 ], [ -61.254639483243601, -38.694525407477919 ], [ -61.254481387515774, -38.694463543932244 ], [ -61.254158322332827, -38.694319195659013 ], [ -61.253972731695811, -38.694449796477656 ], [ -61.253855878331763, -38.694649134569261 ], [ -61.253876499513659, -38.694759114206008 ], [ -61.253890246968247, -38.694951578570318 ], [ -61.253835257149873, -38.695109674298145 ], [ -61.253663413967452, -38.695254022571376 ], [ -61.253635919058269, -38.695418992026504 ], [ -61.25380776224069, -38.695494603026766 ], [ -61.253835257149873, -38.695693941118371 ], [ -61.25373215124042, -38.695858910573499 ], [ -61.253635919058269, -38.695879531755388 ], [ -61.253395338602878, -38.695968890210246 ], [ -61.253305980148021, -38.695996385119436 ], [ -61.25340221233018, -38.696223218120224 ], [ -61.253642792785563, -38.696346945211566 ], [ -61.253711530058531, -38.696450051121019 ], [ -61.253752772422317, -38.696553157030472 ], [ -61.253773393604206, -38.696752495122084 ], [ -61.253608424149078, -38.697006823032062 ], [ -61.253718403785832, -38.697164918759889 ], [ -61.253821509695278, -38.697199287396373 ], [ -61.254165196060121, -38.696951833213689 ], [ -61.254330165515242, -38.696986201850173 ], [ -61.254144574878232, -38.696628768030735 ], [ -61.253958984241216, -38.69618884948374 ], [ -61.253897120695548, -38.69583828939161 ], [ -61.254172069787415, -38.69557708775433 ], [ -61.255120644154374, -38.694827851478976 ], [ -61.255546815246781, -38.69469725066034 ], [ -61.255739279611085, -38.694827851478976 ], [ -61.255876754157022, -38.69483472520627 ], [ -61.255959238884586, -38.694779735387897 ], [ -61.255979860066475, -38.69462163966007 ], [ -61.256007354975665, -38.694580397296292 ], [ -61.256096713430523, -38.694704124387634 ], [ -61.256282304067533, -38.694635387114666 ], [ -61.256289177794834, -38.694491038841434 ], [ -61.256137955794301, -38.694360438022798 ], [ -61.256021102430253, -38.694291700749829 ], [ -61.256131082067007, -38.694222963476861 ], [ -61.256007354975665, -38.694037372839844 ] ] ] ] } }, 46 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.323991954804647, -38.975284517347426 ], [ -61.323991954804647, -38.975683193530642 ], [ -61.324459368260833, -38.975476981711736 ], [ -61.324789307171081, -38.97527076989283 ], [ -61.324789307171081, -38.975092052983115 ], [ -61.32505050880836, -38.974707124254493 ], [ -61.325270468081854, -38.974885841164216 ], [ -61.325531669719133, -38.974982073346368 ], [ -61.325682891719666, -38.974803356436652 ], [ -61.325916598447755, -38.974555902253968 ], [ -61.325916598447755, -38.974445922617221 ], [ -61.325944093356938, -38.97422596334372 ], [ -61.32609531535747, -38.973909771888067 ], [ -61.326466496631497, -38.973841034615099 ], [ -61.326686455904998, -38.973662317705383 ], [ -61.326727698268776, -38.973593580432414 ], [ -61.326658960995807, -38.97318115679461 ], [ -61.326576476268244, -38.973043682248672 ], [ -61.325971588266128, -38.972809975520583 ], [ -61.325669144265071, -38.972809975520583 ], [ -61.325036761353765, -38.972823722975171 ], [ -61.324638085170548, -38.973043682248672 ], [ -61.324225661532743, -38.973456105886477 ], [ -61.324198166623553, -38.973827287160503 ], [ -61.324404378442459, -38.974006004070226 ], [ -61.324885539353232, -38.974267205707498 ], [ -61.324844296989454, -38.97439093279884 ], [ -61.324693074988922, -38.974720871709088 ], [ -61.324349388624086, -38.974954578437178 ], [ -61.323991954804647, -38.975284517347426 ] ] ] ] } }, 47 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -62.252691798499974, -38.094597658820284 ], [ -62.252547450226743, -38.094790123184595 ], [ -62.252519955317553, -38.095078819731064 ], [ -62.252643682408895, -38.095367516277534 ], [ -62.252650556136196, -38.095993025461546 ], [ -62.252361859589726, -38.095993025461546 ], [ -62.252245006225678, -38.095917414461283 ], [ -62.252437470589989, -38.095628717914813 ], [ -62.252499334135663, -38.095415632368614 ], [ -62.252334364680536, -38.095195673095112 ], [ -62.252059415588661, -38.095346895095645 ], [ -62.251798213951382, -38.095614970460218 ], [ -62.251805087678676, -38.095834929733719 ], [ -62.251585128405182, -38.095972404279657 ], [ -62.251268936949522, -38.095999899188847 ], [ -62.250581564219836, -38.096865988828249 ], [ -62.250829018402527, -38.097147811647424 ], [ -62.251158957312775, -38.097230296374988 ], [ -62.25135829540438, -38.097168432829314 ], [ -62.251420158950054, -38.096969094737702 ], [ -62.251633244496254, -38.096721640555018 ], [ -62.251832582587866, -38.096639155827454 ], [ -62.251880698678946, -38.096501681281516 ], [ -62.252025046952177, -38.09626797455342 ], [ -62.252148774043526, -38.096226732189642 ], [ -62.252354985862432, -38.096082383916411 ], [ -62.252568071408632, -38.096164868643967 ], [ -62.252822399318617, -38.096419196553953 ], [ -62.252829273045911, -38.096652903282049 ], [ -62.252829273045911, -38.097024084556082 ], [ -62.253056106046714, -38.097099695556345 ], [ -62.253399792411557, -38.097305907375251 ], [ -62.253729731321805, -38.096948473555813 ], [ -62.253729731321805, -38.097154685374718 ], [ -62.253922195686116, -38.097030958283376 ], [ -62.254039049050164, -38.096694145645827 ], [ -62.253832837231258, -38.096487933826921 ], [ -62.253482277139113, -38.096261100826126 ], [ -62.253282939047509, -38.096171742371268 ], [ -62.253310433956692, -38.096109878825594 ], [ -62.253468529684525, -38.095834929733719 ], [ -62.253832837231258, -38.095346895095645 ], [ -62.253846584685853, -38.095147557004033 ], [ -62.253777847412884, -38.094893229094048 ], [ -62.253406666138851, -38.09477637573 ], [ -62.25313859077427, -38.094762628275411 ], [ -62.252918631500776, -38.094748880820816 ], [ -62.252843020500507, -38.094728259638927 ], [ -62.252753662045649, -38.094680143547848 ], [ -62.252691798499974, -38.094597658820284 ] ] ] ] } }, 48 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -62.252898010318866, -38.094109624182202 ], [ -62.253014863682914, -38.094336457182997 ], [ -62.253124843319668, -38.094274593637323 ], [ -62.253351676320463, -38.094027139454639 ], [ -62.253736605049085, -38.093855296272217 ], [ -62.25375035250368, -38.093896538635995 ], [ -62.253908448231506, -38.094034013181933 ], [ -62.254142154959602, -38.093951528454376 ], [ -62.254114660050419, -38.094185235182465 ], [ -62.254087165141229, -38.094322709728402 ], [ -62.253901574504212, -38.094583911365682 ], [ -62.254162776141492, -38.094577037638388 ], [ -62.254430851506072, -38.094796996911889 ], [ -62.254554578597414, -38.094817618093778 ], [ -62.254616442143089, -38.09470076472973 ], [ -62.254671431961462, -38.094425815637855 ], [ -62.254884517507662, -38.09422647754625 ], [ -62.254960128507932, -38.094308962273807 ], [ -62.254898264962257, -38.094425815637855 ], [ -62.255021992053607, -38.09465264863865 ], [ -62.255303814872775, -38.094735133366214 ], [ -62.255351930963855, -38.094556416456498 ], [ -62.255441289418712, -38.094377699546776 ], [ -62.255455036873308, -38.094192108909766 ], [ -62.255207582690616, -38.094164614000576 ], [ -62.254953254780631, -38.094068381818417 ], [ -62.254643937052272, -38.09398589709086 ], [ -62.254685179416057, -38.093786558999248 ], [ -62.254863896325773, -38.093649084453311 ], [ -62.255118224235758, -38.093614715816827 ], [ -62.255647501237618, -38.093621589544121 ], [ -62.25555814278276, -38.093497862452779 ], [ -62.25553064787357, -38.093181670997126 ], [ -62.25555814278276, -38.092961711723625 ], [ -62.255736859692476, -38.092810489723092 ], [ -62.255936197784088, -38.092556161813107 ], [ -62.255633753783023, -38.092487424540138 ], [ -62.255345057236553, -38.092789868541203 ], [ -62.255056360690091, -38.093154176087936 ], [ -62.25483640141659, -38.093181670997126 ], [ -62.25425900832365, -38.093504736180073 ], [ -62.253970311777181, -38.093614715816827 ], [ -62.253825963503949, -38.093532231089263 ], [ -62.253358550047757, -38.093759064090058 ], [ -62.252898010318866, -38.094109624182202 ] ] ] ] } }, 49 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -62.839068853014261, -36.44963223195105 ], [ -62.839240696196683, -36.449735337860503 ], [ -62.839082600468856, -36.449281671858913 ], [ -62.838828272558871, -36.448800510948132 ], [ -62.838594565830775, -36.448477445765178 ], [ -62.838649555649148, -36.448525561856258 ], [ -62.838780156467791, -36.448628667765711 ], [ -62.839075726741555, -36.448614920311115 ], [ -62.839233822469382, -36.448401834764915 ], [ -62.839130716559929, -36.44819562294601 ], [ -62.838938252195618, -36.448065022127366 ], [ -62.838649555649148, -36.447886305217644 ], [ -62.838388354011869, -36.447810694217381 ], [ -62.837886571919199, -36.447611356125769 ], [ -62.837962182919462, -36.447322659579307 ], [ -62.837769718555151, -36.447143942669584 ], [ -62.837542885554356, -36.447047710487432 ], [ -62.837206072916807, -36.446704024122582 ], [ -62.836958618734116, -36.446676529213399 ], [ -62.836614932369272, -36.446807130032035 ], [ -62.836415594277668, -36.447033963032837 ], [ -62.83653932136901, -36.447267669760926 ], [ -62.836745533187916, -36.447473881579832 ], [ -62.836958618734116, -36.447583861216586 ], [ -62.83726106273518, -36.447638851034959 ], [ -62.837384789826523, -36.447680093398738 ], [ -62.837226694098696, -36.447810694217381 ], [ -62.836986113643306, -36.447817567944675 ], [ -62.83680739673359, -36.447680093398738 ], [ -62.836498079005231, -36.447398270579569 ], [ -62.836291867186326, -36.447233301124442 ], [ -62.835955054548776, -36.447288290942822 ], [ -62.835783211366355, -36.447473881579832 ], [ -62.835831327457434, -36.447721335762523 ], [ -62.836216256186056, -36.448023779763581 ], [ -62.836587437460089, -36.448140633127629 ], [ -62.836986113643306, -36.447955042490612 ], [ -62.837233567825997, -36.44787943149035 ], [ -62.837556633008944, -36.447707588307928 ], [ -62.837680360100293, -36.447721335762523 ], [ -62.837859077010009, -36.447893178944945 ], [ -62.838250879465932, -36.448223117855193 ], [ -62.838470838739433, -36.448518688128956 ], [ -62.83860831328537, -36.448773016038942 ], [ -62.83884889374076, -36.449192313404055 ], [ -62.839068853014261, -36.44963223195105 ] ] ] ] } }, 50 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -58.466176249141846, -35.754791197555541 ], [ -58.466327471142378, -35.754722460282572 ], [ -58.466272481324005, -35.754664033600548 ], [ -58.466179686005496, -35.754475006099888 ], [ -58.466097201277933, -35.754413142554213 ], [ -58.46599753223213, -35.754282541735577 ], [ -58.465877242004431, -35.754375337054086 ], [ -58.465787883549574, -35.754512811600023 ], [ -58.465884115731733, -35.754567801418396 ], [ -58.466014716550369, -35.75464684928231 ], [ -58.466176249141846, -35.754791197555541 ] ] ] ] } }, 51 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -58.467258861191105, -35.755354843193885 ], [ -58.467159192145303, -35.75539608555767 ], [ -58.467090454872334, -35.755471696557933 ], [ -58.467152318418002, -35.75560573424022 ], [ -58.46724167687286, -35.75563322914941 ], [ -58.467358530236908, -35.755650413467656 ], [ -58.467379151418797, -35.755482007148878 ], [ -58.467258861191105, -35.755354843193885 ] ] ] ] } }, 52 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.082048467486899, -36.036098487179927 ], [ -59.08228904794229, -36.036290951544245 ], [ -59.082550249579569, -36.036524658272334 ], [ -59.082715219034696, -36.036737743818541 ], [ -59.082749587671181, -36.036902713273662 ], [ -59.082543375852275, -36.037170788638242 ], [ -59.082495259761195, -36.037411369093633 ], [ -59.082536502124974, -36.037803171549555 ], [ -59.082708345307395, -36.038057499459541 ], [ -59.083340728218708, -36.038002509641167 ], [ -59.083705035765448, -36.037686318185507 ], [ -59.084000606039211, -36.037486980093902 ], [ -59.084316797494864, -36.037273894547695 ], [ -59.084296176312975, -36.036978324273932 ], [ -59.083952489948132, -36.03677898618232 ], [ -59.083746278129226, -36.036620890454493 ], [ -59.083485076491947, -36.036634637909088 ], [ -59.083478202764645, -36.036820228546105 ], [ -59.083485076491947, -36.036964576819337 ], [ -59.083457581582756, -36.037157041183647 ], [ -59.083134516399802, -36.036758365000431 ], [ -59.08277020885307, -36.036524658272334 ], [ -59.082756461398475, -36.036435299817477 ], [ -59.082130952214463, -36.03603662363426 ], [ -59.082048467486899, -36.036098487179927 ] ] ] ] } }, 53 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.116384290342204, -34.526849408469651 ], [ -59.11657522435565, -34.527032998867199 ], [ -59.116913030687137, -34.526731910615219 ], [ -59.11717740085961, -34.526335355356515 ], [ -59.117434427416178, -34.525880051170596 ], [ -59.118029260304233, -34.525101627884993 ], [ -59.117926449681605, -34.524962099182858 ], [ -59.117919106065706, -34.524749134321702 ], [ -59.118080665615544, -34.524727103473992 ], [ -59.118264256013092, -34.524528825844641 ], [ -59.118256912397193, -34.524286486519877 ], [ -59.118117383695058, -34.52392664934068 ], [ -59.118029260304233, -34.523809151486255 ], [ -59.117904418833902, -34.523794464254451 ], [ -59.117559268886509, -34.523809151486255 ], [ -59.11733161679355, -34.523845869565761 ], [ -59.117081933852887, -34.524088208890525 ], [ -59.117045215773373, -34.524448046069722 ], [ -59.117368334873056, -34.524719759858094 ], [ -59.117236149786827, -34.524925381103344 ], [ -59.116868968991731, -34.524925381103344 ], [ -59.116744127521393, -34.525057566189581 ], [ -59.116633973282866, -34.52516037681221 ], [ -59.116443039269413, -34.525248500203027 ], [ -59.116450382885319, -34.526026923488637 ], [ -59.116538506276143, -34.526364729820124 ], [ -59.116384290342204, -34.526849408469651 ] ] ] ] } }, 54 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.119446578173303, -34.523111507975578 ], [ -59.120078129140865, -34.522582767630645 ], [ -59.119887195127419, -34.522244961299151 ], [ -59.120136878068081, -34.522068714517509 ], [ -59.120592182254001, -34.521554661404373 ], [ -59.120298437617926, -34.521099357218453 ], [ -59.119916569591027, -34.520834987045987 ], [ -59.119123459073613, -34.521466538013549 ], [ -59.118859088901146, -34.522230274067347 ], [ -59.119402516477891, -34.522861825034916 ], [ -59.119446578173303, -34.523111507975578 ] ] ] ] } }, 55 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.423501650976689, -34.607386844066099 ], [ -59.42410382748065, -34.607372156834295 ], [ -59.424397572116725, -34.607239971748058 ], [ -59.424588506130178, -34.606623108012293 ], [ -59.42463256782559, -34.606138429362765 ], [ -59.424603193361982, -34.605800623031278 ], [ -59.424808814607232, -34.605154384831913 ], [ -59.425014435852489, -34.604537521096148 ], [ -59.425014435852489, -34.604038155214816 ], [ -59.424823501839036, -34.603597538260701 ], [ -59.424294761494096, -34.60352410210168 ], [ -59.423545712672102, -34.603509414869876 ], [ -59.422326672432384, -34.603465353174464 ], [ -59.421416064060544, -34.60339191701545 ], [ -59.421621685305801, -34.604331899850891 ], [ -59.421988866100897, -34.604890014659439 ], [ -59.422502919214033, -34.605066261441088 ], [ -59.422928848936344, -34.605198446527318 ], [ -59.423413527585865, -34.605477503931596 ], [ -59.423692584990143, -34.605903433653907 ], [ -59.423751333917359, -34.606329363376219 ], [ -59.423751333917359, -34.606432173998847 ], [ -59.422987597863553, -34.606358737839827 ], [ -59.422796663850107, -34.606094367667353 ], [ -59.422517606445837, -34.606564359085077 ], [ -59.423016972327162, -34.607386844066099 ], [ -59.423501650976689, -34.607386844066099 ] ] ] ] } }, 56 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.023776158416091, -34.924484178711339 ], [ -60.02461333062891, -34.924939482897258 ], [ -60.025406441146316, -34.9247044871884 ], [ -60.025553313464357, -34.925145104142516 ], [ -60.026082053809297, -34.925394787083178 ], [ -60.026728292008663, -34.925203853069725 ], [ -60.027022036644745, -34.925717906182861 ], [ -60.026977974949332, -34.92589415296451 ], [ -60.026919226022116, -34.926775386872741 ], [ -60.027227657889995, -34.927142567667836 ], [ -60.027712336539523, -34.926966320886187 ], [ -60.028387949202504, -34.926936946422586 ], [ -60.028931376779241, -34.926936946422586 ], [ -60.028990125706457, -34.926966320886187 ], [ -60.029254495878931, -34.927274752754073 ], [ -60.029298557574343, -34.927289439985877 ], [ -60.029695112833046, -34.927113193204228 ], [ -60.029592302210418, -34.92655507839568 ], [ -60.029048874633673, -34.926055712514355 ], [ -60.02857888321595, -34.925541659401219 ], [ -60.027947332248388, -34.924895421201846 ], [ -60.027212970658191, -34.924293244697893 ], [ -60.026772353704075, -34.923735129889344 ], [ -60.025656124086986, -34.923485446948675 ], [ -60.0253476922191, -34.923397323557857 ], [ -60.025156758205654, -34.923632319266716 ], [ -60.025465190073533, -34.923955438366399 ], [ -60.025303630523695, -34.924028874525419 ], [ -60.024995198655809, -34.923911376670986 ], [ -60.024304898761031, -34.923955438366399 ], [ -60.023776158416091, -34.924484178711339 ] ] ] ] } }, 57 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.258360624787265, -35.015912196690337 ], [ -60.259520916099767, -35.016367500876257 ], [ -60.259682475649612, -35.016103130703783 ], [ -60.260225903226356, -35.015824073299513 ], [ -60.260255277689964, -35.015824073299513 ], [ -60.260739956339485, -35.015677200981472 ], [ -60.261180573293601, -35.015045650013903 ], [ -60.261724000870345, -35.014443473509949 ], [ -60.262473049692346, -35.013811922542381 ], [ -60.262149930592656, -35.013488803442698 ], [ -60.261870873188386, -35.013195058806623 ], [ -60.261738688102149, -35.013048186488582 ], [ -60.26143025623427, -35.01300412479317 ], [ -60.260872141425722, -35.013195058806623 ], [ -60.260416837239802, -35.013665050224347 ], [ -60.259770599040436, -35.013973482092226 ], [ -60.259329982086321, -35.014296601191909 ], [ -60.258859990668597, -35.014810654305045 ], [ -60.258507497105299, -35.015265958490964 ], [ -60.258360624787265, -35.015912196690337 ] ] ] ] } }, 58 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.893534203205711, -35.789650255349173 ], [ -61.893813260609981, -35.788445902341252 ], [ -61.894268564795901, -35.78854871296388 ], [ -61.89444481157755, -35.788166844936981 ], [ -61.894151066941468, -35.787858413069102 ], [ -61.893857322305394, -35.78781435137369 ], [ -61.893783886146373, -35.787520606737608 ], [ -61.893695762755549, -35.786977179160871 ], [ -61.893431392583082, -35.786918430233655 ], [ -61.893225771337825, -35.786889055770047 ], [ -61.892902652238142, -35.786874368538243 ], [ -61.892594220370263, -35.787094677015297 ], [ -61.892608907602067, -35.787535293969412 ], [ -61.892608907602067, -35.787961223691724 ], [ -61.892608907602067, -35.788210906632393 ], [ -61.892506096979439, -35.788680898050117 ], [ -61.892799841615513, -35.78893058099078 ], [ -61.893181709642413, -35.789371197944895 ], [ -61.893534203205711, -35.789650255349173 ] ] ] ] } }, 59 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.912833225796, -34.767697979205224 ], [ -61.912671666246155, -34.768270781245569 ], [ -61.913156344895683, -34.768358904636393 ], [ -61.914713191466895, -34.767932974914082 ], [ -61.91568254876595, -34.767639230278007 ], [ -61.916020355097437, -34.767977036609494 ], [ -61.916622531601398, -34.768094534463927 ], [ -61.917400954887, -34.76775672813244 ], [ -61.917400954887, -34.767316111178324 ], [ -61.917195333641743, -34.767051741005851 ], [ -61.91687221454206, -34.766684560210756 ], [ -61.916637218833202, -34.766581749588127 ], [ -61.916123165720066, -34.766611124051735 ], [ -61.915755984924971, -34.766787370833384 ], [ -61.915550363679714, -34.766508313429107 ], [ -61.915021623334773, -34.766684560210756 ], [ -61.914581006380658, -34.766684560210756 ], [ -61.914081640499326, -34.766684560210756 ], [ -61.913685085240623, -34.766713934674364 ], [ -61.913082908736669, -34.766655185747148 ], [ -61.912774476868783, -34.766948930383222 ], [ -61.912833225796, -34.767697979205224 ] ] ] ] } }, 60 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.30677194902588, -34.287719243855278 ], [ -61.306331332071764, -34.28746221729871 ], [ -61.306155085290122, -34.287359406676089 ], [ -61.306059618283392, -34.287175816278541 ], [ -61.305964151276669, -34.286918789721973 ], [ -61.305905402349453, -34.286625045085891 ], [ -61.305817278958628, -34.286345987681621 ], [ -61.305538221554357, -34.286213802595384 ], [ -61.305259164150087, -34.286257864290796 ], [ -61.305193071606965, -34.286250520674898 ], [ -61.305046199288931, -34.286022868581938 ], [ -61.304906670586796, -34.286008181350134 ], [ -61.304590895103011, -34.286008181350134 ], [ -61.30437058662595, -34.28606693027735 ], [ -61.304209027076112, -34.286125679204559 ], [ -61.304150278148896, -34.286213802595384 ], [ -61.304209027076112, -34.286478172767858 ], [ -61.304333868546443, -34.286838009947047 ], [ -61.304421991937268, -34.286940820569676 ], [ -61.304524802559889, -34.28697753864919 ], [ -61.30482589081187, -34.287381437523791 ], [ -61.304921357818593, -34.287623776848555 ], [ -61.304847921659579, -34.287866116173319 ], [ -61.304972763129911, -34.288071737418576 ], [ -61.305193071606965, -34.288225953352516 ], [ -61.305237133302377, -34.28793955233234 ], [ -61.305332600309107, -34.287748618318886 ], [ -61.305457441779438, -34.287704556623474 ], [ -61.305765873647317, -34.28771190023938 ], [ -61.305824622574534, -34.287476904530514 ], [ -61.306323988455866, -34.288189235273002 ], [ -61.30677194902588, -34.287719243855278 ] ] ] ] } }, 61 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.275030632884636, -33.327548808294232 ], [ -60.275441875375151, -33.327490059367015 ], [ -60.27529500305711, -33.326902570094866 ], [ -60.27582374340205, -33.327401935976191 ], [ -60.277674334609337, -33.326256331895493 ], [ -60.276793100701106, -33.325375097987262 ], [ -60.275412500911543, -33.324376366224598 ], [ -60.274648764857737, -33.3236126301708 ], [ -60.27423752236723, -33.323436383389151 ], [ -60.273679407558689, -33.32381825141605 ], [ -60.273297539531782, -33.324288242833774 ], [ -60.272798173650457, -33.324611361933464 ], [ -60.27206381206026, -33.324728859787889 ], [ -60.271505697251712, -33.325198851205613 ], [ -60.273091918286532, -33.327548808294232 ], [ -60.273532535240648, -33.327372561512583 ], [ -60.273914403267547, -33.326638199922392 ], [ -60.274472518076095, -33.326931944558467 ], [ -60.275030632884636, -33.327548808294232 ] ] ] ] } }, 62 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.06567883075251, -33.459587022210897 ], [ -60.065568676513983, -33.459719207297127 ], [ -60.064885720235104, -33.460189198714851 ], [ -60.064562601135414, -33.460314040185182 ], [ -60.064232138419833, -33.460108418939932 ], [ -60.063872301240636, -33.460027639165013 ], [ -60.063343560895696, -33.460284665721581 ], [ -60.06305715987552, -33.460695908212088 ], [ -60.062726697159931, -33.461055745391278 ], [ -60.062256705742215, -33.461334802795555 ], [ -60.062418265292052, -33.461679952742941 ], [ -60.062579824841897, -33.461878230372292 ], [ -60.062550450378289, -33.462194005856077 ], [ -60.062844195014364, -33.46245837602855 ], [ -60.063049816259621, -33.462429001564942 ], [ -60.063439027902419, -33.462825556823645 ], [ -60.063629961915872, -33.463031178068896 ], [ -60.06381355231342, -33.462994459989389 ], [ -60.064525883055907, -33.463537887566133 ], [ -60.06484900215559, -33.463501169486619 ], [ -60.064915094698712, -33.463170706771038 ], [ -60.064724160685259, -33.462943054678078 ], [ -60.0648710330033, -33.462898992982666 ], [ -60.065201495718881, -33.46314133230743 ], [ -60.065957888156781, -33.462884305750862 ], [ -60.06636178703139, -33.462656653657902 ], [ -60.066648188051566, -33.4626639972738 ], [ -60.066861152912722, -33.462260098399199 ], [ -60.066897870992229, -33.461981040994921 ], [ -60.067272395403229, -33.461746045286063 ], [ -60.067485360264385, -33.461415582570474 ], [ -60.067558796423405, -33.4611218379344 ], [ -60.067404580489459, -33.460813406066514 ], [ -60.067074117773878, -33.460725282675696 ], [ -60.066839122065012, -33.460835436914223 ], [ -60.066765685905992, -33.460754657139297 ], [ -60.066611469972052, -33.460394819960108 ], [ -60.06567883075251, -33.459587022210897 ] ] ] ] } }, 63 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.063424340670622, -34.064517382132181 ], [ -60.063718085306697, -34.064429258741363 ], [ -60.063218719425365, -34.064282386423322 ], [ -60.063424340670622, -34.064091452409869 ], [ -60.06365933637948, -34.064062077946268 ], [ -60.063864957624737, -34.064091452409869 ], [ -60.063879644856542, -34.063636148223949 ], [ -60.06365933637948, -34.063401152515091 ], [ -60.063394966207014, -34.063489275905916 ], [ -60.063394966207014, -34.062931161097367 ], [ -60.063218719425365, -34.062534605838664 ], [ -60.062807476934857, -34.06259335476588 ], [ -60.062748728007641, -34.06259335476588 ], [ -60.062366859980742, -34.062813663242935 ], [ -60.062073115344667, -34.062666790924901 ], [ -60.061852806867606, -34.062563980302272 ], [ -60.061074383582003, -34.063092720647212 ], [ -60.060648453859692, -34.063489275905916 ], [ -60.060369396455414, -34.06378302054199 ], [ -60.060119713514752, -34.063841769469207 ], [ -60.059781907183265, -34.064120826873477 ], [ -60.059899405037697, -34.064488007668579 ], [ -60.061118445277415, -34.064502694900384 ], [ -60.062264049358113, -34.064370509814147 ], [ -60.063424340670622, -34.064517382132181 ] ] ] ] } }, 64 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.769514473235766, -34.168826102403138 ], [ -59.769367600917725, -34.168980318337077 ], [ -59.769073856281651, -34.169112503423314 ], [ -59.768677301022947, -34.16930343743676 ], [ -59.768552459552609, -34.169457653370699 ], [ -59.768611208479825, -34.169810146933997 ], [ -59.768758080797866, -34.170030455411052 ], [ -59.768743393566062, -34.170258107504011 ], [ -59.768390900002771, -34.170067173490558 ], [ -59.768097155366689, -34.169927644788423 ], [ -59.767950283048656, -34.170177327729093 ], [ -59.768104498982595, -34.170654662762715 ], [ -59.768236684068832, -34.171080592485026 ], [ -59.768523085089001, -34.171205433955357 ], [ -59.768816829725083, -34.171168715875851 ], [ -59.769103230745259, -34.171131997796344 ], [ -59.769499786003962, -34.17104387440552 ], [ -59.769749468944624, -34.170985125478303 ], [ -59.769844935951348, -34.170801535080756 ], [ -59.76973478171282, -34.17056653937189 ], [ -59.769499786003962, -34.170537164908282 ], [ -59.769286821142806, -34.170559195755992 ], [ -59.769389631765428, -34.170390292590248 ], [ -59.769565878547077, -34.170427010669755 ], [ -59.76973478171282, -34.170294825583518 ], [ -59.769852279567253, -34.170140609649579 ], [ -59.76968337640151, -34.169949675636133 ], [ -59.769609940242489, -34.169868895861207 ], [ -59.769631971090192, -34.169744054390875 ], [ -59.769859623183152, -34.169677961847761 ], [ -59.769925715726274, -34.169494371450213 ], [ -59.769852279567253, -34.169200626814131 ], [ -59.76973478171282, -34.169163908734625 ], [ -59.769918372110368, -34.168855476866746 ], [ -59.769514473235766, -34.168826102403138 ] ] ] ] } }, 65 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.114698930492764, -34.29837483052907 ], [ -59.115580164400995, -34.298639200701537 ], [ -59.115727036719036, -34.297757966793306 ], [ -59.116108904745936, -34.297934213574955 ], [ -59.116755142945301, -34.298139834820205 ], [ -59.117401381144674, -34.298727324092361 ], [ -59.118781980934237, -34.298286707138246 ], [ -59.118811355397845, -34.298404204992679 ], [ -59.120133206260192, -34.298932945337611 ], [ -59.12127881034089, -34.298462953919888 ], [ -59.120661946605132, -34.297787341256914 ], [ -59.120191955187408, -34.297434847693623 ], [ -59.119663214842468, -34.296876732885075 ], [ -59.119222597888353, -34.296436115930959 ], [ -59.118635108616196, -34.295731128804377 ], [ -59.118282615052905, -34.295701754340769 ], [ -59.117254508826633, -34.296289243612918 ], [ -59.116725768481693, -34.29605424790406 ], [ -59.116255777063969, -34.295907375586019 ], [ -59.115374543155738, -34.295995498976843 ], [ -59.114845802810805, -34.296347992540134 ], [ -59.114904551738022, -34.297082354130332 ], [ -59.114787053883589, -34.297992962502164 ], [ -59.114698930492764, -34.29837483052907 ] ] ] ] } }, 66 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.444713685509484, -34.259629913030501 ], [ -59.444096821773719, -34.259673974725914 ], [ -59.442936530461218, -34.259673974725914 ], [ -59.442275605030048, -34.259673974725914 ], [ -59.44192311146675, -34.259438979017055 ], [ -59.441732177453304, -34.259101172685561 ], [ -59.441864362539533, -34.258924925903919 ], [ -59.442158107175615, -34.258807428049487 ], [ -59.442216856102831, -34.258454934486195 ], [ -59.442084671016595, -34.258131815386513 ], [ -59.44146780728083, -34.258102440922904 ], [ -59.441159375412951, -34.258102440922904 ], [ -59.440850943545072, -34.258322749399959 ], [ -59.440234079809308, -34.258440247254391 ], [ -59.4402047053457, -34.258778053585878 ], [ -59.440057833027666, -34.259013049294744 ], [ -59.439896273477821, -34.259174608844582 ], [ -59.439646590537151, -34.259409604553447 ], [ -59.439808150086996, -34.259615225798697 ], [ -59.440322203200132, -34.260026468289205 ], [ -59.440527824445383, -34.260114591680029 ], [ -59.441056564790323, -34.260217402302658 ], [ -59.441585305135263, -34.260202715070854 ], [ -59.442040609321182, -34.260143966143637 ], [ -59.443612143124199, -34.260452398011516 ], [ -59.44396463668749, -34.260613957561361 ], [ -59.444346504714389, -34.260246776766266 ], [ -59.444831183363917, -34.260217402302658 ], [ -59.444713685509484, -34.259629913030501 ] ] ] ] } }, 67 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.099531436465618, -36.247576112145758 ], [ -61.098973321657077, -36.24709143349623 ], [ -61.098473955775745, -36.246709565469331 ], [ -61.098077400517042, -36.246063327269965 ], [ -61.098077400517042, -36.245681459243059 ], [ -61.098444581312137, -36.245696146474863 ], [ -61.098723638716407, -36.245519899693221 ], [ -61.099032070584286, -36.244961784884673 ], [ -61.098855823802644, -36.244565229625969 ], [ -61.09856207916657, -36.244550542394165 ], [ -61.098253647298684, -36.244550542394165 ], [ -61.098062713285238, -36.244256797758091 ], [ -61.09810677498065, -36.243683995717738 ], [ -61.097533972940298, -36.243669308485934 ], [ -61.097269602767824, -36.243845555267583 ], [ -61.097210853840615, -36.243948365890205 ], [ -61.096990545363553, -36.243522436167893 ], [ -61.09652055394583, -36.242802761809507 ], [ -61.096270871005167, -36.241980276828492 ], [ -61.095874315746464, -36.241495598178965 ], [ -61.095169328619875, -36.241598408801593 ], [ -61.094523090420509, -36.24186277897406 ], [ -61.094552464884117, -36.242156523610134 ], [ -61.094170596857211, -36.242332770391783 ], [ -61.094053099002785, -36.242582453332446 ], [ -61.094581839347718, -36.242964321359352 ], [ -61.094787460592975, -36.24292025966394 ], [ -61.094846209520192, -36.243316814922643 ], [ -61.094890271215604, -36.243713370181347 ], [ -61.095301513706112, -36.243845555267583 ], [ -61.095639320037598, -36.243918991426597 ], [ -61.09585962851466, -36.244300859453503 ], [ -61.096079936991714, -36.244521167930557 ], [ -61.095977126369085, -36.244814912566632 ], [ -61.096491179482221, -36.244858974262044 ], [ -61.096535241177634, -36.245240842288943 ], [ -61.09652055394583, -36.245843018792904 ], [ -61.096564615641242, -36.246180825124391 ], [ -61.096417743323201, -36.24643050806506 ], [ -61.096549928409438, -36.246944561178196 ], [ -61.096828985813708, -36.247194244118859 ], [ -61.096887734740925, -36.247164869655251 ], [ -61.097343038926844, -36.246973935641805 ], [ -61.097519285708493, -36.246768314396547 ], [ -61.098782387643624, -36.247943292940853 ], [ -61.099531436465618, -36.247576112145758 ] ] ] ] } }, 68 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.874794759018982, -35.427279528668755 ], [ -60.874089771892393, -35.427103281887113 ], [ -60.873472908156636, -35.426574541542173 ], [ -60.872518238089384, -35.426236735210686 ], [ -60.872283242380526, -35.426163299051666 ], [ -60.871548880790328, -35.425590497011314 ], [ -60.870814519200138, -35.425605184243118 ], [ -60.870432651173239, -35.426133924588058 ], [ -60.870403276709631, -35.426471730919545 ], [ -60.870579523491273, -35.426765475555626 ], [ -60.869962659755515, -35.426574541542173 ], [ -60.869624853424028, -35.426882973410052 ], [ -60.869947972523711, -35.427352964827776 ], [ -60.870241717159786, -35.427587960536641 ], [ -60.870667646882097, -35.427808269013696 ], [ -60.871211074458841, -35.428087326417973 ], [ -60.871475444631308, -35.428248885967811 ], [ -60.871504819094916, -35.428248885967811 ], [ -60.871901374353619, -35.428410445517656 ], [ -60.872033559439856, -35.428366383822244 ], [ -60.872136370062485, -35.428116700881581 ], [ -60.872283242380526, -35.428278260431419 ], [ -60.872459489162168, -35.428601379531102 ], [ -60.872767921030047, -35.428689502921927 ], [ -60.873046978434324, -35.428704190153731 ], [ -60.873634467706481, -35.428454507213068 ], [ -60.873722591097298, -35.428057951954365 ], [ -60.874339454833063, -35.427955141331736 ], [ -60.874897569641611, -35.427911079636324 ], [ -60.875367561059335, -35.427764207318283 ], [ -60.875411622754747, -35.42723546697335 ], [ -60.874794759018982, -35.427279528668755 ] ] ] ] } }, 69 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.012157094464598, -35.001716987152122 ], [ -61.011510856265232, -35.001761048847534 ], [ -61.0110114903839, -35.001805110542946 ], [ -61.010952741456684, -35.0016141765295 ], [ -61.010600247893393, -35.001335119125223 ], [ -61.010321190489115, -35.001320431893419 ], [ -61.010071507548453, -35.001026687257344 ], [ -61.009895260766804, -35.00101200002554 ], [ -61.009880573535, -35.00101200002554 ], [ -61.009645577826142, -35.001144185111777 ], [ -61.009601516130729, -35.001452616979655 ], [ -61.009410582117276, -35.001202934038986 ], [ -61.008852467308735, -35.00121762127079 ], [ -61.008294352500187, -35.001158872343581 ], [ -61.008294352500187, -35.001496678675068 ], [ -61.007912484473287, -35.00129105742981 ], [ -61.007559990909989, -35.001276370198006 ], [ -61.007457180287368, -35.001276370198006 ], [ -61.007031250565056, -35.001276370198006 ], [ -61.006502510220116, -35.00129105742981 ], [ -61.007001876101448, -35.002054793483616 ], [ -61.008353101427403, -35.003215084796118 ], [ -61.008808405613323, -35.003185710332509 ], [ -61.008779031149714, -35.002936027391847 ], [ -61.00929308426285, -35.002789155073806 ], [ -61.009469331044492, -35.003024150782664 ], [ -61.010277128793703, -35.003024150782664 ], [ -61.010277128793703, -35.002642282755765 ], [ -61.010526811734373, -35.002583533828549 ], [ -61.010306503257311, -35.003024150782664 ], [ -61.010556186197981, -35.003200397564314 ], [ -61.010967428688488, -35.003126961405293 ], [ -61.011349296715387, -35.002936027391847 ], [ -61.012083658305578, -35.002789155073806 ], [ -61.012098345537382, -35.002186978569846 ], [ -61.012348028478051, -35.002157604106237 ], [ -61.012348028478051, -35.001628863761297 ], [ -61.012157094464598, -35.001716987152122 ] ] ] ] } }, 70 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.513878068287077, -34.662295060165064 ], [ -60.514296654393483, -34.662463963330808 ], [ -60.515809439269283, -34.661369764561421 ], [ -60.515449602090087, -34.661024614614028 ], [ -60.515669910567148, -34.661024614614028 ], [ -60.515926937123716, -34.66099524015042 ], [ -60.515993029666831, -34.660708839130244 ], [ -60.516294117918811, -34.660473843421386 ], [ -60.516205994527986, -34.660047913699074 ], [ -60.516470364700453, -34.659981821155959 ], [ -60.516624580634399, -34.660114006242189 ], [ -60.51667598594571, -34.660312283871541 ], [ -60.516764109336535, -34.660429781725973 ], [ -60.517248787986063, -34.660385720030561 ], [ -60.517483783694921, -34.660238847712527 ], [ -60.517520501774428, -34.660018539235466 ], [ -60.517498470926725, -34.659849636069723 ], [ -60.517799559178705, -34.65980557437431 ], [ -60.517814246410509, -34.659511829738236 ], [ -60.517689404940178, -34.659174023406742 ], [ -60.517145977363434, -34.658924340466079 ], [ -60.516874263575062, -34.658718719220822 ], [ -60.516492395548163, -34.658667313909511 ], [ -60.515706628646655, -34.658953714929687 ], [ -60.515243980844836, -34.659386988267897 ], [ -60.514972267056464, -34.659342926572492 ], [ -60.514538993718247, -34.65952651697004 ], [ -60.514281967161679, -34.659673389288074 ], [ -60.514113063995936, -34.659923072228743 ], [ -60.514179156539058, -34.66003322646727 ], [ -60.514392121400213, -34.660114006242189 ], [ -60.514443526711524, -34.660246191328426 ], [ -60.514135094843645, -34.660466499805487 ], [ -60.514208531002659, -34.660650090203035 ], [ -60.51463446072497, -34.660628059355325 ], [ -60.514825394738423, -34.660547279580406 ], [ -60.515023672367775, -34.660679464666643 ], [ -60.515243980844836, -34.660958522070914 ], [ -60.515075077679093, -34.661009927382224 ], [ -60.51486211281793, -34.661061332693542 ], [ -60.514649147956774, -34.661266953938792 ], [ -60.514605086261369, -34.661494606031752 ], [ -60.514399465016112, -34.661847099595043 ], [ -60.513878068287077, -34.662295060165064 ] ] ] ] } }, 71 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.46763311073952, -34.452249286330215 ], [ -59.467265929944418, -34.45216116293939 ], [ -59.46730999163983, -34.452498969270884 ], [ -59.467647797971324, -34.45248428203908 ], [ -59.46808841492544, -34.452822088370567 ], [ -59.467985604302811, -34.452954273456804 ], [ -59.467691859666736, -34.452954273456804 ], [ -59.467133744858188, -34.453101145774838 ], [ -59.467148432089992, -34.453556449960757 ], [ -59.467354053335242, -34.453732696742406 ], [ -59.467691859666736, -34.453894256292244 ], [ -59.468029665998223, -34.453820820133231 ], [ -59.468470282952339, -34.453365515947311 ], [ -59.468484970184143, -34.452807401138763 ], [ -59.468734653124805, -34.452924898993196 ], [ -59.4691018339199, -34.453027709615817 ], [ -59.469454327483199, -34.452792713906959 ], [ -59.469160582847117, -34.452425533111864 ], [ -59.468984336065475, -34.452190537402998 ], [ -59.468690591429393, -34.45188210553512 ], [ -59.468411534025122, -34.451514924740025 ], [ -59.468000291534615, -34.451294616262963 ], [ -59.4675596745805, -34.451279929031159 ], [ -59.467236555480817, -34.451838043839707 ], [ -59.467691859666736, -34.451838043839707 ], [ -59.467912168143791, -34.452117101243978 ], [ -59.46763311073952, -34.452249286330215 ] ] ] ] } }, 72 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.70068496960031, -34.211797270853417 ], [ -60.700354506884722, -34.211731178310302 ], [ -60.699935920778309, -34.211833988932931 ], [ -60.69962748891043, -34.211863363396539 ], [ -60.699554052751409, -34.211694460230795 ], [ -60.699311713426646, -34.211672429383086 ], [ -60.698951876247449, -34.211701803846694 ], [ -60.698445166750219, -34.211782583621613 ], [ -60.698283607200374, -34.211951486787356 ], [ -60.698166109345948, -34.212179138880316 ], [ -60.69813673488234, -34.212465539900492 ], [ -60.698107360418732, -34.212597724986729 ], [ -60.697945800868887, -34.212553663291317 ], [ -60.6979825189484, -34.212414134589181 ], [ -60.698055955107414, -34.212201169728026 ], [ -60.697931113637082, -34.212149764416708 ], [ -60.697835646630359, -34.212135077184911 ], [ -60.697828303014454, -34.212002892098674 ], [ -60.697277531821811, -34.211995548482768 ], [ -60.697218782894595, -34.21221585695983 ], [ -60.696528482999817, -34.212538976059513 ], [ -60.696381610681776, -34.212832720695587 ], [ -60.69639629791358, -34.213016311093142 ], [ -60.696631293622445, -34.213398179120041 ], [ -60.697696117928224, -34.214117853478427 ], [ -60.698254232736772, -34.214022386471704 ], [ -60.699113435797294, -34.213258650417899 ], [ -60.699671550605842, -34.212663817529844 ], [ -60.70006076224864, -34.212340698430161 ], [ -60.700075449480444, -34.21221585695983 ], [ -60.700317788805208, -34.212142420800809 ], [ -60.700508722818661, -34.212245231423438 ], [ -60.700883247229662, -34.212010235714573 ], [ -60.70068496960031, -34.211797270853417 ] ] ] ] } }, 73 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -57.89151689140445, -36.875033013846249 ], [ -57.891179085072956, -36.874768643673782 ], [ -57.890180353310299, -36.874122405474409 ], [ -57.889607551269947, -36.874886141528208 ], [ -57.889519427879122, -36.875444256336756 ], [ -57.890356600091941, -36.875943622218088 ], [ -57.890547534105394, -36.876017058377109 ], [ -57.89151689140445, -36.875033013846249 ] ] ] ] } }, 74 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -57.889445991720102, -36.875899560522676 ], [ -57.887580713281011, -36.877030477371576 ], [ -57.887272281413132, -36.877852962352591 ], [ -57.886067928405218, -36.878528575015565 ], [ -57.885436377437649, -36.878704821797214 ], [ -57.884951698788122, -36.878543262247369 ], [ -57.885113258337967, -36.879072002592309 ], [ -57.884687328615655, -36.879160125983134 ], [ -57.884657954152047, -36.879453870619209 ], [ -57.885157320033379, -36.879600742937249 ], [ -57.885671373146515, -36.8794244961556 ], [ -57.885832932696353, -36.87914543875133 ], [ -57.886346985809489, -36.878734196260822 ], [ -57.886523232591138, -36.879248249373958 ], [ -57.887169470790504, -36.87935105999658 ], [ -57.887698211135444, -36.879292311069364 ], [ -57.887712898367248, -36.878939817506073 ], [ -57.887389779267565, -36.878851694115248 ], [ -57.887066660167882, -36.87861669840639 ], [ -57.887140096326895, -36.878337641002119 ], [ -57.887551338817403, -36.878719509029018 ], [ -57.888050704698735, -36.879204187678546 ], [ -57.88926974493846, -36.879233562142154 ], [ -57.889827859747001, -36.879072002592309 ], [ -57.890195040542103, -36.878484513320153 ], [ -57.890400661787353, -36.877867649584395 ], [ -57.889754423587981, -36.87763265387553 ], [ -57.889343181097473, -36.877338909239455 ], [ -57.88902006199779, -36.877147975226002 ], [ -57.888564757811871, -36.877441719862084 ], [ -57.888315074871208, -36.877735464498159 ], [ -57.888138828089559, -36.877559217716509 ], [ -57.888550070580067, -36.87710391353059 ], [ -57.889343181097473, -36.876677983808278 ], [ -57.889871921442413, -36.876810168894515 ], [ -57.890474097946374, -36.876604547649265 ], [ -57.890606283032611, -36.876207992390555 ], [ -57.889827859747001, -36.875693939277426 ], [ -57.889445991720102, -36.875899560522676 ] ] ] ] } }, 75 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -58.41456593401923, -37.17432942354521 ], [ -58.415329670073028, -37.1746525426449 ], [ -58.416137467822246, -37.173448189636979 ], [ -58.416489961385537, -37.173389440709762 ], [ -58.416710269862591, -37.173536313027803 ], [ -58.41688651664424, -37.173639123650432 ], [ -58.41762087823443, -37.173697872577648 ], [ -58.417973371797721, -37.173022259914667 ], [ -58.417988059029526, -37.172640391887768 ], [ -58.418017433493134, -37.172640391887768 ], [ -58.418413988751837, -37.172831325901221 ], [ -58.418986790792189, -37.172346647251693 ], [ -58.418737107851527, -37.171876655833969 ], [ -58.418267116433803, -37.17149478780707 ], [ -58.418413988751837, -37.171127607011968 ], [ -58.418693046156115, -37.170686990057852 ], [ -58.418487424910857, -37.170510743276211 ], [ -58.417679627161647, -37.171010109157542 ], [ -58.417312446366552, -37.171215730402793 ], [ -58.417194948512119, -37.171406664416246 ], [ -58.416915891107848, -37.171480100575266 ], [ -58.4163577762993, -37.171597598429692 ], [ -58.415726225331738, -37.171582911197888 ], [ -58.41537373176844, -37.171964779224794 ], [ -58.415314982841224, -37.172581642960552 ], [ -58.415535291318285, -37.173022259914667 ], [ -58.415344357304832, -37.173433502405175 ], [ -58.415050612668757, -37.173991617213723 ], [ -58.41456593401923, -37.17432942354521 ] ] ] ] } }, 76 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.568142254399746, -34.483621213463344 ], [ -61.567642888518414, -34.48332746882727 ], [ -61.565322305893403, -34.483797460244993 ], [ -61.565057935720937, -34.484884315398482 ], [ -61.565733548383918, -34.485236808961773 ], [ -61.565762922847526, -34.485266183425381 ], [ -61.566556033364932, -34.485295557888989 ], [ -61.567819135300063, -34.485031187716515 ], [ -61.568142254399746, -34.483621213463344 ] ] ] ] } }, 77 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.306724215522955, -34.277897157586786 ], [ -61.307150145245267, -34.277294981082832 ], [ -61.306063290091778, -34.277045298142163 ], [ -61.305842981614724, -34.277618100182515 ], [ -61.305519862515041, -34.277750285268752 ], [ -61.305123307256338, -34.278234963918273 ], [ -61.304902998779276, -34.278954638276666 ], [ -61.304814875388452, -34.279454004157998 ], [ -61.30438894566614, -34.280056180661951 ], [ -61.303845518089396, -34.281818648478414 ], [ -61.303669271307754, -34.283346120586017 ], [ -61.304021764871045, -34.283801424771937 ], [ -61.304902998779276, -34.284521099130323 ], [ -61.305945792237353, -34.284947028852635 ], [ -61.306650779363935, -34.285035152243459 ], [ -61.307869819603653, -34.284638596984756 ], [ -61.308457308875809, -34.284065794944404 ], [ -61.308824489670904, -34.283404869513234 ], [ -61.308883238598121, -34.282362076055158 ], [ -61.308560119498438, -34.281686463392184 ], [ -61.308119502544322, -34.28089335287477 ], [ -61.30734107925872, -34.280526172079675 ], [ -61.307326392026916, -34.279879933880309 ], [ -61.307003272927226, -34.2791015105947 ], [ -61.306900462304604, -34.278469959627138 ], [ -61.306724215522955, -34.277897157586786 ] ] ] ] } }, 78 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.136073269194, -33.903637116761004 ], [ -61.135573903312668, -33.904209918801349 ], [ -61.135882335180547, -33.904533037901039 ], [ -61.136484511684507, -33.905135214404993 ], [ -61.136190767048433, -33.905649267518129 ], [ -61.136234828743845, -33.906133946167657 ], [ -61.136337639366467, -33.906354254644718 ], [ -61.136690132929765, -33.90660393758538 ], [ -61.136998564797643, -33.906956431148672 ], [ -61.137409807288151, -33.907470484261808 ], [ -61.137938547633091, -33.907499858725416 ], [ -61.137938547633091, -33.907852352288707 ], [ -61.138100107182929, -33.908234220315606 ], [ -61.138643534759673, -33.908439841560863 ], [ -61.139275085727242, -33.90804328630216 ], [ -61.139480706972492, -33.907147365162125 ], [ -61.139392583581667, -33.906677373744401 ], [ -61.139260398495438, -33.906045822776832 ], [ -61.13877571984591, -33.905840201531582 ], [ -61.13804135825572, -33.905693329213541 ], [ -61.137644802997009, -33.905913637690603 ], [ -61.13733637112913, -33.906192695094873 ], [ -61.137160124347488, -33.90600176108142 ], [ -61.136969190334035, -33.905766765372562 ], [ -61.136910441406819, -33.905443646272879 ], [ -61.13713074988388, -33.905076465477777 ], [ -61.136983877565839, -33.90473865914629 ], [ -61.136719507393373, -33.904253980496762 ], [ -61.136646071234352, -33.903989610324295 ], [ -61.136469824452703, -33.903769301847234 ], [ -61.136073269194, -33.903637116761004 ] ] ] ] } }, 79 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.572798106881805, -34.882467680328887 ], [ -61.573605904631016, -34.882614552646928 ], [ -61.574017147121523, -34.88293767174661 ], [ -61.574516513002855, -34.883216729150881 ], [ -61.575089315043208, -34.882849548355786 ], [ -61.575618055388141, -34.882482367560691 ], [ -61.576176170196689, -34.882041750606575 ], [ -61.575897112792418, -34.881630508116068 ], [ -61.575603368156337, -34.881454261334419 ], [ -61.575427121374695, -34.881057706075715 ], [ -61.575104002275005, -34.881057706075715 ], [ -61.574869006566146, -34.881380825175405 ], [ -61.57481025763893, -34.881468948566223 ], [ -61.574310891757598, -34.881630508116068 ], [ -61.574310891757598, -34.882027063374771 ], [ -61.573958398194307, -34.881718631506892 ], [ -61.574399015148423, -34.881439574102615 ], [ -61.574428389612031, -34.881175203930148 ], [ -61.574428389612031, -34.881028331612107 ], [ -61.574252142830382, -34.880470216803566 ], [ -61.574061208816936, -34.880176472167484 ], [ -61.573605904631016, -34.879897414763214 ], [ -61.57301841535886, -34.879603670127139 ], [ -61.572504362245724, -34.879794604140585 ], [ -61.572151868682433, -34.879897414763214 ], [ -61.571637815569296, -34.879912101995018 ], [ -61.571153136919769, -34.880014912617646 ], [ -61.571020951833539, -34.880220533862897 ], [ -61.570932828442714, -34.880308657253721 ], [ -61.570536273184011, -34.880602401889796 ], [ -61.571241260310593, -34.880646463585208 ], [ -61.572798106881805, -34.882467680328887 ] ] ] ] } }, 80 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.097720490528161, -35.22241834766092 ], [ -59.098704535059021, -35.221816171156966 ], [ -59.09855766274098, -35.221419615898263 ], [ -59.098190481945885, -35.221081809566769 ], [ -59.097882050077999, -35.220626505380849 ], [ -59.097735177759965, -35.220274011817558 ], [ -59.098249230873101, -35.220053703340504 ], [ -59.098337354263919, -35.21958371192278 ], [ -59.097867362846195, -35.219157782200469 ], [ -59.097529556514708, -35.218996222650624 ], [ -59.096795194924518, -35.218937473723408 ], [ -59.09658957367926, -35.219451526836544 ], [ -59.096369265202206, -35.219289967286699 ], [ -59.096707071533693, -35.218805288637178 ], [ -59.09651613752024, -35.218673103550941 ], [ -59.096031458870719, -35.218805288637178 ], [ -59.095605529148408, -35.219010909882428 ], [ -59.095458656830367, -35.219216531127685 ], [ -59.096090207797928, -35.219495588531956 ], [ -59.096486763056639, -35.219730584240814 ], [ -59.096648322606477, -35.219936205486071 ], [ -59.096442701361227, -35.220332760744775 ], [ -59.096545511983848, -35.220744003235282 ], [ -59.096927380010754, -35.221125871262181 ], [ -59.096780507692714, -35.221346179739243 ], [ -59.097015503401572, -35.221551800984493 ], [ -59.097720490528161, -35.22241834766092 ] ] ] ] } }, 81 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -58.842243436916057, -35.456136267355653 ], [ -58.842258124147861, -35.456026113117119 ], [ -58.84243437092951, -35.45596736418991 ], [ -58.842390309234098, -35.45573971209695 ], [ -58.842346247538686, -35.455401905765456 ], [ -58.84213328267753, -35.455291751526929 ], [ -58.841898286968672, -35.455365187685949 ], [ -58.841655947643908, -35.455379874917753 ], [ -58.841538449789475, -35.455379874917753 ], [ -58.841119863683062, -35.455409249381361 ], [ -58.841002365828636, -35.455556121699395 ], [ -58.84101705306044, -35.455725024865146 ], [ -58.84117126899438, -35.455879240799085 ], [ -58.841274079617008, -35.456011425885315 ], [ -58.841207987073886, -35.45624642159418 ], [ -58.841105176451265, -35.456297826905491 ], [ -58.84092158605371, -35.456459386455336 ], [ -58.840855493510595, -35.4567017257801 ], [ -58.840848149894697, -35.457179060813722 ], [ -58.841002365828636, -35.457267184204547 ], [ -58.841494388094063, -35.457267184204547 ], [ -58.841839538041455, -35.457105624654702 ], [ -58.84183219442555, -35.456797192786823 ], [ -58.841810163577847, -35.456525478998451 ], [ -58.842067190134415, -35.456430011991728 ], [ -58.842324216690983, -35.456569540693863 ], [ -58.842610617711159, -35.456642976852883 ], [ -58.842507807088531, -35.456738443859606 ], [ -58.842265467763767, -35.456789849170924 ], [ -58.842081877366219, -35.456936721488958 ], [ -58.842008441207199, -35.457149686350114 ], [ -58.842140626293435, -35.457347963979466 ], [ -58.842471089009017, -35.457347963979466 ], [ -58.84266202302247, -35.457245153356844 ], [ -58.842720771949686, -35.457083593806999 ], [ -58.842904362347234, -35.457076250191101 ], [ -58.842955767658545, -35.457311245899959 ], [ -58.843080609128883, -35.457443430986196 ], [ -58.843756221791857, -35.457414056522587 ], [ -58.843939812189404, -35.457024844879783 ], [ -58.844005904732519, -35.456518135382552 ], [ -58.843961843037114, -35.456195016282862 ], [ -58.843682785632836, -35.456070174812531 ], [ -58.843455133539877, -35.456070174812531 ], [ -58.843212794215113, -35.456165641819261 ], [ -58.842801551724605, -35.456290483289592 ], [ -58.842500463472625, -35.456187672666964 ], [ -58.842243436916057, -35.456136267355653 ] ] ] ] } }, 82 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -59.082599985386125, -36.036362703382792 ], [ -59.08228420990234, -36.0360175534354 ], [ -59.08207858865709, -36.036105676826224 ], [ -59.08230624075005, -36.036370046998698 ], [ -59.082196086511523, -36.036443483157711 ], [ -59.081975778034462, -36.03654629378034 ], [ -59.081637971702975, -36.036854725648226 ], [ -59.081887654643637, -36.036986910734456 ], [ -59.082144681200205, -36.036942849039043 ], [ -59.082563267306618, -36.036928161807239 ], [ -59.082394364140875, -36.037053003277578 ], [ -59.082166712047915, -36.037185188363807 ], [ -59.082181399279719, -36.03737612237726 ], [ -59.082342958829557, -36.037537681927098 ], [ -59.08253389284301, -36.037691897861045 ], [ -59.082746857704166, -36.037838770179079 ], [ -59.08306263318795, -36.038022360576626 ], [ -59.083451844830748, -36.038022360576626 ], [ -59.083789651162242, -36.037882831874491 ], [ -59.084186206420945, -36.037522994695301 ], [ -59.08427432981177, -36.037192531979713 ], [ -59.084127457493729, -36.036964879886753 ], [ -59.083980585175688, -36.036759258641496 ], [ -59.083980585175688, -36.036737227793793 ], [ -59.083987928791593, -36.036707853330185 ], [ -59.084171519189141, -36.036502232084928 ], [ -59.084193550036844, -36.036333328919184 ], [ -59.084105426646019, -36.036149738521637 ], [ -59.083929179864377, -36.035966148124089 ], [ -59.083907149016667, -36.035892711965069 ], [ -59.083606060764694, -36.035833963037852 ], [ -59.083451844830748, -36.035819275806048 ], [ -59.0832682544332, -36.035936773660481 ], [ -59.083400439519437, -36.036193800217049 ], [ -59.083172787426477, -36.036303954455576 ], [ -59.083047945956146, -36.03634067253509 ], [ -59.082827637479085, -36.036362703382792 ], [ -59.082599985386125, -36.036362703382792 ] ] ] ] } }, 83 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -58.82839337732505, -38.515633524416515 ], [ -58.828305253934225, -38.515721647807339 ], [ -58.827659015734859, -38.516044766907022 ], [ -58.827864636980109, -38.516338511543097 ], [ -58.827100900926311, -38.516779128497213 ], [ -58.827864636980109, -38.517366617769369 ], [ -58.829568355869355, -38.518570970777283 ], [ -58.831154576904176, -38.520127817348495 ], [ -58.831242700295, -38.520127817348495 ], [ -58.832123934203231, -38.519657825930771 ], [ -58.833240163820321, -38.518835340949757 ], [ -58.832975793647854, -38.518218477213992 ], [ -58.832711423475381, -38.517924732577917 ], [ -58.832505802230131, -38.517425366696585 ], [ -58.831653942785508, -38.516955375278862 ], [ -58.830948955658918, -38.516485383861138 ], [ -58.829950223896262, -38.515339779780433 ], [ -58.828687121961124, -38.515897894588981 ], [ -58.82839337732505, -38.515633524416515 ] ] ] ] } }, 84 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -58.74517552192443, -38.150802686408795 ], [ -58.744176790161767, -38.150993620422248 ], [ -58.743589300889617, -38.150920184263228 ], [ -58.743089935008285, -38.150773311945187 ], [ -58.742458384040717, -38.150729250249775 ], [ -58.742414322345304, -38.150391443918288 ], [ -58.742884313763028, -38.150127073745821 ], [ -58.742972437153853, -38.150038950354997 ], [ -58.743251494558123, -38.149789267414327 ], [ -58.74345711580338, -38.149554271705469 ], [ -58.743589300889617, -38.149289901532995 ], [ -58.743119309471894, -38.149069593055941 ], [ -58.742605256358758, -38.149642395096294 ], [ -58.742267450027271, -38.149789267414327 ], [ -58.742091203245622, -38.14970114402351 ], [ -58.74212057770923, -38.149319275996604 ], [ -58.742091203245622, -38.148952095201508 ], [ -58.741635899059702, -38.148863971810684 ], [ -58.741195282105586, -38.149098967519549 ], [ -58.74113653317837, -38.149921452500564 ], [ -58.741180594873782, -38.150171135441227 ], [ -58.74166527352331, -38.150097699282213 ], [ -58.741900269232175, -38.150597065163545 ], [ -58.742076516013817, -38.151037682117661 ], [ -58.742326198954487, -38.151243303362911 ], [ -58.742664005285974, -38.151492986303573 ], [ -58.742957749922049, -38.151727982012439 ], [ -58.742913688226636, -38.152036413880317 ], [ -58.742693379749582, -38.152095162807534 ], [ -58.742267450027271, -38.152271409589183 ], [ -58.742223388331858, -38.152579841457062 ], [ -58.742443696808913, -38.153049832874785 ], [ -58.742693379749582, -38.15313795626561 ], [ -58.742957749922049, -38.153093894570198 ], [ -58.74345711580338, -38.152770775470515 ], [ -58.743677424280442, -38.152007039416709 ], [ -58.744529283725065, -38.151595796926202 ], [ -58.745072711301802, -38.151786730939655 ], [ -58.745660200573958, -38.151184554435694 ], [ -58.74517552192443, -38.150802686408795 ] ] ] ] } }, 85 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -61.251977558974403, -38.696697718094455 ], [ -61.252594422710168, -38.697167709512179 ], [ -61.253270035373141, -38.696492096849198 ], [ -61.25344628215479, -38.69646272238559 ], [ -61.253681277863649, -38.696668343630847 ], [ -61.253534405545608, -38.696962088266922 ], [ -61.253857524645298, -38.697138335048571 ], [ -61.254621260699096, -38.697373330757429 ], [ -61.255561243534544, -38.697167709512179 ], [ -61.25635435405195, -38.696492096849198 ], [ -61.256765596542458, -38.696168977749515 ], [ -61.257294336887398, -38.695640237404575 ], [ -61.256648098688025, -38.69519962045046 ], [ -61.25620748173391, -38.695434616159318 ], [ -61.256266230661126, -38.695875233113433 ], [ -61.255737490316186, -38.696374598994765 ], [ -61.25509125211682, -38.696638969167239 ], [ -61.254533137308272, -38.696727092558064 ], [ -61.254180643744981, -38.696550845776414 ], [ -61.25403377142694, -38.69593398204065 ], [ -61.254797507480745, -38.695375867232109 ], [ -61.255473120143719, -38.694993999205202 ], [ -61.255766864779794, -38.694993999205202 ], [ -61.256559975297208, -38.694670880105519 ], [ -61.256060609415876, -38.693701522806464 ], [ -61.255003128725996, -38.693848395124505 ], [ -61.253886899108906, -38.693848395124505 ], [ -61.252888167346242, -38.694200888687796 ], [ -61.252418175928518, -38.694435884396661 ], [ -61.251801312192754, -38.69519962045046 ], [ -61.252653171637377, -38.696198352213123 ], [ -61.251977558974403, -38.696697718094455 ] ] ] ] } }, 86 | { "type": "Feature", "properties": { "class": "B", "id": null }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -62.249306690999234, -38.097811154060501 ], [ -62.249703246257937, -38.098060837001171 ], [ -62.250981035424871, -38.096474615966351 ], [ -62.251142594974716, -38.096503990429959 ], [ -62.250922286497655, -38.096988669079487 ], [ -62.2510838460475, -38.097443973265406 ], [ -62.251304154524554, -38.097576158351643 ], [ -62.251686022551453, -38.097120854165723 ], [ -62.25181820763769, -38.096533364893567 ], [ -62.252508507532475, -38.096254307489296 ], [ -62.25272881600953, -38.096562739357175 ], [ -62.252420384141651, -38.096841796761446 ], [ -62.252229450128198, -38.097502722192623 ], [ -62.252229450128198, -38.097943339146738 ], [ -62.252978498950199, -38.098310519941833 ], [ -62.25399191794466, -38.098148960391988 ], [ -62.254182851958113, -38.097517409424427 ], [ -62.254153477494505, -38.096827109529642 ], [ -62.253698173308585, -38.096151496866668 ], [ -62.253389741440706, -38.09612212240306 ], [ -62.252963811718395, -38.095754941607964 ], [ -62.253272243586274, -38.095608069289923 ], [ -62.253903794553835, -38.095343699117457 ], [ -62.253815671163018, -38.094903082163341 ], [ -62.253404428672511, -38.094638711990868 ], [ -62.253037247877408, -38.094565275831847 ], [ -62.252743503241334, -38.094300905659381 ], [ -62.252009141651143, -38.094903082163341 ], [ -62.250995722656675, -38.095843064998789 ], [ -62.250041052589424, -38.096915232920466 ], [ -62.249306690999234, -38.097811154060501 ] ] ] ] } } 87 | ] 88 | } 89 | -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_13_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_13_37.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_13_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_13_38.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_13_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_13_39.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_13_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_13_40.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_14_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_14_37.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_14_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_14_38.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_14_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_14_39.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_14_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_14_40.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_15_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_15_37.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_15_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_15_38.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_15_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_15_39.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_15_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_15_40.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_16_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_16_37.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_16_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_16_38.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_16_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_16_39.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_16_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_16_40.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_17_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_17_37.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_17_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_17_38.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_17_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_17_39.tif -------------------------------------------------------------------------------- /tests/data/results/0000054272-0000054272_17_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/results/0000054272-0000054272_17_40.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_13_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_13_37.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_13_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_13_38.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_13_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_13_39.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_13_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_13_40.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_14_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_14_37.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_14_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_14_38.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_14_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_14_39.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_14_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_14_40.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_15_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_15_37.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_15_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_15_38.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_15_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_15_39.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_15_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_15_40.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_16_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_16_37.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_16_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_16_38.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_16_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_16_39.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_16_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_16_40.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_17_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_17_37.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_17_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_17_38.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_17_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_17_39.tif -------------------------------------------------------------------------------- /tests/data/train/extent/0000054272-0000054272_17_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/extent/0000054272-0000054272_17_40.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_13_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_13_37.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_13_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_13_38.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_13_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_13_39.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_13_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_13_40.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_14_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_14_37.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_14_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_14_38.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_14_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_14_39.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_14_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_14_40.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_15_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_15_37.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_15_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_15_38.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_15_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_15_39.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_15_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_15_40.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_16_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_16_37.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_16_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_16_38.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_16_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_16_39.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_16_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_16_40.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_17_37.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_17_37.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_17_38.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_17_38.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_17_39.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_17_39.tif -------------------------------------------------------------------------------- /tests/data/train/images/0000054272-0000054272_17_40.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dymaxionlabs/unetseg/971b5137cb8874652bc6d0245f88ec1c1d97c350/tests/data/train/images/0000054272-0000054272_17_40.tif -------------------------------------------------------------------------------- /tests/test_evaluate.py: -------------------------------------------------------------------------------- 1 | import matplotlib 2 | 3 | from unetseg.evaluate import plot_data_generator, plot_data_results 4 | from unetseg.predict import PredictConfig 5 | from unetseg.train import TrainConfig 6 | 7 | __author__ = "Damián Silvani" 8 | __copyright__ = "Dymaxion Labs" 9 | __license__ = "apache-2.0" 10 | 11 | 12 | def test_plot_data_generator(shared_datadir): 13 | matplotlib.use("agg") 14 | 15 | images_path = shared_datadir / "train" 16 | cfg = TrainConfig( 17 | images_path=images_path, 18 | width=160, 19 | height=160, 20 | n_channels=3, 21 | n_classes=1, 22 | apply_image_augmentation=True, 23 | seed=42, 24 | epochs=1, 25 | steps_per_epoch=10, 26 | batch_size=4, 27 | model_architecture="unet", 28 | evaluate=True, 29 | class_weights=[1], 30 | ) 31 | 32 | plot_data_generator(num_samples=4, train_config=cfg) 33 | 34 | 35 | def test_plot_data_results(shared_datadir): 36 | matplotlib.use("agg") 37 | 38 | images_path = shared_datadir / "train" 39 | results_path = shared_datadir / "results" 40 | 41 | cfg = PredictConfig( 42 | images_path=images_path, 43 | results_path=results_path, 44 | batch_size=4, 45 | height=160, 46 | width=160, 47 | n_channels=3, 48 | n_classes=1, 49 | class_weights=[1], 50 | ) 51 | 52 | plot_data_results(predict_config=cfg) 53 | -------------------------------------------------------------------------------- /tests/test_postprocess.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from unetseg.postprocess import merge 4 | 5 | __author__ = "Damián Silvani" 6 | __copyright__ = "Dymaxion Labs" 7 | __license__ = "apache-2.0" 8 | 9 | 10 | def test_main(): 11 | assert True 12 | -------------------------------------------------------------------------------- /tests/test_predict.py: -------------------------------------------------------------------------------- 1 | import tempfile 2 | from pathlib import Path 3 | 4 | from unetseg.predict import PredictConfig, predict 5 | from unetseg.train import TrainConfig, train 6 | 7 | __author__ = "Damián Silvani" 8 | __copyright__ = "Dymaxion Labs" 9 | __license__ = "apache-2.0" 10 | 11 | 12 | def train_test_model(*, images_path, model_path): 13 | cfg = TrainConfig( 14 | images_path=images_path, 15 | width=160, 16 | height=160, 17 | n_channels=3, 18 | n_classes=1, 19 | apply_image_augmentation=True, 20 | seed=42, 21 | epochs=1, 22 | steps_per_epoch=10, 23 | batch_size=4, 24 | model_architecture="unet", 25 | evaluate=True, 26 | class_weights=[1], 27 | model_path=model_path, 28 | ) 29 | train(cfg) 30 | 31 | 32 | def test_predict(shared_datadir): 33 | with tempfile.TemporaryDirectory() as tmpdir: 34 | images_path = shared_datadir / "train" 35 | model_path = Path(tmpdir) / "unet_model.h5" 36 | results_path = Path(tmpdir) / "results" 37 | 38 | # Train a test model first, to predict with 39 | train_test_model(images_path=images_path, model_path=model_path) 40 | assert model_path.is_file() 41 | 42 | cfg = PredictConfig( 43 | images_path=images_path, 44 | results_path=results_path, 45 | batch_size=4, 46 | model_path=model_path, 47 | height=160, 48 | width=160, 49 | n_channels=3, 50 | n_classes=1, 51 | class_weights=[1], 52 | ) 53 | predict(cfg) 54 | 55 | image_files = list((images_path / "images").glob("*.tif")) 56 | result_files = list(results_path.glob("*.tif")) 57 | assert len(result_files) == len(image_files) 58 | -------------------------------------------------------------------------------- /tests/test_train.py: -------------------------------------------------------------------------------- 1 | import tempfile 2 | from pathlib import Path 3 | 4 | from unetseg.train import TrainConfig, train 5 | 6 | __author__ = "Damián Silvani" 7 | __copyright__ = "Dymaxion Labs" 8 | __license__ = "apache-2.0" 9 | 10 | 11 | def test_train_unet(shared_datadir): 12 | with tempfile.TemporaryDirectory() as tmpdir: 13 | images_path = shared_datadir / "train" 14 | model_path = Path(tmpdir) / "unet_model.h5" 15 | 16 | cfg = TrainConfig( 17 | images_path=images_path, 18 | width=160, 19 | height=160, 20 | n_channels=3, 21 | n_classes=1, 22 | apply_image_augmentation=True, 23 | seed=42, 24 | epochs=1, 25 | steps_per_epoch=10, 26 | batch_size=4, 27 | model_architecture="unet", 28 | evaluate=True, 29 | class_weights=[1], 30 | model_path=model_path, 31 | ) 32 | 33 | res = train(cfg) 34 | 35 | assert res.params["epochs"] == 1 36 | assert res.params["steps"] == 10 37 | assert len(res.epoch) == 1 38 | assert model_path.is_file() 39 | 40 | 41 | def test_train_unetplusplus(shared_datadir): 42 | with tempfile.TemporaryDirectory() as tmpdir: 43 | images_path = shared_datadir / "train" 44 | model_path = Path(tmpdir) / "unet_model.h5" 45 | 46 | cfg = TrainConfig( 47 | images_path=images_path, 48 | width=160, 49 | height=160, 50 | n_channels=3, 51 | n_classes=1, 52 | apply_image_augmentation=True, 53 | seed=42, 54 | epochs=1, 55 | steps_per_epoch=10, 56 | batch_size=4, 57 | model_architecture="unetplusplus", 58 | evaluate=True, 59 | class_weights=[1], 60 | model_path=model_path, 61 | ) 62 | 63 | res = train(cfg) 64 | 65 | assert res.params["epochs"] == 1 66 | assert res.params["steps"] == 10 67 | assert len(res.epoch) == 1 68 | assert model_path.is_file() 69 | -------------------------------------------------------------------------------- /unetseg/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from pkg_resources import DistributionNotFound, get_distribution 3 | 4 | try: 5 | # Change here if project is renamed and does not equal the package name 6 | dist_name = __name__ 7 | __version__ = get_distribution(dist_name).version 8 | except DistributionNotFound: 9 | __version__ = "unknown" 10 | finally: 11 | del get_distribution, DistributionNotFound 12 | -------------------------------------------------------------------------------- /unetseg/console/predict.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | This is a skeleton file that can serve as a starting point for a Python 4 | console script. To run this script uncomment the following lines in the 5 | [options.entry_points] section in setup.cfg: 6 | 7 | console_scripts = 8 | fibonacci = unetseg.skeleton:run 9 | 10 | Then run `python setup.py install` which will install the command `fibonacci` 11 | inside your current environment. 12 | Besides console scripts, the header (i.e. until _logger...) of this file can 13 | also be used as template for Python modules. 14 | 15 | Note: This skeleton file can be safely removed if not needed! 16 | """ 17 | 18 | import argparse 19 | import logging 20 | import sys 21 | 22 | from unetseg import __version__ 23 | from unetseg.predict import PredictConfig, predict 24 | 25 | __author__ = "Damián Silvani" 26 | __copyright__ = "Dymaxion Labs" 27 | __license__ = "apache-2.0" 28 | 29 | _logger = logging.getLogger(__name__) 30 | 31 | 32 | def parse_args(args): 33 | """Parse command line parameters 34 | 35 | Args: 36 | args ([str]): command line parameters as list of strings 37 | 38 | Returns: 39 | :obj:`argparse.Namespace`: command line parameters namespace 40 | """ 41 | parser = argparse.ArgumentParser( 42 | description="Predict over a directory of image tiles", 43 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, 44 | ) 45 | 46 | parser.add_argument( 47 | "--version", action="version", version="unetseg {ver}".format(ver=__version__) 48 | ) 49 | parser.add_argument( 50 | "-v", 51 | "--verbose", 52 | dest="loglevel", 53 | help="set loglevel to INFO", 54 | action="store_const", 55 | const=logging.INFO, 56 | ) 57 | parser.add_argument( 58 | "-vv", 59 | "--very-verbose", 60 | dest="loglevel", 61 | help="set loglevel to DEBUG", 62 | action="store_const", 63 | const=logging.DEBUG, 64 | ) 65 | 66 | parser.add_argument("dir", help="Path to image tiles to predict") 67 | parser.add_argument( 68 | "-o", 69 | "--output-dir", 70 | help="path to results output directory", 71 | default="./results", 72 | ) 73 | parser.add_argument( 74 | "--model", "-m", help="path to trained model (.h5)", default="./unet.h5" 75 | ) 76 | parser.add_argument("-W", "--width", type=int, help="Image tile width") 77 | parser.add_argument("-H", "--height", type=int, help="Image tile height") 78 | parser.add_argument( 79 | "-N", "--num-channels", default=3, type=int, help="Number of channels" 80 | ) 81 | parser.add_argument( 82 | "-C", "--num-classes", default=1, type=int, help="Number of classes" 83 | ) 84 | parser.add_argument( 85 | "--batch-size", default=32, type=int, help="Batch size for prediction" 86 | ) 87 | 88 | return parser.parse_args(args) 89 | 90 | 91 | def setup_logging(loglevel): 92 | """Setup basic logging 93 | 94 | Args: 95 | loglevel (int): minimum loglevel for emitting messages 96 | """ 97 | logformat = "[%(asctime)s] %(levelname)s:%(name)s:%(message)s" 98 | logging.basicConfig( 99 | level=loglevel, stream=sys.stdout, format=logformat, datefmt="%Y-%m-%d %H:%M:%S" 100 | ) 101 | 102 | 103 | def main(args): 104 | """Main entry point allowing external calls 105 | 106 | Args: 107 | args ([str]): command line parameter list 108 | """ 109 | args = parse_args(args) 110 | setup_logging(args.loglevel) 111 | 112 | config = PredictConfig( 113 | batch_size=args.batch_size, 114 | model_path=args.model, 115 | images_path=args.dir, 116 | results_path=args.output_dir, 117 | height=args.height, 118 | width=args.width, 119 | n_channels=args.num_channels, 120 | n_classes=args.num_classes, 121 | ) 122 | 123 | predict(config) 124 | 125 | 126 | def run(): 127 | """Entry point for console_scripts""" 128 | main(sys.argv[1:]) 129 | 130 | 131 | if __name__ == "__main__": 132 | run() 133 | -------------------------------------------------------------------------------- /unetseg/console/train.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | This is a skeleton file that can serve as a starting point for a Python 4 | console script. To run this script uncomment the following lines in the 5 | [options.entry_points] section in setup.cfg: 6 | 7 | console_scripts = 8 | fibonacci = unetseg.skeleton:run 9 | 10 | Then run `python setup.py install` which will install the command `fibonacci` 11 | inside your current environment. 12 | Besides console scripts, the header (i.e. until _logger...) of this file can 13 | also be used as template for Python modules. 14 | 15 | Note: This skeleton file can be safely removed if not needed! 16 | """ 17 | 18 | import argparse 19 | import logging 20 | import sys 21 | 22 | from unetseg import __version__ 23 | from unetseg.train import TrainConfig, train 24 | 25 | __author__ = "Damián Silvani" 26 | __copyright__ = "Dymaxion Labs" 27 | __license__ = "apache-2.0" 28 | 29 | _logger = logging.getLogger(__name__) 30 | 31 | 32 | def parse_args(args): 33 | """Parse command line parameters 34 | 35 | Args: 36 | args ([str]): command line parameters as list of strings 37 | 38 | Returns: 39 | :obj:`argparse.Namespace`: command line parameters namespace 40 | """ 41 | parser = argparse.ArgumentParser( 42 | description="Train a model", 43 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, 44 | ) 45 | parser.add_argument( 46 | "--version", action="version", version="unetseg {ver}".format(ver=__version__) 47 | ) 48 | parser.add_argument( 49 | "-v", 50 | "--verbose", 51 | dest="loglevel", 52 | help="set loglevel to INFO", 53 | action="store_const", 54 | const=logging.INFO, 55 | ) 56 | parser.add_argument( 57 | "-vv", 58 | "--very-verbose", 59 | dest="loglevel", 60 | help="set loglevel to DEBUG", 61 | action="store_const", 62 | const=logging.DEBUG, 63 | ) 64 | 65 | parser.add_argument( 66 | "train_dir", 67 | help="Path to image tiles and masks (directory with images/ and masks/)", 68 | ) 69 | parser.add_argument( 70 | "-o", "--output", help="path to output model (.h5)", default="./unet.h5" 71 | ) 72 | parser.add_argument("-W", "--width", type=int, help="Image tile width") 73 | parser.add_argument("-H", "--height", type=int, help="Image tile height") 74 | parser.add_argument( 75 | "-N", "--num-channels", default=3, type=int, help="Number of channels" 76 | ) 77 | parser.add_argument( 78 | "-C", "--num-classes", default=1, type=int, help="Number of classes" 79 | ) 80 | parser.add_argument( 81 | "-E", "--epochs", default=15, type=int, help="number of training epochs" 82 | ) 83 | parser.add_argument( 84 | "--steps-per-epoch", default=100, type=int, help="steps per epoch" 85 | ) 86 | parser.add_argument( 87 | "--early-stopping-patience", 88 | default=3, 89 | type=int, 90 | help="number of epochs with no improvement after which training will be stopped", 91 | ) 92 | parser.add_argument("--batch-size", default=32, type=int, help="batch size") 93 | parser.add_argument( 94 | "--image-augmentation", 95 | dest="image_augmentation", 96 | help="Apply image augmentation", 97 | action="store_true", 98 | default=True, 99 | ) 100 | parser.add_argument( 101 | "--no-image-augmentation", 102 | dest="image_augmentation", 103 | help="Do not apply image augmentation", 104 | action="store_false", 105 | default=False, 106 | ) 107 | parser.add_argument( 108 | "--evaluate", 109 | dest="evaluate", 110 | help="Evaluate metrics over validation set at the end of training", 111 | action="store_true", 112 | default=True, 113 | ) 114 | parser.add_argument( 115 | "--no-evaluate", 116 | dest="evaluate", 117 | help="Do not evaluate emtrics over validation set at the end of training", 118 | action="store_false", 119 | default=False, 120 | ) 121 | parser.add_argument( 122 | "-s", 123 | "--seed", 124 | default=None, 125 | type=int, 126 | help="Seed number for the random number generation", 127 | ) 128 | 129 | return parser.parse_args(args) 130 | 131 | 132 | def setup_logging(loglevel): 133 | """Setup basic logging 134 | 135 | Args: 136 | loglevel (int): minimum loglevel for emitting messages 137 | """ 138 | logformat = "[%(asctime)s] %(levelname)s:%(name)s:%(message)s" 139 | logging.basicConfig( 140 | level=loglevel, stream=sys.stdout, format=logformat, datefmt="%Y-%m-%d %H:%M:%S" 141 | ) 142 | 143 | 144 | def main(args): 145 | """Main entry point allowing external calls 146 | 147 | Args: 148 | args ([str]): command line parameter list 149 | """ 150 | args = parse_args(args) 151 | setup_logging(args.loglevel) 152 | 153 | config = TrainConfig( 154 | width=args.width, 155 | height=args.height, 156 | n_channels=args.num_channels, 157 | n_classes=args.num_classes, 158 | epochs=args.epochs, 159 | steps_per_epoch=args.steps_per_epoch, 160 | early_stopping_patience=args.early_stopping_patience, 161 | apply_image_augmentation=args.image_augmentation, 162 | batch_size=args.batch_size, 163 | seed=args.seed, 164 | images_path=args.train_dir, 165 | evaluate=args.evaluate, 166 | model_path=args.output, 167 | ) 168 | 169 | train(config) 170 | 171 | 172 | def run(): 173 | """Entry point for console_scripts""" 174 | main(sys.argv[1:]) 175 | 176 | 177 | if __name__ == "__main__": 178 | run() 179 | -------------------------------------------------------------------------------- /unetseg/evaluate.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | from glob import glob 4 | 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | import tifffile as tiff 8 | from skimage.transform import resize 9 | 10 | from unetseg.predict import PredictConfig 11 | from unetseg.train import TrainConfig, build_data_generator 12 | 13 | 14 | def plot_data_generator( 15 | num_samples: int = 3, 16 | fig_size=(20, 10), 17 | *, 18 | train_config: TrainConfig, 19 | img_ch: int = 3 20 | ): 21 | """ 22 | Plots some samples from a data generator. 23 | 24 | Parameters 25 | ---------- 26 | num_samples : int 27 | Number of samples to plot. 28 | fig_size : tuple 29 | Figure size. 30 | img_ch : int 31 | Number of channels. 32 | train_config : TrainConfig 33 | Training configuration object. 34 | 35 | """ 36 | 37 | if train_config.n_channels < 4: 38 | img_ch = train_config.n_channels 39 | 40 | images_dir = os.path.join(train_config.images_path, "images") 41 | mask_dir = train_config.masks_path or os.path.join( 42 | train_config.images_path, "extent" 43 | ) 44 | 45 | images = glob(os.path.join(images_dir, "*.tif")) 46 | 47 | data_generator = build_data_generator( 48 | images, config=train_config, mask_dir=mask_dir 49 | ) 50 | 51 | def plot_samples(plt, generator, num): 52 | j = 0 53 | for image_batch, mask_batch in data_generator: 54 | for image, mask in zip(image_batch, mask_batch): 55 | _, ax = plt.subplots( 56 | nrows=1, ncols=train_config.n_classes + 1, figsize=fig_size 57 | ) 58 | 59 | if train_config.n_channels < 4: 60 | image = image[:, :, 0].astype(np.uint8) 61 | else: 62 | image = image[:, :, :img_ch].astype(np.uint8) 63 | 64 | ax[0].imshow(image) 65 | for i in range(train_config.n_classes): 66 | ax[i + 1].imshow(mask[:, :, i]) 67 | j += 1 68 | if j >= num: 69 | return 70 | 71 | plot_samples(plt, data_generator, num_samples) 72 | plt.show() 73 | 74 | 75 | def plot_data_results( 76 | num_samples: int = 3, 77 | fig_size=(20, 10), 78 | *, 79 | predict_config: PredictConfig, 80 | img_ch: int = 3, 81 | n_bands: int = 3 82 | ): 83 | """ 84 | Plots some samples from the results directory. 85 | Parameters 86 | ---------- 87 | num_samples : int 88 | Number of samples to plot. 89 | fig_size : tuple 90 | Figure size. 91 | img_ch : int 92 | Number of channels. 93 | predict_config : PredictConfig 94 | Prediction onfiguration object. 95 | """ 96 | 97 | images = [ 98 | os.path.basename(f) 99 | for f in sorted(glob(os.path.join(predict_config.results_path, "*.tif"))) 100 | ] 101 | 102 | images = random.sample(images, num_samples) 103 | for img_file in images: 104 | try: 105 | if n_bands not in (1, 3): 106 | raise RuntimeError("n_bands option must be 1 or 3") 107 | 108 | fig, axes = plt.subplots( 109 | nrows=1, ncols=predict_config.n_classes + 1, figsize=(20, 40) 110 | ) 111 | 112 | if n_bands == 1: 113 | 114 | img_s2 = tiff.imread( 115 | os.path.join(predict_config.images_path, "images", img_file) 116 | )[:, :, img_ch] 117 | axes[0].imshow(img_s2) 118 | 119 | if n_bands == 3: 120 | 121 | img_s2 = tiff.imread( 122 | os.path.join(predict_config.images_path, "images", img_file) 123 | )[:, :, :3] 124 | axes[0].imshow(img_s2) 125 | 126 | # Prediccion 127 | mask_ = ( 128 | tiff.imread(os.path.join(predict_config.results_path, img_file)) / 255 129 | ) 130 | 131 | mask_ = resize( 132 | mask_, 133 | (predict_config.height, predict_config.width, predict_config.n_classes), 134 | mode="constant", 135 | preserve_range=True, 136 | ) 137 | 138 | for c in range(predict_config.n_classes): 139 | axes[1 + c].imshow(np.squeeze(mask_[:, :, c])) 140 | 141 | plt.show() 142 | 143 | except Exception as err: 144 | print(err) 145 | -------------------------------------------------------------------------------- /unetseg/postprocess.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import math 3 | import os 4 | from glob import glob 5 | from typing import List, Tuple 6 | 7 | import numpy as np 8 | import rasterio 9 | import rasterio.merge 10 | import rasterio.windows 11 | from rasterio.transform import Affine 12 | from tqdm import tqdm 13 | 14 | _logger = logging.getLogger(__name__) 15 | 16 | 17 | def get_bounds_from_image_files(image_files: List[str]) -> Tuple[float]: 18 | """Get bounds from all images, and transform to pixels based on the affine transform""" 19 | xs = [] 20 | ys = [] 21 | for img_path in tqdm(image_files): 22 | with rasterio.open(img_path) as src: 23 | left, bottom, right, top = src.bounds 24 | xs.extend([left, right]) 25 | ys.extend([bottom, top]) 26 | dst_w, dst_s, dst_e, dst_n = min(xs), min(ys), max(xs), max(ys) 27 | return (dst_w, dst_s, dst_e, dst_n) 28 | 29 | 30 | def crop_image(img: np.ndarray, margin_ratio: float) -> np.ndarray: 31 | """Center crop an image, with a margin of ``margin_ratio``""" 32 | h, w = img.shape[0], img.shape[1] 33 | h_margin = math.floor(h * margin_ratio) 34 | w_margin = math.floor(w * margin_ratio) 35 | return img[h_margin:-h_margin, w_margin:-w_margin] 36 | 37 | 38 | def merge(images_dir: str, output_path: str, crop_margin_ratio: float = 0.125): 39 | """Merge all images in ``images_dir`` into a single image""" 40 | image_paths = glob(os.path.join(images_dir, "*.tif")) 41 | if not image_paths: 42 | raise RuntimeError("images_dir does not contain any .tif file") 43 | 44 | # Get the profile and affine of some image as template for output image 45 | with rasterio.open(image_paths[0]) as src: 46 | profile = src.profile.copy() 47 | src_res = src.res 48 | src_count = src.count 49 | # nodataval = src.nodatavals[0] 50 | # dt = src.dtypes[0] 51 | # transform = src.transform 52 | 53 | # Get bounds from all images, and transform to (width, height) in pixels 54 | dst_w, dst_s, dst_e, dst_n = get_bounds_from_image_files(image_paths) 55 | 56 | _logger.debug("Output bounds: %r", (dst_w, dst_s, dst_e, dst_n)) 57 | output_transform = Affine.translation(dst_w, dst_n) 58 | _logger.debug("Output transform, before scaling: %r", output_transform) 59 | 60 | output_transform *= Affine.scale(src_res[0], -src_res[1]) 61 | _logger.debug("Output transform, after scaling: %r", output_transform) 62 | 63 | # Compute output array shape. We guarantee it will cover the output 64 | # bounds completely 65 | output_width = int(math.ceil((dst_e - dst_w) / src_res[0])) 66 | output_height = int(math.ceil((dst_n - dst_s) / src_res[1])) 67 | 68 | # Adjust bounds to fit 69 | dst_e, dst_s = output_transform * (output_width, output_height) 70 | _logger.debug("Output width: %d, height: %d", output_width, output_height) 71 | _logger.debug("Adjusted bounds: %r", (dst_w, dst_s, dst_e, dst_n)) 72 | 73 | # Set width and height, and other attributes 74 | profile.update( 75 | width=output_width, height=output_height, transform=output_transform, tiled=True 76 | ) 77 | 78 | # Call rasterio.merge using windowed reading-writing 79 | # and a custom callable that center-crops image. 80 | with rasterio.open(output_path, "w", **profile) as dst: 81 | for image_path in image_paths: 82 | with rasterio.open(image_path) as src: 83 | img = np.dstack(src.read()) 84 | b = src.bounds 85 | window = rasterio.windows.from_bounds( 86 | b[0], b[1], b[2], b[3], output_transform 87 | ) 88 | # window = window.round_shape() 89 | 90 | cropped_img = crop_image(img, margin_ratio=crop_margin_ratio) 91 | # cropped_img = img.copy() 92 | 93 | for b in range(src_count): 94 | dst.write(cropped_img[:, :, b], b + 1, window=window) 95 | 96 | 97 | if __name__ == "__main__": 98 | import sys 99 | 100 | merge(sys.argv[1], sys.argv[2]) 101 | -------------------------------------------------------------------------------- /unetseg/predict.py: -------------------------------------------------------------------------------- 1 | import os 2 | import warnings 3 | from dataclasses import dataclass,field 4 | from glob import glob 5 | from typing import List 6 | 7 | import numpy as np 8 | import rasterio 9 | from sklearn.preprocessing import minmax_scale 10 | from tqdm import tqdm 11 | 12 | from unetseg.train import build_model_unet, build_model_unetplusplus 13 | from unetseg.utils import grouper, resize 14 | 15 | warnings.filterwarnings("ignore", category=UserWarning, module="skimage") 16 | 17 | 18 | @dataclass 19 | class PredictConfig: 20 | images_path: str 21 | results_path: str = "." 22 | batch_size: int = 32 23 | model_architecture: str = "unet" 24 | model_path: str = "unet.h5" 25 | height: int = 320 26 | width: int = 320 27 | n_channels: int = 3 28 | n_classes: int = 1 29 | class_weights: List[float] = field(default_factory=list) 30 | 31 | 32 | 33 | def predict(cfg: PredictConfig): 34 | """ 35 | Performs inference based on a configuration object 36 | 37 | Parameters 38 | ---------- 39 | cfg : PredictConfig 40 | Configuration object 41 | 42 | """ 43 | pat = os.path.join(cfg.images_path, "images/*.tif") 44 | predict_ids = glob(pat) 45 | print(f"Total images to predict ({pat}):", len(predict_ids)) 46 | 47 | os.makedirs(cfg.results_path, exist_ok=True) 48 | 49 | # Skip already existing files 50 | predict_ids = [ 51 | p 52 | for p in predict_ids 53 | if not os.path.exists(os.path.join(cfg.results_path, os.path.basename(p))) 54 | ] 55 | print("After skipping existing results:", len(predict_ids)) 56 | 57 | # Load model 58 | # FIXME: Find a better way to load model (.load_model() did not work because 59 | # of the weighted_binary_crossentropy function). 60 | # build_model() only expects cfg to have: width, height, n_channels, n_classes 61 | 62 | if cfg.model_architecture == "unet": 63 | model = build_model_unet(cfg) 64 | # print(model.summary()) 65 | elif cfg.model_architecture == "unetplusplus": 66 | model = build_model_unetplusplus(cfg) 67 | # print(model.summary()) 68 | else: 69 | print("no model architecture was set so default UNet model will be use") 70 | model = build_model_unet(cfg) 71 | # print(model.summary()) 72 | 73 | model.load_weights(cfg.model_path) 74 | 75 | # Predict over each batch of images 76 | groups = list(grouper(predict_ids, cfg.batch_size)) 77 | for mini_group in tqdm(groups): 78 | mini_group = [g for g in mini_group if g] 79 | 80 | X_predict = [] 81 | X_profile = [] 82 | 83 | for i, img_path in enumerate(mini_group): 84 | with rasterio.open(img_path) as src: 85 | img_ = np.dstack([src.read(b) for b in range(1, cfg.n_channels + 1)]) 86 | profile_ = src.profile.copy() 87 | img_ = minmax_scale(img_.ravel(), feature_range=(0, 255)).reshape( 88 | img_.shape 89 | ) 90 | img_ = resize(img_, (cfg.height, cfg.width)) 91 | img_ = img_.reshape(cfg.height, cfg.width, cfg.n_channels) 92 | X_predict.append(img_) 93 | X_profile.append(profile_) 94 | 95 | # Predict batch 96 | pred = model.predict(np.array(X_predict)) 97 | preds_test_ = pred # > 0.05 98 | 99 | preds_test_scaled_ = minmax_scale( 100 | preds_test_.ravel(), feature_range=(1, 255) 101 | ).reshape(preds_test_.shape) 102 | 103 | for i, img_path in enumerate(mini_group): 104 | profile_ = X_profile[i] 105 | profile_.update(count=cfg.n_classes, dtype=np.uint8) 106 | 107 | out_height, out_width = profile_["height"], profile_["width"] 108 | 109 | filename = os.path.basename(img_path) 110 | with rasterio.open( 111 | os.path.join(cfg.results_path, filename), "w", **profile_ 112 | ) as dst: 113 | 114 | img = resize(preds_test_scaled_[i], (out_height, out_width)) 115 | img = img.astype(np.uint8).reshape( 116 | (out_height, out_width, cfg.n_classes) 117 | ) 118 | for b in range(cfg.n_classes): 119 | dst.write(img[:, :, b], b + 1) 120 | 121 | print("Done!") 122 | -------------------------------------------------------------------------------- /unetseg/train.py: -------------------------------------------------------------------------------- 1 | import math 2 | import os 3 | import random 4 | import warnings 5 | from dataclasses import dataclass,field 6 | from glob import glob 7 | from typing import List, Tuple 8 | from datetime import datetime 9 | import albumentations as A 10 | import numpy as np 11 | import rasterio 12 | import tensorflow as tf 13 | from sklearn.preprocessing import minmax_scale 14 | from tensorflow.compat.v1.keras import backend as K 15 | from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, TensorBoard,CSVLogger 16 | from tensorflow.keras.layers import ( 17 | BatchNormalization, 18 | Conv2D, 19 | Conv2DTranspose, 20 | Dropout, 21 | Input, 22 | LeakyReLU, 23 | MaxPooling2D, 24 | UpSampling2D, 25 | concatenate, 26 | ) 27 | from tensorflow.keras.models import Model 28 | 29 | from unetseg.utils import resize 30 | 31 | warnings.filterwarnings("ignore", category=UserWarning, module="skimage") 32 | 33 | 34 | @dataclass 35 | class TrainConfig: 36 | images_path: str 37 | masks_path: str 38 | width: int = 200 39 | height: int = 200 40 | n_channels: int = 3 41 | n_classes: int = 1 42 | apply_image_augmentation: bool = True 43 | model_path: str = "unet.h5" 44 | model_architecture: str = "unet" 45 | validation_split: float = 0.1 46 | test_split: float = 0.1 47 | epochs: int = 15 48 | steps_per_epoch: int = 2000 49 | early_stopping_patience: int = 3 50 | batch_size: int = 32 51 | seed: int = None 52 | evaluate: bool = True 53 | class_weights: List[float] = field(default_factory=list) 54 | 55 | 56 | def build_model_unetplusplus(cfg: TrainConfig) -> Model: 57 | """ 58 | Builds a U-Net++ model. 59 | 60 | Parameters 61 | ---------- 62 | cfg : TrainConfig 63 | Training configuration. 64 | 65 | Returns 66 | ------- 67 | Model 68 | The U-Net++ model. 69 | 70 | """ 71 | # Classes are equally balanced by default 72 | if not cfg.class_weights: 73 | cfg.class_weights = [0.5 for _ in range(cfg.n_classes)] 74 | 75 | # growth_factor = 2 76 | # droprate = 0.25 77 | number_of_filters = 2 78 | # upconv = True 79 | # batch_size = cfg.batch_size 80 | 81 | def conv2d(filters: int): 82 | return Conv2D(filters=filters, kernel_size=(3, 3), padding="same") 83 | 84 | def conv2dtranspose(filters: int): 85 | return Conv2DTranspose( 86 | filters=filters, kernel_size=(2, 2), strides=(2, 2), padding="same" 87 | ) 88 | 89 | model_input = Input((cfg.height, cfg.width, cfg.n_channels)) 90 | x00 = conv2d(filters=int(16 * number_of_filters))(model_input) 91 | x00 = BatchNormalization()(x00) 92 | x00 = LeakyReLU(0.01)(x00) 93 | x00 = Dropout(0.2)(x00) 94 | x00 = conv2d(filters=int(16 * number_of_filters))(x00) 95 | x00 = BatchNormalization()(x00) 96 | x00 = LeakyReLU(0.01)(x00) 97 | x00 = Dropout(0.2)(x00) 98 | p0 = MaxPooling2D(pool_size=(2, 2))(x00) 99 | 100 | x10 = conv2d(filters=int(32 * number_of_filters))(p0) 101 | x10 = BatchNormalization()(x10) 102 | x10 = LeakyReLU(0.01)(x10) 103 | x10 = Dropout(0.2)(x10) 104 | x10 = conv2d(filters=int(32 * number_of_filters))(x10) 105 | x10 = BatchNormalization()(x10) 106 | x10 = LeakyReLU(0.01)(x10) 107 | x10 = Dropout(0.2)(x10) 108 | p1 = MaxPooling2D(pool_size=(2, 2))(x10) 109 | 110 | x01 = conv2dtranspose(int(16 * number_of_filters))(x10) 111 | x01 = concatenate([x00, x01]) 112 | x01 = conv2d(filters=int(16 * number_of_filters))(x01) 113 | x01 = BatchNormalization()(x01) 114 | x01 = LeakyReLU(0.01)(x01) 115 | x01 = conv2d(filters=int(16 * number_of_filters))(x01) 116 | x01 = BatchNormalization()(x01) 117 | x01 = LeakyReLU(0.01)(x01) 118 | x01 = Dropout(0.2)(x01) 119 | 120 | x20 = conv2d(filters=int(64 * number_of_filters))(p1) 121 | x20 = BatchNormalization()(x20) 122 | x20 = LeakyReLU(0.01)(x20) 123 | x20 = Dropout(0.2)(x20) 124 | x20 = conv2d(filters=int(64 * number_of_filters))(x20) 125 | x20 = BatchNormalization()(x20) 126 | x20 = LeakyReLU(0.01)(x20) 127 | x20 = Dropout(0.2)(x20) 128 | p2 = MaxPooling2D(pool_size=(2, 2))(x20) 129 | 130 | x11 = conv2dtranspose(int(16 * number_of_filters))(x20) 131 | x11 = concatenate([x10, x11]) 132 | x11 = conv2d(filters=int(16 * number_of_filters))(x11) 133 | x11 = BatchNormalization()(x11) 134 | x11 = LeakyReLU(0.01)(x11) 135 | x11 = conv2d(filters=int(16 * number_of_filters))(x11) 136 | x11 = BatchNormalization()(x11) 137 | x11 = LeakyReLU(0.01)(x11) 138 | x11 = Dropout(0.2)(x11) 139 | 140 | x02 = conv2dtranspose(int(16 * number_of_filters))(x11) 141 | x02 = concatenate([x00, x01, x02]) 142 | x02 = conv2d(filters=int(16 * number_of_filters))(x02) 143 | x02 = BatchNormalization()(x02) 144 | x02 = LeakyReLU(0.01)(x02) 145 | x02 = conv2d(filters=int(16 * number_of_filters))(x02) 146 | x02 = BatchNormalization()(x02) 147 | x02 = LeakyReLU(0.01)(x02) 148 | x02 = Dropout(0.2)(x02) 149 | 150 | x30 = conv2d(filters=int(128 * number_of_filters))(p2) 151 | x30 = BatchNormalization()(x30) 152 | x30 = LeakyReLU(0.01)(x30) 153 | x30 = Dropout(0.2)(x30) 154 | x30 = conv2d(filters=int(128 * number_of_filters))(x30) 155 | x30 = BatchNormalization()(x30) 156 | x30 = LeakyReLU(0.01)(x30) 157 | x30 = Dropout(0.2)(x30) 158 | p3 = MaxPooling2D(pool_size=(2, 2))(x30) 159 | 160 | x21 = conv2dtranspose(int(16 * number_of_filters))(x30) 161 | x21 = concatenate([x20, x21]) 162 | x21 = conv2d(filters=int(16 * number_of_filters))(x21) 163 | x21 = BatchNormalization()(x21) 164 | x21 = LeakyReLU(0.01)(x21) 165 | x21 = conv2d(filters=int(16 * number_of_filters))(x21) 166 | x21 = BatchNormalization()(x21) 167 | x21 = LeakyReLU(0.01)(x21) 168 | x21 = Dropout(0.2)(x21) 169 | 170 | x12 = conv2dtranspose(int(16 * number_of_filters))(x21) 171 | x12 = concatenate([x10, x11, x12]) 172 | x12 = conv2d(filters=int(16 * number_of_filters))(x12) 173 | x12 = BatchNormalization()(x12) 174 | x12 = LeakyReLU(0.01)(x12) 175 | x12 = conv2d(filters=int(16 * number_of_filters))(x12) 176 | x12 = BatchNormalization()(x12) 177 | x12 = LeakyReLU(0.01)(x12) 178 | x12 = Dropout(0.2)(x12) 179 | 180 | x03 = conv2dtranspose(int(16 * number_of_filters))(x12) 181 | x03 = concatenate([x00, x01, x02, x03]) 182 | x03 = conv2d(filters=int(16 * number_of_filters))(x03) 183 | x03 = BatchNormalization()(x03) 184 | x03 = LeakyReLU(0.01)(x03) 185 | x03 = conv2d(filters=int(16 * number_of_filters))(x03) 186 | x03 = BatchNormalization()(x03) 187 | x03 = LeakyReLU(0.01)(x03) 188 | x03 = Dropout(0.2)(x03) 189 | 190 | m = conv2d(filters=int(256 * number_of_filters))(p3) 191 | m = BatchNormalization()(m) 192 | m = LeakyReLU(0.01)(m) 193 | m = conv2d(filters=int(256 * number_of_filters))(m) 194 | m = BatchNormalization()(m) 195 | m = LeakyReLU(0.01)(m) 196 | m = Dropout(0.2)(m) 197 | 198 | x31 = conv2dtranspose(int(128 * number_of_filters))(m) 199 | x31 = concatenate([x31, x30]) 200 | x31 = conv2d(filters=int(128 * number_of_filters))(x31) 201 | x31 = BatchNormalization()(x31) 202 | x31 = LeakyReLU(0.01)(x31) 203 | x31 = conv2d(filters=int(128 * number_of_filters))(x31) 204 | x31 = BatchNormalization()(x31) 205 | x31 = LeakyReLU(0.01)(x31) 206 | x31 = Dropout(0.2)(x31) 207 | 208 | x22 = conv2dtranspose(int(64 * number_of_filters))(x31) 209 | x22 = concatenate([x22, x20, x21]) 210 | x22 = conv2d(filters=int(64 * number_of_filters))(x22) 211 | x22 = BatchNormalization()(x22) 212 | x22 = LeakyReLU(0.01)(x22) 213 | x22 = conv2d(filters=int(64 * number_of_filters))(x22) 214 | x22 = BatchNormalization()(x22) 215 | x22 = LeakyReLU(0.01)(x22) 216 | x22 = Dropout(0.2)(x22) 217 | 218 | x13 = conv2dtranspose(int(32 * number_of_filters))(x22) 219 | x13 = concatenate([x13, x10, x11, x12]) 220 | x13 = conv2d(filters=int(32 * number_of_filters))(x13) 221 | x13 = BatchNormalization()(x13) 222 | x13 = LeakyReLU(0.01)(x13) 223 | x13 = conv2d(filters=int(32 * number_of_filters))(x13) 224 | x13 = BatchNormalization()(x13) 225 | x13 = LeakyReLU(0.01)(x13) 226 | x13 = Dropout(0.2)(x13) 227 | 228 | x04 = conv2dtranspose(int(16 * number_of_filters))(x13) 229 | x04 = concatenate([x04, x00, x01, x02, x03], axis=3) 230 | x04 = conv2d(filters=int(16 * number_of_filters))(x04) 231 | x04 = BatchNormalization()(x04) 232 | x04 = LeakyReLU(0.01)(x04) 233 | x04 = conv2d(filters=int(16 * number_of_filters))(x04) 234 | x04 = BatchNormalization()(x04) 235 | x04 = LeakyReLU(0.01)(x04) 236 | x04 = Dropout(0.2)(x04) 237 | 238 | output = Conv2D(cfg.n_classes, kernel_size=(1, 1), activation="sigmoid")(x04) 239 | 240 | model = Model(inputs=[model_input], outputs=[output]) 241 | 242 | def weighted_binary_crossentropy(y_true, y_pred): 243 | class_loglosses = K.mean(K.binary_crossentropy(y_true, y_pred), axis=[0, 1, 2]) 244 | return K.sum(class_loglosses * K.constant(cfg.class_weights)) 245 | 246 | model.compile( 247 | optimizer="adam", 248 | # optimizer=Adam(),#tf.optimizers.Adam(lr=0.0005), 249 | loss=weighted_binary_crossentropy, 250 | metrics=[tf.keras.metrics.MeanIoU(num_classes=cfg.n_classes + 1)], 251 | ) 252 | 253 | return model 254 | 255 | 256 | def build_model_unet(cfg: TrainConfig) -> Model: 257 | """ 258 | Build U-Net model class. 259 | 260 | Parameters 261 | ---------- 262 | cfg : TrainConfig 263 | Configuration for training. 264 | 265 | Returns 266 | ------- 267 | Model 268 | U-Net model class. 269 | 270 | """ 271 | # Classes are equally balanced by default 272 | if not cfg.class_weights: 273 | cfg.class_weights = [0.5 for _ in range(cfg.n_classes)] 274 | 275 | growth_factor = 2 276 | n_filters_start = 32 277 | droprate = 0.25 278 | n_filters = n_filters_start 279 | upconv = True 280 | inputs = Input((cfg.height, cfg.width, cfg.n_channels)) 281 | # inputs = BatchNormalization()(inputs) 282 | conv1 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(inputs) 283 | conv1 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(conv1) 284 | pool1 = MaxPooling2D(pool_size=(2, 2))(conv1) 285 | # pool1 = Dropout(droprate)(pool1) 286 | 287 | n_filters *= growth_factor 288 | pool1 = BatchNormalization()(pool1) 289 | conv2 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(pool1) 290 | conv2 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(conv2) 291 | pool2 = MaxPooling2D(pool_size=(2, 2))(conv2) 292 | pool2 = Dropout(droprate)(pool2) 293 | 294 | n_filters *= growth_factor 295 | pool2 = BatchNormalization()(pool2) 296 | conv3 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(pool2) 297 | conv3 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(conv3) 298 | pool3 = MaxPooling2D(pool_size=(2, 2))(conv3) 299 | pool3 = Dropout(droprate)(pool3) 300 | 301 | n_filters *= growth_factor 302 | pool3 = BatchNormalization()(pool3) 303 | conv4_0 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(pool3) 304 | conv4_0 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(conv4_0) 305 | pool4_1 = MaxPooling2D(pool_size=(2, 2))(conv4_0) 306 | pool4_1 = Dropout(droprate)(pool4_1) 307 | 308 | n_filters *= growth_factor 309 | pool4_1 = BatchNormalization()(pool4_1) 310 | conv4_1 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(pool4_1) 311 | conv4_1 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(conv4_1) 312 | pool4_2 = MaxPooling2D(pool_size=(2, 2))(conv4_1) 313 | pool4_2 = Dropout(droprate)(pool4_2) 314 | 315 | n_filters *= growth_factor 316 | conv5 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(pool4_2) 317 | conv5 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(conv5) 318 | 319 | n_filters //= growth_factor 320 | if upconv: 321 | up6_1 = concatenate( 322 | [ 323 | Conv2DTranspose(n_filters, (2, 2), strides=(2, 2), padding="same")( 324 | conv5 325 | ), 326 | conv4_1, 327 | ] 328 | ) 329 | else: 330 | up6_1 = concatenate([UpSampling2D(size=(2, 2))(conv5), conv4_1]) 331 | up6_1 = BatchNormalization()(up6_1) 332 | conv6_1 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(up6_1) 333 | conv6_1 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(conv6_1) 334 | conv6_1 = Dropout(droprate)(conv6_1) 335 | 336 | n_filters //= growth_factor 337 | if upconv: 338 | up6_2 = concatenate( 339 | [ 340 | Conv2DTranspose(n_filters, (2, 2), strides=(2, 2), padding="same")( 341 | conv6_1 342 | ), 343 | conv4_0, 344 | ] 345 | ) 346 | else: 347 | up6_2 = concatenate([UpSampling2D(size=(2, 2))(conv6_1), conv4_0]) 348 | up6_2 = BatchNormalization()(up6_2) 349 | conv6_2 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(up6_2) 350 | conv6_2 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(conv6_2) 351 | conv6_2 = Dropout(droprate)(conv6_2) 352 | 353 | n_filters //= growth_factor 354 | if upconv: 355 | up7 = concatenate( 356 | [ 357 | Conv2DTranspose(n_filters, (2, 2), strides=(2, 2), padding="same")( 358 | conv6_2 359 | ), 360 | conv3, 361 | ] 362 | ) 363 | else: 364 | up7 = concatenate([UpSampling2D(size=(2, 2))(conv6_2), conv3]) 365 | up7 = BatchNormalization()(up7) 366 | conv7 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(up7) 367 | conv7 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(conv7) 368 | conv7 = Dropout(droprate)(conv7) 369 | 370 | n_filters //= growth_factor 371 | if upconv: 372 | up8 = concatenate( 373 | [ 374 | Conv2DTranspose(n_filters, (2, 2), strides=(2, 2), padding="same")( 375 | conv7 376 | ), 377 | conv2, 378 | ] 379 | ) 380 | else: 381 | up8 = concatenate([UpSampling2D(size=(2, 2))(conv7), conv2]) 382 | up8 = BatchNormalization()(up8) 383 | conv8 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(up8) 384 | conv8 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(conv8) 385 | conv8 = Dropout(droprate)(conv8) 386 | 387 | n_filters //= growth_factor 388 | if upconv: 389 | up9 = concatenate( 390 | [ 391 | Conv2DTranspose(n_filters, (2, 2), strides=(2, 2), padding="same")( 392 | conv8 393 | ), 394 | conv1, 395 | ] 396 | ) 397 | else: 398 | up9 = concatenate([UpSampling2D(size=(2, 2))(conv8), conv1]) 399 | conv9 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(up9) 400 | conv9 = Conv2D(n_filters, (3, 3), activation="relu", padding="same")(conv9) 401 | 402 | conv10 = Conv2D(cfg.n_classes, (1, 1), activation="sigmoid")(conv9) 403 | 404 | model = Model(inputs=[inputs], outputs=[conv10]) 405 | 406 | def weighted_binary_crossentropy(y_true, y_pred): 407 | class_loglosses = K.mean(K.binary_crossentropy(y_true, y_pred), axis=[0, 1, 2]) 408 | return K.sum(class_loglosses * K.constant(cfg.class_weights)) 409 | 410 | model.compile( 411 | optimizer="adam", 412 | # optimizer=Adam(),#tf.optimizers.Adam(), 413 | loss=weighted_binary_crossentropy, 414 | metrics=[tf.keras.metrics.MeanIoU(num_classes=cfg.n_classes + 1)], 415 | ) 416 | 417 | return model 418 | 419 | 420 | def preprocess_input( 421 | image: np.ndarray, mask: np.ndarray, *, config: TrainConfig 422 | ) -> Tuple[np.ndarray, np.ndarray]: 423 | """ 424 | Preprocess input image and masks. 425 | 426 | Parameters 427 | ---------- 428 | image : np.ndarray 429 | Input image. 430 | mask : np.ndarray 431 | Input mask. 432 | config : TrainConfig 433 | Training configuration. 434 | 435 | Returns 436 | ------- 437 | Tuple[np.ndarray, np.ndarray] 438 | Preprocessed image and mask. 439 | 440 | """ 441 | # Scale image to 0-255 range 442 | image_ = minmax_scale(image.ravel(), feature_range=(0, 255)).reshape(image.shape) 443 | # Scale to 0-1 by dividing by 255 (we assume that mask has true values 444 | # filled with 255, and false values as 0). 445 | mask_ = mask / 255 446 | size = (config.height, config.width) 447 | 448 | # Resize image and mask 449 | image_ = resize(image_, size) 450 | mask_ = resize(mask_, size) 451 | 452 | if config.apply_image_augmentation: 453 | # Add extra augmentations to image and mask 454 | aug_pipeline = A.Compose( 455 | [ 456 | A.RandomRotate90(p=0.5), 457 | A.HorizontalFlip(p=0.5), 458 | A.RandomBrightnessContrast(p=0.2), 459 | ] 460 | ) 461 | res = aug_pipeline(image=image_.astype(np.uint8), mask=mask_) 462 | image_, mask_ = res["image"], res["mask"] 463 | 464 | # In case mask is binary (1 class), 465 | # make sure mask has shape (H, W, 1) and not (H, W). 466 | image_ = image_.reshape(image_.shape[0], image_.shape[1], config.n_channels) 467 | mask_ = mask_.reshape(mask_.shape[0], mask_.shape[1], config.n_classes) 468 | 469 | return image_, mask_ 470 | 471 | 472 | def get_raster(image_path: str, n_channels: int = None) -> np.ndarray: 473 | """ 474 | Loads a raster image from a file. 475 | 476 | Parameters 477 | ---------- 478 | image_path : str 479 | Path to the image file. 480 | n_channels : int, optional 481 | Number of channels in the image. If not specified, the number of channels 482 | is inferred from the image file. 483 | 484 | Returns 485 | ------- 486 | np.ndarray 487 | The loaded image. 488 | 489 | """ 490 | with rasterio.open(image_path) as src: 491 | if not n_channels: 492 | n_channels = src.count 493 | return np.dstack([src.read(b) for b in range(1, n_channels + 1)]) 494 | 495 | 496 | def get_mask_raster( 497 | image_path: str, n_channels: int = None, *, mask_dir: str 498 | ) -> np.ndarray: 499 | """ 500 | Get respective mask raster from image path. 501 | 502 | Parameters 503 | ---------- 504 | image_path : str 505 | Path to image. 506 | n_channels : int, optional 507 | Number of channels in image. The default is None. 508 | mask_dir : str, optional 509 | Path to mask directory. The default is None. 510 | 511 | Returns 512 | ------- 513 | np.ndarray 514 | Mask image. 515 | 516 | """ 517 | basename = os.path.basename(image_path) 518 | mask_path = os.path.join(mask_dir, basename) 519 | with rasterio.open(mask_path) as src: 520 | if not n_channels: 521 | n_channels = src.count 522 | return np.dstack([src.read(b) for b in range(1, n_channels + 1)]) 523 | 524 | 525 | def build_data_generator(image_files: List[str], *, config: TrainConfig, mask_dir: str): 526 | """ 527 | Build data generator based on a list of images and directory of binary masks. 528 | 529 | Parameters 530 | ---------- 531 | image_files : List[str] 532 | List of paths to images. 533 | config : TrainConfig 534 | Configuration object. 535 | mask_dir : str 536 | Path to directory with binary masks. 537 | 538 | Yields 539 | ------ 540 | tuple 541 | Tuple of image and mask batch. 542 | 543 | """ 544 | if not image_files: 545 | raise RuntimeError("image_files is empty") 546 | 547 | while True: 548 | # Select files (paths/indices) for the batch 549 | batch_paths = np.random.choice(a=image_files, size=config.batch_size) 550 | batch_input = [] 551 | batch_output = [] 552 | 553 | # Read in each input, perform preprocessing and get labels 554 | for input_path in batch_paths: 555 | input = get_raster(input_path, n_channels=config.n_channels) 556 | mask = get_mask_raster( 557 | input_path, mask_dir=mask_dir, n_channels=config.n_classes 558 | ) 559 | 560 | input, mask = preprocess_input(image=input, mask=mask, config=config) 561 | 562 | if not np.any(np.isnan(input)): 563 | if not np.any(np.isnan(mask)): 564 | 565 | batch_input.append(input) 566 | batch_output.append(mask) 567 | 568 | # Return a tuple of (input, output) to feed the network 569 | batch_x = np.array(batch_input) 570 | batch_y = np.array(batch_output) 571 | 572 | yield batch_x, batch_y 573 | 574 | 575 | def train(cfg: TrainConfig): 576 | """ 577 | Performs training and evaluation of the model based on a configuration object. 578 | 579 | Parameters 580 | ---------- 581 | cfg : TrainConfig 582 | Configuration object containing all the necessary parameters for training. 583 | 584 | """ 585 | #Save date and time 586 | # datetime object containing current date and time 587 | now = datetime.now() 588 | dt_string = now.strftime("Date_%d-%m-%Y_Time_%H-%M-%S") 589 | 590 | 591 | 592 | if cfg.seed: 593 | random.seed = cfg.seed 594 | np.random.seed = cfg.seed 595 | 596 | if cfg.model_architecture == "unet": 597 | model = build_model_unet(cfg) 598 | print(model.summary()) 599 | elif cfg.model_architecture == "unetplusplus": 600 | model = build_model_unetplusplus(cfg) 601 | print(model.summary()) 602 | else: 603 | print("no model architecture was set so default UNet model will be use") 604 | model = build_model_unet(cfg) 605 | print(model.summary()) 606 | 607 | all_images = glob(os.path.join(cfg.images_path, "images", "*.tif")) 608 | print("All images:", len(all_images)) 609 | 610 | # Split dataset by shuffling and taking the first N elements for validation, 611 | # and the rest for training. 612 | np.random.shuffle(all_images) 613 | 614 | n_test = round(cfg.test_split * len(all_images)) 615 | n_val = round(cfg.validation_split * (len(all_images) - n_test)) 616 | 617 | test_images, all_train_images = all_images[:n_test], all_images[n_test:] 618 | val_images, train_images = all_train_images[:n_val], all_train_images[n_val:] 619 | 620 | print("Num. training images:", len(train_images)) 621 | print("Num. validation images:", len(val_images)) 622 | print("Num. test images:", len(test_images)) 623 | 624 | if not train_images: 625 | raise RuntimeError("train_images is empty") 626 | if not val_images: 627 | raise RuntimeError("val_images is empty") 628 | if not test_images: 629 | raise RuntimeError("test_images is empty") 630 | 631 | mask_dir = cfg.masks_path or os.path.join(cfg.images_path, "extent") 632 | train_generator = build_data_generator(train_images, config=cfg, mask_dir=mask_dir) 633 | val_generator = build_data_generator(val_images, config=cfg, mask_dir=mask_dir) 634 | test_generator = build_data_generator(test_images, config=cfg, mask_dir=mask_dir) 635 | 636 | # Make sure weights dir exist 637 | os.makedirs(os.path.dirname(cfg.model_path), exist_ok=True) 638 | 639 | print("Compile and fit the UNet model") 640 | early_stopping = EarlyStopping(patience=cfg.early_stopping_patience, verbose=1) 641 | checkpoint = ModelCheckpoint(cfg.model_path, verbose=1, save_best_only=True) 642 | 643 | head, tail = os.path.split(cfg.model_path) 644 | log_file = tail[:-3] 645 | print(log_file) 646 | os.makedirs('./../logs', exist_ok=True) 647 | log_csv = CSVLogger ( f'./../logs/my_logs.csv',separator = ',',append=False) 648 | tensorboard = TensorBoard(log_dir = f'./../logs/{log_file}_{dt_string}') 649 | # reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2, 650 | # patience=5, min_lr=0.001) 651 | 652 | results = model.fit( 653 | train_generator, 654 | epochs=cfg.epochs, 655 | steps_per_epoch=cfg.steps_per_epoch, 656 | validation_data=val_generator, 657 | validation_steps=round(cfg.steps_per_epoch * cfg.validation_split), 658 | callbacks=[early_stopping, checkpoint,tensorboard,log_csv], 659 | ) 660 | 661 | # Save model 662 | model.save(cfg.model_path) 663 | 664 | # Evaluate model on test set 665 | if cfg.evaluate: 666 | steps = math.ceil(len(test_images) / cfg.batch_size) 667 | scores = model.evaluate(test_generator, steps=steps) 668 | loss, mean_iou = scores 669 | print("*** Final metrics ***") 670 | print("Loss:", loss) 671 | print("Mean IoU:", mean_iou) 672 | 673 | return results 674 | -------------------------------------------------------------------------------- /unetseg/utils.py: -------------------------------------------------------------------------------- 1 | from itertools import zip_longest 2 | 3 | import cv2 4 | import skimage.transform 5 | import tensorflow as tf 6 | from tensorflow.keras.models import Model 7 | 8 | 9 | def grouper(iterable, n, fillvalue=None): 10 | """Collect data into fixed-length chunks or blocks""" 11 | # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx" 12 | args = [iter(iterable)] * n 13 | return zip_longest(*args, fillvalue=fillvalue) 14 | 15 | 16 | def load_model(model_path: str) -> Model: 17 | """Load model from ``model_path``""" 18 | return tf.keras.models.load_model(model_path) 19 | 20 | 21 | def resize(image, size): 22 | """Resize multiband image to an image of size (h, w)""" 23 | n_channels = image.shape[2] 24 | if n_channels >= 4: 25 | return skimage.transform.resize( 26 | image, size, mode="constant", preserve_range=True 27 | ) 28 | else: 29 | return cv2.resize(image, size, interpolation=cv2.INTER_AREA) 30 | --------------------------------------------------------------------------------