├── .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 | [](https://pypi.python.org/pypi/unetseg)
6 | [](https://github.com/dymaxionlabs/unetseg/actions/workflows/main.yml)
7 | [](https://codecov.io/gh/dymaxionlabs/unetseg)
8 | [](https://sonarcloud.io/summary/new_code?id=dymaxionlabs_unetseg)
9 | [](https://github.com/dymaxionlabs/unetseg/issues)
10 | [](https://github.com/dymaxionlabs/unetseg/blob/main/LICENSE.txt)
11 | [](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 |
--------------------------------------------------------------------------------