├── .bumpversion.cfg
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ └── python-publish.yml
├── .gitignore
├── .vscode
├── launch.json
└── settings.json
├── LICENSE
├── MANIFEST.in
├── README.md
├── docs
├── .nojekyll
├── .vscode
│ └── settings.json
├── Makefile
├── _images
│ ├── abstract.png
│ ├── aoi_pn.png
│ ├── border.png
│ ├── centroid.png
│ ├── ch3_io_res_demo_shapefile_13_0.png
│ ├── ch3_io_res_demo_shapefile_9_1.png
│ ├── ch4_adv_custom_index_15_0.png
│ ├── ch4_adv_custom_index_20_1.png
│ ├── ch4_adv_custom_index_6_1.png
│ ├── ch4_adv_seasons_11_1.png
│ ├── ch4_adv_seasons_13_1.png
│ ├── ch4_adv_seasons_15_0.png
│ ├── ch4_adv_seasons_16_1.png
│ ├── ch4_adv_seasons_22_0.png
│ ├── ck_out.png
│ ├── ct_adj.png
│ ├── ct_maj.png
│ ├── ct_pn.png
│ ├── demo_image.png
│ ├── demo_map.png
│ ├── demo_option.png
│ ├── fill.png
│ ├── geo.png
│ ├── h5.png
│ ├── input.png
│ ├── inputs.png
│ ├── inspect.png
│ ├── km_alg.png
│ ├── km_dis.png
│ ├── km_k.png
│ ├── km_misc.png
│ ├── km_noise.png
│ ├── km_pn.png
│ ├── km_shade.png
│ ├── label.png
│ ├── ld_dnd.gif
│ ├── ld_pn.png
│ ├── load.png
│ ├── npy_plot.png
│ ├── results.png
│ ├── s1_shp.png
│ ├── seg.png
│ ├── seg_fix.png
│ ├── seg_grid.png
│ ├── seg_out.png
│ ├── seg_pn.png
│ ├── shapefiles.png
│ └── unck_out.png
├── _sources
│ ├── ch1_started
│ │ ├── firsttime.rst.txt
│ │ └── installation.rst.txt
│ ├── ch2_interface
│ │ ├── aoi.rst.txt
│ │ ├── centroids.rst.txt
│ │ ├── kmeans.rst.txt
│ │ ├── load.rst.txt
│ │ └── segmentation.rst.txt
│ ├── ch3_io
│ │ ├── inputs.rst.txt
│ │ ├── outputs.rst.txt
│ │ └── res
│ │ │ └── demo_shapefile.ipynb.txt
│ ├── ch4_adv
│ │ ├── arbitrary.rst.txt
│ │ ├── custom_index.ipynb.txt
│ │ ├── dl.rst.txt
│ │ ├── qgis.rst.txt
│ │ └── seasons.ipynb.txt
│ └── index.rst.txt
├── _static
│ ├── GRID_banner.png
│ ├── _sphinx_javascript_frameworks_compat.js
│ ├── aoi_corner.mp4
│ ├── aoi_create.mp4
│ ├── aoi_entire.mp4
│ ├── aoi_new.mp4
│ ├── aoi_rotate.mp4
│ ├── aoi_side.mp4
│ ├── basic.css
│ ├── css
│ │ ├── badge_only.css
│ │ ├── fonts
│ │ │ ├── Roboto-Slab-Bold.woff
│ │ │ ├── Roboto-Slab-Bold.woff2
│ │ │ ├── Roboto-Slab-Regular.woff
│ │ │ ├── Roboto-Slab-Regular.woff2
│ │ │ ├── fontawesome-webfont.eot
│ │ │ ├── fontawesome-webfont.svg
│ │ │ ├── fontawesome-webfont.ttf
│ │ │ ├── fontawesome-webfont.woff
│ │ │ ├── fontawesome-webfont.woff2
│ │ │ ├── lato-bold-italic.woff
│ │ │ ├── lato-bold-italic.woff2
│ │ │ ├── lato-bold.woff
│ │ │ ├── lato-bold.woff2
│ │ │ ├── lato-normal-italic.woff
│ │ │ ├── lato-normal-italic.woff2
│ │ │ ├── lato-normal.woff
│ │ │ └── lato-normal.woff2
│ │ └── theme.css
│ ├── ct_min.mp4
│ ├── doctools.js
│ ├── documentation_options.js
│ ├── file.png
│ ├── google_analytics.js
│ ├── jquery-3.6.0.js
│ ├── jquery.js
│ ├── js
│ │ ├── badge_only.js
│ │ ├── html5shiv-printshiv.min.js
│ │ ├── html5shiv.min.js
│ │ └── theme.js
│ ├── language_data.js
│ ├── minus.png
│ ├── plus.png
│ ├── poi_bin.mp4
│ ├── poi_noise.mp4
│ ├── poi_refine.mp4
│ ├── poi_shad.mp4
│ ├── pygments.css
│ ├── searchtools.js
│ ├── seg_adj.mp4
│ ├── underscore-1.13.1.js
│ └── underscore.js
├── ch1_started
│ ├── firsttime.html
│ └── installation.html
├── ch2_interface
│ ├── aoi.html
│ ├── centroids.html
│ ├── kmeans.html
│ ├── load.html
│ └── segmentation.html
├── ch3_io
│ ├── inputs.html
│ ├── outputs.html
│ └── res
│ │ ├── demo_shapefile.html
│ │ └── demo_shapefile.ipynb
├── ch4_adv
│ ├── arbitrary.html
│ ├── custom_index.html
│ ├── custom_index.ipynb
│ ├── dl.html
│ ├── qgis.html
│ ├── seasons.html
│ └── seasons.ipynb
├── demo
│ ├── features.rst
│ └── main.rst
├── genindex.html
├── grid.bib
├── index.html
├── make.bat
├── objects.inv
├── search.html
└── searchindex.js
├── grid
├── __init__.py
├── __init__.pyc
├── __main__.py
├── archive
│ ├── 0611_shapefile.py
│ ├── 0615_zz_image.r
│ ├── CPU_Agent.py
│ ├── CPU_Field copy.py
│ ├── GPU_Anchor copy.py
│ ├── GPU_Output copy.py
│ ├── Misc.py
│ ├── archive.py
│ ├── grid2.py
│ ├── test.py
│ ├── test.r
│ ├── testAnchor.py
│ ├── testFindAngel.py
│ ├── testRecoverSize.py
│ ├── test_shapefile.py
│ └── thread.py
├── benchmark.py
├── benchmark.r
├── demo
│ └── seg_img.jpg
├── dir.py
├── gagent.py
├── gimage.py
├── gimage.pyc
├── gmap.py
├── grid.py
├── grid.pyc
├── gridGUI.py
├── gtest.py
├── gui
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-310.pyc
│ │ ├── __init__.cpython-36.pyc
│ │ ├── __init__.cpython-37.pyc
│ │ ├── __init__.cpython-39.pyc
│ │ ├── anchor.cpython-310.pyc
│ │ ├── anchor.cpython-36.pyc
│ │ ├── anchor.cpython-37.pyc
│ │ ├── anchor.cpython-39.pyc
│ │ ├── cropper.cpython-310.pyc
│ │ ├── cropper.cpython-36.pyc
│ │ ├── cropper.cpython-37.pyc
│ │ ├── cropper.cpython-39.pyc
│ │ ├── customQt.cpython-310.pyc
│ │ ├── customQt.cpython-36.pyc
│ │ ├── customQt.cpython-37.pyc
│ │ ├── customQt.cpython-39.pyc
│ │ ├── inputer.cpython-310.pyc
│ │ ├── inputer.cpython-36.pyc
│ │ ├── inputer.cpython-37.pyc
│ │ ├── inputer.cpython-39.pyc
│ │ ├── kmeaner.cpython-310.pyc
│ │ ├── kmeaner.cpython-36.pyc
│ │ ├── kmeaner.cpython-37.pyc
│ │ ├── kmeaner.cpython-39.pyc
│ │ ├── outputer.cpython-310.pyc
│ │ ├── outputer.cpython-36.pyc
│ │ ├── outputer.cpython-37.pyc
│ │ └── outputer.cpython-39.pyc
│ ├── anchor.py
│ ├── cropper.py
│ ├── customQt.py
│ ├── inputer.py
│ ├── kmeaner.py
│ └── outputer.py
├── guser.py
├── guser.pyc
├── io.py
├── io.pyc
├── lib.py
├── res
│ └── rotate.png
└── test
│ └── test_gui.py
├── requirements.txt
├── res
├── GRID_banner.png
├── GRID_logo2.png
└── abstract.png
└── setup.py
/.bumpversion.cfg:
--------------------------------------------------------------------------------
1 | [bumpversion]
2 | current_version = 1.3.13
3 | commit = True
4 | tag = True
5 |
6 | [bumpversion:file:setup.py]
7 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/workflows/python-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will upload a Python Package using Twine when a release is created
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3 |
4 | # This workflow uses actions that are not certified by GitHub.
5 | # They are provided by a third-party and are governed by
6 | # separate terms of service, privacy policy, and support
7 | # documentation.
8 |
9 | name: Upload Python Package
10 |
11 | on:
12 | push:
13 | tags:
14 | - '*'
15 |
16 | permissions:
17 | contents: read
18 |
19 | jobs:
20 | deploy:
21 |
22 | runs-on: ubuntu-latest
23 |
24 | steps:
25 | - uses: actions/checkout@v3
26 | - name: Set up Python
27 | uses: actions/setup-python@v3
28 | with:
29 | python-version: '3.x'
30 | - name: Install dependencies
31 | run: |
32 | python -m pip install --upgrade pip
33 | pip install build
34 | - name: Build package
35 | run: python -m build
36 | - name: Publish package
37 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
38 | with:
39 | user: __token__
40 | password: ${{ secrets.PYPI_UNIVERSAL_TOKEN }}
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.out
2 | *.log
3 | *.map
4 | *.idx
5 | *.xlsx
6 | *.roc
7 | *.pVal
8 | *.h5
9 | *.csv
10 | *.x
11 | *.y
12 | *.wt
13 | *.hdr
14 | *.raw
15 | *.pdf
16 | *.tif
17 | *.zip
18 | *.key
19 | *.ppt
20 | *.pptx
21 | *.Rprofile
22 | *.tidy
23 | *.spec
24 | *.dat
25 | *.pyc
26 | **/data/*
27 | docs/source/*
28 | env/*
29 | *.npy
30 | test/*
31 | .DS_Store
32 | build/*
33 | **/__pycache__/*
34 |
35 | publish.sh
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Python Console App",
9 | "type": "python",
10 | "request": "launch",
11 | "stopOnEntry": true,
12 | "program": "${file}",
13 | "externalConsole": true,
14 | "debugOptions": [
15 | "WaitOnAbnormalExit",
16 | "WaitOnNormalExit"
17 | ],
18 | "env": {},
19 | "envFile": "${workspaceRoot}/.env",
20 | "console": "integratedTerminal",
21 | "python": "${command:python.interpreterPath}"
22 | // "python": "/usr/local/bin/python3"
23 | // "python": "${workspaceRoot}"
24 | }
25 | ]
26 | }
27 |
28 | // ${workspaceRoot}
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.linting.enabled": true,
3 | "python.linting.pylintEnabled": false,
4 | "python.linting.flake8Enabled": true,
5 | "workbench.colorTheme": "Monokai Pro",
6 | "jupyter.jupyterServerType": "local",
7 | "jupyter.jupyterCommandLineArguments": []
8 | }
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include grid/demo/seg_img.jpg
2 | include grid/demo/seg_map.csv
3 | include grid/res/rotate.png
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [](https://pypi.org/project/photo-grid/)
4 | [](https://pypi.org/project/photo-grid/)
5 | [](https://pypi.org/project/photo-grid/)
6 | [](https://app.codacy.com/manual/Poissonfish/photo_grid/dashboard)
7 | [](https://github.com/Poissonfish/GRID/blob/master/LICENSE)
8 | [](https://github.com/Poissonfish/GRID/search?l=Python)
9 |
10 |
11 |
12 | ### [Software Page (zzlab.net)](https://zzlab.net/GRID)
13 |
14 | ### [User Manual](https://poissonfish.github.io/GRID/index.html)
15 |
16 | ## Get Started
17 | ### Installation (All users)
18 | ***Highly recommended install GRID in [Conda](https://poissonfish.github.io/GRID/ch1_started/installation.html) environment***
19 |
20 | ```bash
21 | conda create -n grid python==3.11
22 | conda install gdal
23 | conda install rasterio
24 | python -m pip install photo-grid
25 | ```
26 |
27 | ### Launch GRID
28 | Just type `GRID` (case-sensitive) in your terminal.
29 |
30 | ```GRID```
31 |
32 | or
33 | ```python -m grid```
34 |
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/.nojekyll
--------------------------------------------------------------------------------
/docs/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "restructuredtext.confPath": "${workspaceFolder}/source"
3 | }
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal 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 = source
9 | BUILDDIR = build
10 | PDF = GRID.pdf
11 |
12 | # Put it first so that "make" without argument is like "make help".
13 | help:
14 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
15 |
16 | .PHONY: help Makefile
17 |
18 | # Catch-all target: route all unknown targets to Sphinx using the new
19 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
20 | %: Makefile
21 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
22 |
--------------------------------------------------------------------------------
/docs/_images/abstract.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/abstract.png
--------------------------------------------------------------------------------
/docs/_images/aoi_pn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/aoi_pn.png
--------------------------------------------------------------------------------
/docs/_images/border.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/border.png
--------------------------------------------------------------------------------
/docs/_images/centroid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/centroid.png
--------------------------------------------------------------------------------
/docs/_images/ch3_io_res_demo_shapefile_13_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ch3_io_res_demo_shapefile_13_0.png
--------------------------------------------------------------------------------
/docs/_images/ch3_io_res_demo_shapefile_9_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ch3_io_res_demo_shapefile_9_1.png
--------------------------------------------------------------------------------
/docs/_images/ch4_adv_custom_index_15_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ch4_adv_custom_index_15_0.png
--------------------------------------------------------------------------------
/docs/_images/ch4_adv_custom_index_20_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ch4_adv_custom_index_20_1.png
--------------------------------------------------------------------------------
/docs/_images/ch4_adv_custom_index_6_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ch4_adv_custom_index_6_1.png
--------------------------------------------------------------------------------
/docs/_images/ch4_adv_seasons_11_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ch4_adv_seasons_11_1.png
--------------------------------------------------------------------------------
/docs/_images/ch4_adv_seasons_13_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ch4_adv_seasons_13_1.png
--------------------------------------------------------------------------------
/docs/_images/ch4_adv_seasons_15_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ch4_adv_seasons_15_0.png
--------------------------------------------------------------------------------
/docs/_images/ch4_adv_seasons_16_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ch4_adv_seasons_16_1.png
--------------------------------------------------------------------------------
/docs/_images/ch4_adv_seasons_22_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ch4_adv_seasons_22_0.png
--------------------------------------------------------------------------------
/docs/_images/ck_out.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ck_out.png
--------------------------------------------------------------------------------
/docs/_images/ct_adj.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ct_adj.png
--------------------------------------------------------------------------------
/docs/_images/ct_maj.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ct_maj.png
--------------------------------------------------------------------------------
/docs/_images/ct_pn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ct_pn.png
--------------------------------------------------------------------------------
/docs/_images/demo_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/demo_image.png
--------------------------------------------------------------------------------
/docs/_images/demo_map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/demo_map.png
--------------------------------------------------------------------------------
/docs/_images/demo_option.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/demo_option.png
--------------------------------------------------------------------------------
/docs/_images/fill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/fill.png
--------------------------------------------------------------------------------
/docs/_images/geo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/geo.png
--------------------------------------------------------------------------------
/docs/_images/h5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/h5.png
--------------------------------------------------------------------------------
/docs/_images/input.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/input.png
--------------------------------------------------------------------------------
/docs/_images/inputs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/inputs.png
--------------------------------------------------------------------------------
/docs/_images/inspect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/inspect.png
--------------------------------------------------------------------------------
/docs/_images/km_alg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/km_alg.png
--------------------------------------------------------------------------------
/docs/_images/km_dis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/km_dis.png
--------------------------------------------------------------------------------
/docs/_images/km_k.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/km_k.png
--------------------------------------------------------------------------------
/docs/_images/km_misc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/km_misc.png
--------------------------------------------------------------------------------
/docs/_images/km_noise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/km_noise.png
--------------------------------------------------------------------------------
/docs/_images/km_pn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/km_pn.png
--------------------------------------------------------------------------------
/docs/_images/km_shade.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/km_shade.png
--------------------------------------------------------------------------------
/docs/_images/label.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/label.png
--------------------------------------------------------------------------------
/docs/_images/ld_dnd.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ld_dnd.gif
--------------------------------------------------------------------------------
/docs/_images/ld_pn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/ld_pn.png
--------------------------------------------------------------------------------
/docs/_images/load.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/load.png
--------------------------------------------------------------------------------
/docs/_images/npy_plot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/npy_plot.png
--------------------------------------------------------------------------------
/docs/_images/results.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/results.png
--------------------------------------------------------------------------------
/docs/_images/s1_shp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/s1_shp.png
--------------------------------------------------------------------------------
/docs/_images/seg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/seg.png
--------------------------------------------------------------------------------
/docs/_images/seg_fix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/seg_fix.png
--------------------------------------------------------------------------------
/docs/_images/seg_grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/seg_grid.png
--------------------------------------------------------------------------------
/docs/_images/seg_out.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/seg_out.png
--------------------------------------------------------------------------------
/docs/_images/seg_pn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/seg_pn.png
--------------------------------------------------------------------------------
/docs/_images/shapefiles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/shapefiles.png
--------------------------------------------------------------------------------
/docs/_images/unck_out.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_images/unck_out.png
--------------------------------------------------------------------------------
/docs/_sources/ch1_started/firsttime.rst.txt:
--------------------------------------------------------------------------------
1 | First-Time Users
2 | ================
3 |
4 | Learning a new thing could sometimes be a tough thing to do,
5 | but not when you deal with GRID.
6 | GRID aims to provide a smooth envirnoment
7 | for users to perform image segmentation,
8 | with no experience required!
9 |
10 | Launch GRID
11 | -----------
12 |
13 | In the terminal:
14 |
15 | .. prompt:: bash $
16 |
17 | python3 -m grid
18 |
19 | Demo mode
20 | ---------
21 |
22 | For the first-time users, it's recommended to use demo files. Users can start
23 | GRID in the demo mode by choosing the option "Demo" in the
24 | :ref:`welcome panel `.
25 |
26 | .. figure:: res/demo_option.png
27 |
28 | GRID provides two ways to start the analysis,
29 | the bottom one will use the demo image to proceed.
30 |
31 | .. figure:: res/demo_image.png
32 |
33 | **Demo image**. It's recommended to define AOI over the highlighted area.
34 |
35 | Work with your images
36 | ---------------------
37 |
38 | GRID supports most types of :ref:`image files `,
39 | including GeoTiff, PNG, and JPEG.
40 | It's encouraged to provide a :ref:`map file (CSV) ` as well to specify
41 | the field layout and plot IDs. To learn how to make a valid map file,
42 | please follow the instruction of the section :ref:`Maps`.
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/_sources/ch1_started/installation.rst.txt:
--------------------------------------------------------------------------------
1 | Installation
2 | ============
3 |
4 | Step 1: Python
5 | ----------------
6 |
7 | GRID is developed in **Python 3**.
8 | Follow the `official instruction `_
9 | to set up Python.
10 |
11 | Step 2: Rasterio (Windows Users)
12 | ---------------------------------
13 | The easiest way to install Rasterio in Windows is to build it from binaries
14 | `(Official instruction) `_.
15 | Please download correct versions of ``.whl`` from
16 | `Rasterio `_ and
17 | `GDAL `_, and use ``pip``` to install them.
18 |
19 | For example, if you want to run GRID in **64-bit** Windows 10 using Python **3.9**,
20 | the ``.whl`` names and the commands should be:
21 |
22 | .. prompt:: bash
23 |
24 | python -m pip install GDAL-3.4.3-cp39-cp39-win_amd64.whl
25 | python -m pip install rasterio-1.2.10-cp39-cp39-win_amd64.whl
26 |
27 | Step 2: Rasterio (Other Users)
28 | ---------------------------------
29 | `Rasterio `_
30 | is the only GRID dependency that can't be installed via
31 | `PyPI `_.
32 | Below are the alternatives:
33 |
34 | * **Anaconda (Recommended)**
35 | Install Anaconda `here `_,
36 | and run the following commands in **Anaconda Prompt**:
37 |
38 | .. prompt:: bash
39 |
40 | conda config --add channels conda-forge
41 | conda install rasterio
42 |
43 | * `Install from binaries `_
44 |
45 | * `Install from the source distribution `_
46 |
47 | Step 3: Install GRID via PyPI
48 | --------------------------------
49 |
50 | Finally, to install GRID, in the prompt
51 | (or Anaconda Prompts if you installed Rasterio via Anaconda):
52 |
53 | .. prompt:: bash
54 |
55 | python -m pip install photo_grid
56 |
57 | After finishing this step, you should be good to go.
58 | Otherwise, check what dependencies you miss or report any issue to
59 | the `GitHub repository `_ .
60 |
61 | .. NOTE::
62 | If your system can't find the command ``pip``,
63 | follow the `link `_
64 | to install it.
65 |
--------------------------------------------------------------------------------
/docs/_sources/ch2_interface/aoi.rst.txt:
--------------------------------------------------------------------------------
1 | Define AOI
2 | ================
3 |
4 | .. figure:: res/aoi_pn.png
5 |
6 |
7 | Screenshot of GRID defining AOI
8 |
9 | Often time the provided orthoimages contain areas you don't need.
10 | In this step, you can define an area of interest (AOI) to
11 | exclude the redundant parts.
12 |
13 | Draw AOI
14 | ----------
15 |
16 | To draw AOI,
17 | left-click on the image **four times** to assign
18 | four corners of the AOI rectangle.
19 | The red shaded region will be AOI used in the analysis.
20 |
21 | .. raw:: html
22 |
23 |
24 |
25 |
26 |
27 | |
28 |
29 | Adjust AOI
30 | ----------
31 |
32 | * **Move the entire AOI**
33 | Drag from the central area to move the AOI.
34 | The cursor should become a "move" icon.
35 |
36 | .. raw:: html
37 |
38 |
39 |
40 |
41 |
42 | |
43 |
44 | * **Move one corner of the AOI**
45 | Left-click near the **corner** and drag it to adjust its position.
46 | The cursor should become a magnifying glass to help increasing the precision.
47 |
48 | .. raw:: html
49 |
50 |
51 |
52 |
53 |
54 | |
55 |
56 | * **Move one side of the AOI**
57 | Left-click near the AOI **edge** and drag it to adjust its position.
58 | The cursor should become a magnifying glass to help increasing the precision.
59 |
60 | .. raw:: html
61 |
62 |
63 |
64 |
65 |
66 | |
67 |
68 | * **Rotate the AOI**
69 | Left-click and drag at the surrounding area of the AOI to rotate.
70 | The cursor should become a "rotation" icon indicating the AOI can be rotated.
71 |
72 | .. raw:: html
73 |
74 |
75 |
76 |
77 |
78 | |
79 |
80 | * **Create a new AOI**
81 | When move the cursor far away from the exisitng AOI,
82 | the cursor should become a magnifying glass again.
83 | It indicates that users can assign new set of coorindates to create a new AOI.
84 |
85 | .. raw:: html
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/docs/_sources/ch2_interface/centroids.rst.txt:
--------------------------------------------------------------------------------
1 | Detect Centroids
2 | ===================
3 |
4 | .. figure:: res/ct_pn.png
5 |
6 | Screenshot of GRID searching centroids
7 |
8 | After defining POI, GRID will detect the plot centroids automatically by
9 | fitting a major axis and a minor axis to the field layout.
10 | The interactions of two axes are the detected centroids.
11 | Users can furhter adjust the axes or centroids if needed.
12 |
13 | Major axis
14 | ----------
15 |
16 | .. figure:: res/ct_maj.png
17 | :width: 450 px
18 | :align: center
19 |
20 | GRID required one axis of the field layout to be
21 | either vertial (0°) or horizontal (90°).
22 | And this axis in GRID is defined as the **major axis**.
23 |
24 | * **Angle**
25 | Check 0° to set the major axis in the vertical direction,
26 | and 90° for the horizontal direction.
27 |
28 | * **# of ticks**
29 | Specify how many lines of plots follow the direction of the major axis.
30 |
31 | Minor axis
32 | ----------
33 |
34 | .. raw:: html
35 |
36 |
37 |
38 |
39 |
40 | |
41 |
42 | The other axis to fit the layout is called the **minor axis**.
43 | This axis can be any angle that can fit the layout the best.
44 |
45 | * **Angle**
46 | Rotate the spinner to specify an angle
47 | between the minor axis and a vertical line.
48 |
49 |
50 | * **# of ticks**
51 | Same usage as one in the major axis.
52 |
53 | Centroid adjustment
54 | -------------------------
55 |
56 | .. figure:: res/ct_adj.png
57 | :width: 450 px
58 | :align: center
59 |
60 | This section allows users to adjust the position of each axis.
61 | The checked axis will be highlighted by a thicker red line
62 | compared to the other axis.
63 | Following actions are available on the highlighted axis:
64 |
65 | * **Move**
66 | Left-click and drag on any lines to move.
67 |
68 | * **Add**
69 | Left-click on an area not occupied by any line.
70 |
71 | * **Delete**
72 | Right-click on a line you want to delete
--------------------------------------------------------------------------------
/docs/_sources/ch2_interface/kmeans.rst.txt:
--------------------------------------------------------------------------------
1 | Define POI
2 | ==================
3 |
4 | .. figure:: res/km_pn.png
5 |
6 | Screenshot of GRID defining POI
7 |
8 | In this step,
9 | GRID will help users to extract pixel of interest (POI) from the AOI.
10 | POI is colored in yellow, whereas the remaining areas are shown as black pixels.
11 | Pixels contain soil, non-vegetation objects,
12 | and field residuals can be excluded in this step.
13 | There're also refining tools avaialble to remove shadow and image noise
14 |
15 |
16 | K-Means clustering algorithm
17 | ----------------------------
18 |
19 | .. figure:: res/km_alg.png
20 | :width: 450 px
21 | :align: center
22 |
23 | The interface of K-means clustering algorithm
24 |
25 | GRID uses K-means clustering algorithm to cluster imagery pixels.
26 | Two parameters are available to be tuned:
27 |
28 | * **Channels used for clustering**
29 | By checking the box, the corresponding channel will be included
30 | in the feature space for clustering.
31 | The checkable boxes are imagery channels found from the inputs.
32 | For example, in a JPEG image, "1" is the red channel,
33 | which should also be the first channel of a JPEG image.
34 |
35 | * **K**
36 | It's how many clusters expected to exist in the image.
37 |
38 | .. figure:: res/km_k.png
39 |
40 | Comparison between the raw image, 3-cluster image, and 5-cluster image.
41 |
42 | Binarization
43 | ------------
44 |
45 | .. raw:: html
46 |
47 |
48 |
49 |
50 |
51 | |
52 |
53 | This section allows you to assign which clusters belong to POI.
54 | The image will then be binarized into a yellow/black image
55 | showing POI and non-POI, respectively. Two ways to do the binarization:
56 |
57 | * **Auto cutoff**
58 | GRID will rank clusters based on the possibility of being POI.
59 | When auto cutoff = **m**,
60 | the first **m** cluters will be assigned to AOI (yellow).
61 |
62 | * **Custom**
63 | You can also assign POI in the original order of clusters
64 | (which usually is arbitrary from K-means clustering algorithm).
65 | The checked box will be assign to POI.
66 |
67 |
68 | Refine POI
69 | -----------
70 |
71 | .. raw:: html
72 |
73 |
74 |
75 |
76 |
77 | |
78 |
79 | * **De-Shade**
80 | Even though most orthoimages are taken around noon,
81 | which is a time that has minimum shaded area,
82 | there're still some cases that shaded areas are observed in the image.
83 | These type of areas usually have lower brightness and spectral reflectance.
84 | Exclude such areas can improve the quality of the evaluation on each plot.
85 |
86 | .. figure:: res/km_shade.png
87 | :align: center
88 |
89 | * **De-Noise**
90 | It's inevitable to include non-vegetation objects in the image.
91 | Pipes for irrigation system,
92 | or field residuals can sometimes look similar to your evaluated subjects.
93 | To exclude them, GRID provide a gaussian filtering approach
94 | to remove such noise.
95 |
96 | .. figure:: res/km_noise.png
97 | :align: center
98 |
99 |
100 | Display/Zoom
101 | ------------
102 |
103 | .. figure:: res/km_misc.png
104 | :width: 450 px
105 | :align: center
106 |
107 | Different display modes can help users to validate the result.
108 | Users can hover the cursor on the image to zoom in certain areas.
109 | And use the keys ``A``, ``S``, and ``D``
110 | to switch between different display modes
111 | in order to evaluate whether the extracted POIs are valid.
112 |
113 | .. figure:: res/km_dis.png
114 | :align: center
--------------------------------------------------------------------------------
/docs/_sources/ch2_interface/load.rst.txt:
--------------------------------------------------------------------------------
1 | Load Files
2 | ==========
3 |
4 | It's the first panel you'll see in GRID.
5 | The top option allows you to load your own image, field layouts, and shapefiles.
6 | And the bottom option will load an example image for you to explore GRID.
7 |
8 | .. figure:: res/ld_pn.png
9 |
10 | Screenshot of GRID taking inputs
11 |
12 | Input files
13 | -----------
14 |
15 | * **Iamge**
16 | It's a required input in GRID. Load an image you want to work on.
17 | GeoTiff, regular Tiff, PNG, and JPG are supported.
18 |
19 | * **Map**
20 | It's optional to provide a map file.
21 | It can help GRID to know how many rows and columns exist in the image,
22 | also providing plot IDs in order to track your plots better.
23 | To learn how to provide a valid map file, go to this :ref:`section`.
24 |
25 | * **Shape**
26 | It's another optional input.
27 | By loading a shapefile, GRID can replicate plot positions
28 | learned from the previous image to the current one.
29 | This feature is specificaly designed for a situation when you have multiple
30 | images taken in different seasons.
31 | A detailed tutorial is shown in this
32 | :ref:`section`.
33 |
34 | Drag and drop
35 | -------------
36 |
37 | Don't like the "browse button"?
38 | No worry, you can drag and drop files directly from your folders
39 |
40 | .. figure:: res/ld_dnd.gif
41 |
42 | Drag-n-drop feature in GRID
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/docs/_sources/ch2_interface/segmentation.rst.txt:
--------------------------------------------------------------------------------
1 | Segmentation
2 | ============
3 |
4 | .. figure:: res/seg_pn.png
5 |
6 | Screenshot of GRID performing segmentation
7 |
8 | Dynamic
9 | -------
10 |
11 | .. figure:: res/seg_grid.png
12 | :width: 350 px
13 | :align: center
14 |
15 | GRID infers plot boundaries based on the POI distribution.
16 | The only tunable parameter ``Grid Coef.`` is how much weight should be put
17 | on the global layout over local pattern.
18 | For example, when the boundary between two adjacent plots are ambiguous,
19 | ``Grid Coef. = 0.0`` would encourge plot with more connected POI to
20 | agressively expand its border.
21 | Whereas ``Grid Coef. = 1.0`` would let both of their borders to follow
22 | the pattern from other rows/columes.
23 |
24 | Fixed
25 | -----
26 |
27 | .. figure:: res/seg_fix.png
28 | :width: 450 px
29 | :align: center
30 |
31 | If the option ``Fixed`` is checked,
32 | plots will be assigned boundaries with an equal size.
33 | The size of **units** is obtained from:
34 |
35 | .. math::
36 |
37 | \text{1 unit} =
38 | \frac{\text{Image size}}{\text{Number of plots}} * \frac{1}{100}
39 |
40 | For example, if an input image is 1,000 pixels wide,
41 | and there're 10 columns of plots.
42 | 1 **unit** then become 1 pixel wide.
43 | In this case, assigning 50 **units** width to the plots meaning
44 | each plot would has 5 pixel wide boundary.
45 | And when ``width = 100 units``,
46 | plot boundaries should horizontally occupy the entire image.
47 |
48 | Fine-tune results
49 | -----------------
50 |
51 | .. raw:: html
52 |
53 |
54 |
55 |
56 |
57 | |
58 |
59 | GRID provides several ways to fine-tune the segmentation results:
60 |
61 | * **Move centroids**
62 | Left-click and drag within the plots to move the centroids
63 |
64 | * **Resize borders**
65 | Left-click and drag at **the inner side** of the border to resize it.
66 |
67 | * **Row positions**
68 | Left-click and drag at any row of plots to move the entire row.
69 |
70 | * **Column positions**
71 | Left-click and drag at any column of plots to move the entire column.
72 |
73 | Export results
74 | --------------
75 |
76 | .. figure:: res/seg_out.png
77 | :width: 450 px
78 | :align: center
79 |
80 | * **Prefix**
81 | GRID will create a folder for placing the outputs.
82 | The name of this folder is the specified ``Prefix``,
83 | and all the output filenames will start wtth the ``Prefix``.
84 |
85 | * **Output path**
86 | A path where you want the outputs to be saved
87 |
88 | * **Simple output**
89 | By checking this option, only basic results will be saved.
90 | There's further discussion in this `section `
91 |
--------------------------------------------------------------------------------
/docs/_sources/ch3_io/inputs.rst.txt:
--------------------------------------------------------------------------------
1 | Inputs
2 | ======
3 |
4 | Images
5 | ------
6 |
7 | GRID supports most of common formats,
8 | including ``.tif``, ``.jpg``, and ``.png``
9 |
10 | .. note::
11 | Currently, GRID supports images with up to **9 spectral channels**.
12 | The exceeded channels would be ignored in the K-means clustering process,
13 | and it may also affect the performance.
14 |
15 | Maps
16 | ----
17 |
18 | .. figure:: res/demo_map.png
19 | :align: center
20 |
21 | This is an optional input to tell what's the field layout in the image.
22 | It's a simple ``.csv`` file, requiring no header nor row names.
23 | Simply put the plot names based on how they are grown in the field,
24 | and GRID can output results along with these given IDs.
25 |
26 | Shapefiles (inputs)
27 | ----------------------
28 |
29 | The shapefile has to be obtained from GRID to be a valid input.
30 | It's an optional file allows GRID to replicate plot boundaries
31 | rom the previous analysis in GRID.
32 | You can learn the details in this :ref:`section`.
33 |
34 |
35 |
--------------------------------------------------------------------------------
/docs/_sources/ch3_io/outputs.rst.txt:
--------------------------------------------------------------------------------
1 | Outputs
2 | =======
3 |
4 | Tabular results
5 | ---------------
6 |
7 | Extracted information for each plot is presented in a ``.csv`` file.
8 | Below we will list the definition of each field:
9 |
10 | * **var**
11 | Variety names, which are the IDs learned from the map file.
12 | ID will be "unnamed_xx" instead if there's no map file provided.
13 |
14 | * **row**
15 | Count from the toppest row of plots.
16 |
17 | * **column**
18 | Count from the leftest column of plots.
19 |
20 | * **area_all**
21 | Number of pixels in the segmented rectangle (red boundaries).
22 |
23 | * **area_veg**
24 | Number of POI
25 |
26 | Vegetation indices are represented by the averaged value of the POI,
27 | and ``xxx_std`` is its corresponding standard deviation.
28 | Below are the formula of each index,
29 | the x\ :sup:`th`\ band will be labeled as b\ :sub:`x`\ :
30 |
31 | * **Normalized Difference Vegetation Index (NDVI)**
32 | .. math::
33 |
34 | NDVI = \frac{(b_4 - b_1)}{(b_4 + b_1)}
35 |
36 | * **Green Normalized Difference Vegetation Index (GNDVI)**
37 | .. math::
38 |
39 | GNDVI = \frac{(b_4 - b_2)}{(b_4 + b_2)}
40 |
41 | * **Combination of Normalized Difference Vegetation Index (CNDVI)**
42 | .. math::
43 |
44 | CNDVI = \frac{(2 * b_4 - b_1 - b_2)}{(b_4 + b_1 + b_2)}
45 |
46 | * **Ratio Vegetation Index (RVI)**
47 | .. math::
48 |
49 | RVI = \frac{b_4}{b_1}
50 |
51 | * **Green Ratio Vegetation Index (GRVI)**
52 | .. math::
53 |
54 | GRVI = \frac{b_4}{b_2}
55 |
56 | * **Normalized Difference Greenness Vegetation Index (NDGVI)**
57 | .. math::
58 |
59 | NDGVI = \frac{(b_2 - b_1)}{(b_2 + b_1)}
60 |
61 | The channel values are recorded in this output as well.
62 | The **averaged value** of the x\ :sup:`th`\ channel and
63 | its **standard deviation** will be stored
64 | in the column of ``ch_x`` and ``ch_x_std``, respectively.
65 |
66 | Images for validations
67 | ----------------------
68 |
69 | Several images are exported for users to validate the results.
70 | The title of each sub-figure is its suffix:
71 |
72 | * **Checked** :ref:`Simple output `:
73 |
74 | .. figure:: res/ck_out.png
75 | :align: center
76 |
77 |
78 |
79 | * **unchecked** :ref:`Simple output `:
80 |
81 | .. figure:: res/unck_out.png
82 | :align: center
83 |
84 | Shapefiles (outputs)
85 | ----------------------
86 |
87 | The shapefile is generated by the Python package
88 | `PyShp `_ .
89 | Each record represent a segmented plot,
90 | containing coordinates of boundaries
91 | and all the attributes listed in the tabular results.
92 | The shapefile can be `integrated to the analysis in QGIS `
93 | You can also fetch the attributes in Python,
94 | we use the first plot as an example:
95 |
96 | .. nbinput:: ipython3
97 | :execution-count: 1
98 |
99 | # import PyShp
100 | import shapefile
101 |
102 | # load shapefile and get record
103 | file_sp = shapefile.Reader("GRID.shp")
104 |
105 | .. nbinput:: ipython3
106 | :execution-count: 2
107 |
108 | # list attributes
109 | file_sp.fields
110 |
111 | .. nboutput::
112 | :execution-count: 2
113 |
114 | [('DeletionFlag', 'C', 1, 0),
115 | ['var', 'C', 20, 20],
116 | ['row', 'N', 10, 10],
117 | ['col', 'N', 10, 10], ... ...
118 |
119 | .. nbinput:: ipython3
120 | :execution-count: 3
121 |
122 | # demo with the first record
123 | records = file_sp.shapeRecords()
124 | first_plot = records[0]
125 |
126 | .. nbinput:: ipython3
127 | :execution-count: 4
128 |
129 | # polygon coordinates
130 | first_plot.shape.points
131 |
132 | .. nboutput::
133 | :execution-count: 4
134 |
135 | [(1153.5487982819586, 154.80525925556415),
136 |
137 | (1222.2592755806982, 159.82284445357462),
138 |
139 | (1203.8125387566886, 194.30747345836616),
140 |
141 | (1135.102061457949, 189.2898882603557)]
142 |
143 | .. nbinput:: ipython3
144 | :execution-count: 5
145 |
146 | # attributes (exact the same as ones from the csv output)
147 | first_plot.record
148 |
149 | .. nboutput::
150 | :execution-count: 5
151 |
152 | Record #0: ['325', 0.0, 0.0, 2584.0, 1359.0, 0.23869822, 0.12908907, nan,
153 | nan, 0.14441162, 0.07516949, 1.69628965, 0.47877022, 0.99999999, 0.0,
154 | 0.23869822, 0.12908907, 36.2281089, 23.588658, 54.5069904, 22.4681228,
155 | 29.9830757, 14.3784804, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0]
156 |
157 | .. note::
158 | When you load the ``.shp`` file in Python,
159 | make sure you also have ``.dbf`` and ``.shx``
160 | placed in the **same location** and sharing the **same name**.
161 |
162 | NumPy format of AOI
163 | -------------------
164 |
165 | GRID will output the AOI you cropped from the step of :ref:`define AOI`.
166 | The file is suffixed with ``_image`` and has an extension name ``.npy``.
167 | It's encoded as a
168 | `numpy ndarray `_
169 | and can be loaded in Python:
170 |
171 | .. nbinput:: ipython3
172 | :execution-count: 1
173 |
174 | # imports
175 | import numpy as np
176 | import matplotlib.pyplot as plt
177 |
178 | .. nbinput:: ipython3
179 | :execution-count: 2
180 |
181 | # load npy file
182 | data = np.load("GRID_image.npy")
183 | data.shape
184 |
185 | .. nboutput::
186 | :execution-count: 2
187 |
188 | (142, 214, 3)
189 |
190 | .. nbinput:: ipython3
191 | :execution-count: 3
192 |
193 | # plot the ndarray
194 | plt.imshow(data)
195 |
196 | .. nboutput::
197 | :execution-count: 3
198 |
199 |
200 |
201 | .. figure:: res/npy_plot.png
202 | :align: center
203 | :width: 400 px
204 |
205 | H5 dataset
206 | ----------
207 | .. note::
208 | Only by **unchecking** the option :ref:`Simple output `
209 | to obtain this file,
210 | as compressing plots into a hdf5 can sometimes be time-consuming.
211 |
212 | Segmented plots are structured in
213 | `numpy ndarrays `_
214 | and are compressed in a
215 | `HDF5 file `_ .
216 | The file has an extension name ``.h5`` and you can load the file in Python via
217 | `H5py `_ :
218 |
219 | .. nbinput:: ipython3
220 | :execution-count: 1
221 |
222 | # imports
223 | import matplotlib.pyplot as plt
224 | import h5py as h5
225 |
226 | .. nbinput:: ipython3
227 | :execution-count: 2
228 |
229 | # read h5 file in read mode and list all the plot IDs
230 | f = h5.File("GRID.h5", "r")
231 | ids = list(f.keys()); ids
232 |
233 | .. nboutput::
234 | :execution-count: 2
235 |
236 | ['plot_1', 'plot_2', 'plot_3', 'plot_4',
237 | 'plot_5', 'plot_6', 'plot_7', 'plot_8',
238 | 'plot_9', 'plot_10', 'plot_11', 'plot_12']
239 |
240 | .. nbinput:: ipython3
241 | :execution-count: 3
242 |
243 | # plot all the segmented plots
244 | r = 3; c = 4
245 | for i in range(r * c):
246 | plt.subplot(r, c, (i + 1))
247 | plt.title(ids[i])
248 | img = f.get(ids[i])
249 | plt.imshow(img)
250 | plt.show()
251 |
252 | .. figure:: res/h5.png
253 | :width: 800 px
254 |
255 | .. nbinput:: ipython3
256 | :execution-count: 4
257 |
258 | # close the h5 file
259 | f.close()
260 |
261 | |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
--------------------------------------------------------------------------------
/docs/_sources/ch4_adv/arbitrary.rst.txt:
--------------------------------------------------------------------------------
1 | Deal with Arbitrary Field Layout
2 | ===================================
3 |
4 | .. figure:: res/arbitrary/input.png
5 | :align: center
6 |
7 | Example of an arbitrary layout
8 |
9 | An arbitrary field layout is a type of plot arrangement that
10 | there's no consistant number of plots exisitng in a row/column.
11 | To deal with such scenario, users have to additionally
12 | assign centroids for the extra plots. Make sure **every plot** in the
13 | image get assigned a centroid, and it's ok to have some centroids
14 | occupying empty space without plot.
15 |
16 | .. figure:: res/arbitrary/centroid.png
17 | :align: center
18 |
19 | The way to define centroids for an arbitrary layout
20 |
21 |
22 | .. figure:: res/arbitrary/seg.png
23 | :align: center
24 |
25 | GRID will automatically detect whether the centroid has plot occupied or not,
26 | shrinking the space of the empty spots and
27 | expanding borders for ones that really cover plots.
28 |
29 |
--------------------------------------------------------------------------------
/docs/_sources/ch4_adv/dl.rst.txt:
--------------------------------------------------------------------------------
1 | Generate Datasets for Deep Learning
2 | ===================================
3 |
4 | Will be done by the end of August 2020.
--------------------------------------------------------------------------------
/docs/_sources/ch4_adv/qgis.rst.txt:
--------------------------------------------------------------------------------
1 | Work with QGIS
2 | ==============
3 |
4 | QGIS supports Drag and Drop feature to load files.
5 | You can simply drag the orthoimage into QGIS,
6 | as well as the shapefile obtained from GRID
7 |
8 | .. figure:: res/qgis/shapefiles.png
9 | :align: center
10 | :width: 500
11 |
12 | Right click on the shapefile layer, and choose ``property`` to define the layer.
13 | In the tab of ``Symbology``, users can design how to show the border.
14 | Our example use red solid line to draw borders without filling any color.
15 |
16 | .. figure:: res/qgis/border.png
17 | :align: center
18 |
19 | In the tab of ``label``, users can further config the way to show plot IDs.
20 |
21 | .. figure:: res/qgis/label.png
22 | :align: center
23 |
24 | It's also possible to take advantage of GRID outputs.
25 | In the tab of ``Symbology``,
26 | and select ``Graduated`` in the very top drop-down menu.
27 | Then in the drop-down menu of ``Value``,
28 | select a feature you'd like to visualize.
29 | In this example, we use NDVI as indicators.
30 | Then click ``classify`` button to generate the heat map.
31 |
32 | .. figure:: res/qgis/fill.png
33 | :align: center
34 |
35 | Visualize data in a heatmap allows us to evaluate the spatial variation
36 | between different plots.
37 |
38 | .. figure:: res/qgis/inspect.png
39 | :align: center
40 |
--------------------------------------------------------------------------------
/docs/_sources/index.rst.txt:
--------------------------------------------------------------------------------
1 | .. GRID documentation master file, created by
2 | sphinx-quickstart on Thu Jul 9 14:34:18 2020.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | GRID: Deal with Field Segmentations Elegantly
7 | ==========================================================
8 |
9 | .. figure:: res/abstract.png
10 |
11 | .. figure:: https://img.shields.io/pypi/dm/photo_grid.svg?label=pypi%20downloads&logo=python&logoColor=white
12 |
13 | .. figure:: https://img.shields.io/pypi/v/photo_grid.svg?label=pypi%20version&logo=python&logoColor=white
14 |
15 | .. raw:: html
16 |
17 | Follow @poissonfish
18 | Watch
19 | Star
20 | Fork
21 | Issue
22 |
23 | |
24 |
25 |
26 | Getting started
27 | ----------------
28 |
29 | * **Installation**:
30 | :ref:`Python 3 ` |
31 | :ref:`Rasterio ` |
32 | :ref:`PyPI ` |
33 |
34 | * **First-time users**:
35 | :ref:`Launch GRID` |
36 | :ref:`Demo mode` |
37 | :ref:`Work with your images` |
38 |
39 | .. toctree::
40 | :maxdepth: 2
41 | :hidden:
42 | :caption: GATTING STARTED
43 |
44 | /ch1_started/installation
45 | /ch1_started/firsttime
46 |
47 | Interface
48 | ---------
49 |
50 | * **File loading**:
51 | :ref:`Input files` |
52 | :ref:`Drag and drop` |
53 |
54 | * **Define AOI**:
55 | :ref:`Draw AOI` |
56 | :ref:`Adjust AOI` |
57 |
58 | * **Define POI**:
59 | :ref:`K-Means clustering algorithm` |
60 | :ref:`Binarization` |
61 | :ref:`Refine POI` |
62 | :ref:`Display/Zoom` |
63 |
64 | * **Detect centroids**:
65 | :ref:`Major axis` |
66 | :ref:`Minor axis` |
67 | :ref:`Centroid adjustment` |
68 |
69 | * **Segmentation**:
70 | :ref:`Dynamic` |
71 | :ref:`Fixed` |
72 | :ref:`Fine-tune results` |
73 | :ref:`Export results` |
74 |
75 | .. toctree::
76 | :maxdepth: 2
77 | :hidden:
78 | :caption: INTERFACE
79 |
80 | /ch2_interface/load
81 | /ch2_interface/aoi
82 | /ch2_interface/kmeans
83 | /ch2_interface/centroids
84 | /ch2_interface/segmentation
85 |
86 | Inputs/Outputs
87 | --------------
88 |
89 | * **Inputs**:
90 | :ref:`Images` |
91 | :ref:`Maps` |
92 | :ref:`Shapefiles ` |
93 |
94 | * **Outputs**:
95 | :ref:`Tabular results` |
96 | :ref:`Validation ` |
97 | :ref:`Shapefiles ` |
98 | :ref:`NumPy format of AOI` |
99 | :ref:`H5 dataset` |
100 |
101 | .. toctree::
102 | :maxdepth: 2
103 | :hidden:
104 | :caption: INPUTS/OUTPUTS
105 |
106 | /ch3_io/inputs
107 | /ch3_io/outputs
108 |
109 | Advanced usage (Jupyter notebook)
110 | ----------------------------------
111 |
112 | * :ref:`Customize Vegetation Indices`
113 |
114 | * :ref:`Multi-Season Images`
115 |
116 | * :ref:`Work with QGIS`
117 |
118 | * :ref:`Deal with Arbitrary Field Layout`
119 |
120 | * :ref:`Generate datasets for deep learning`
121 |
122 | .. toctree::
123 | :maxdepth: 2
124 | :hidden:
125 | :caption: ADVANCED USAGE
126 |
127 | /ch4_adv/custom_index
128 | /ch4_adv/seasons
129 | /ch4_adv/qgis
130 | /ch4_adv/arbitrary
131 | /ch4_adv/dl
132 |
133 | How to cite GRID
134 | -------------------
135 | To cite GRID, you can:
136 |
137 | - Import `GRID.bib `_
138 |
139 | - or manually key in the following info:
140 |
141 | .. code-block:: none
142 |
143 | @article{Chen and Zhang:2020,
144 | author = {Chunpeng James Chen and Zhiwu Zhang},
145 | title = {GRID: A Python Package for Field Plot Phenotyping Using Aerial Images},
146 | month = may,
147 | year = 2020,
148 | journal = {Remote Sensing},
149 | volume = 12,
150 | issue = 11,
151 | pages = 1697
152 | doi = {10.3390/rs12111697},
153 | url = {https://doi.org/10.3390/rs12111697}
154 | }
155 |
156 | Support
157 | --------
158 |
159 | Find any issue? Post it on
160 | `GitHub `_
161 | or contact `James Chen `_
--------------------------------------------------------------------------------
/docs/_static/GRID_banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/GRID_banner.png
--------------------------------------------------------------------------------
/docs/_static/_sphinx_javascript_frameworks_compat.js:
--------------------------------------------------------------------------------
1 | /*
2 | * _sphinx_javascript_frameworks_compat.js
3 | * ~~~~~~~~~~
4 | *
5 | * Compatability shim for jQuery and underscores.js.
6 | *
7 | * WILL BE REMOVED IN Sphinx 6.0
8 | * xref RemovedInSphinx60Warning
9 | *
10 | */
11 |
12 | /**
13 | * select a different prefix for underscore
14 | */
15 | $u = _.noConflict();
16 |
17 |
18 | /**
19 | * small helper function to urldecode strings
20 | *
21 | * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL
22 | */
23 | jQuery.urldecode = function(x) {
24 | if (!x) {
25 | return x
26 | }
27 | return decodeURIComponent(x.replace(/\+/g, ' '));
28 | };
29 |
30 | /**
31 | * small helper function to urlencode strings
32 | */
33 | jQuery.urlencode = encodeURIComponent;
34 |
35 | /**
36 | * This function returns the parsed url parameters of the
37 | * current request. Multiple values per key are supported,
38 | * it will always return arrays of strings for the value parts.
39 | */
40 | jQuery.getQueryParameters = function(s) {
41 | if (typeof s === 'undefined')
42 | s = document.location.search;
43 | var parts = s.substr(s.indexOf('?') + 1).split('&');
44 | var result = {};
45 | for (var i = 0; i < parts.length; i++) {
46 | var tmp = parts[i].split('=', 2);
47 | var key = jQuery.urldecode(tmp[0]);
48 | var value = jQuery.urldecode(tmp[1]);
49 | if (key in result)
50 | result[key].push(value);
51 | else
52 | result[key] = [value];
53 | }
54 | return result;
55 | };
56 |
57 | /**
58 | * highlight a given string on a jquery object by wrapping it in
59 | * span elements with the given class name.
60 | */
61 | jQuery.fn.highlightText = function(text, className) {
62 | function highlight(node, addItems) {
63 | if (node.nodeType === 3) {
64 | var val = node.nodeValue;
65 | var pos = val.toLowerCase().indexOf(text);
66 | if (pos >= 0 &&
67 | !jQuery(node.parentNode).hasClass(className) &&
68 | !jQuery(node.parentNode).hasClass("nohighlight")) {
69 | var span;
70 | var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
71 | if (isInSVG) {
72 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
73 | } else {
74 | span = document.createElement("span");
75 | span.className = className;
76 | }
77 | span.appendChild(document.createTextNode(val.substr(pos, text.length)));
78 | node.parentNode.insertBefore(span, node.parentNode.insertBefore(
79 | document.createTextNode(val.substr(pos + text.length)),
80 | node.nextSibling));
81 | node.nodeValue = val.substr(0, pos);
82 | if (isInSVG) {
83 | var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
84 | var bbox = node.parentElement.getBBox();
85 | rect.x.baseVal.value = bbox.x;
86 | rect.y.baseVal.value = bbox.y;
87 | rect.width.baseVal.value = bbox.width;
88 | rect.height.baseVal.value = bbox.height;
89 | rect.setAttribute('class', className);
90 | addItems.push({
91 | "parent": node.parentNode,
92 | "target": rect});
93 | }
94 | }
95 | }
96 | else if (!jQuery(node).is("button, select, textarea")) {
97 | jQuery.each(node.childNodes, function() {
98 | highlight(this, addItems);
99 | });
100 | }
101 | }
102 | var addItems = [];
103 | var result = this.each(function() {
104 | highlight(this, addItems);
105 | });
106 | for (var i = 0; i < addItems.length; ++i) {
107 | jQuery(addItems[i].parent).before(addItems[i].target);
108 | }
109 | return result;
110 | };
111 |
112 | /*
113 | * backward compatibility for jQuery.browser
114 | * This will be supported until firefox bug is fixed.
115 | */
116 | if (!jQuery.browser) {
117 | jQuery.uaMatch = function(ua) {
118 | ua = ua.toLowerCase();
119 |
120 | var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
121 | /(webkit)[ \/]([\w.]+)/.exec(ua) ||
122 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
123 | /(msie) ([\w.]+)/.exec(ua) ||
124 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
125 | [];
126 |
127 | return {
128 | browser: match[ 1 ] || "",
129 | version: match[ 2 ] || "0"
130 | };
131 | };
132 | jQuery.browser = {};
133 | jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
134 | }
135 |
--------------------------------------------------------------------------------
/docs/_static/aoi_corner.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/aoi_corner.mp4
--------------------------------------------------------------------------------
/docs/_static/aoi_create.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/aoi_create.mp4
--------------------------------------------------------------------------------
/docs/_static/aoi_entire.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/aoi_entire.mp4
--------------------------------------------------------------------------------
/docs/_static/aoi_new.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/aoi_new.mp4
--------------------------------------------------------------------------------
/docs/_static/aoi_rotate.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/aoi_rotate.mp4
--------------------------------------------------------------------------------
/docs/_static/aoi_side.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/aoi_side.mp4
--------------------------------------------------------------------------------
/docs/_static/css/badge_only.css:
--------------------------------------------------------------------------------
1 | .fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
--------------------------------------------------------------------------------
/docs/_static/css/fonts/Roboto-Slab-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/Roboto-Slab-Bold.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/Roboto-Slab-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/Roboto-Slab-Bold.woff2
--------------------------------------------------------------------------------
/docs/_static/css/fonts/Roboto-Slab-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/Roboto-Slab-Regular.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/Roboto-Slab-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/Roboto-Slab-Regular.woff2
--------------------------------------------------------------------------------
/docs/_static/css/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/_static/css/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/docs/_static/css/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-bold-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/lato-bold-italic.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-bold-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/lato-bold-italic.woff2
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/lato-bold.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/lato-bold.woff2
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-normal-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/lato-normal-italic.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-normal-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/lato-normal-italic.woff2
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-normal.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/lato-normal.woff
--------------------------------------------------------------------------------
/docs/_static/css/fonts/lato-normal.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/css/fonts/lato-normal.woff2
--------------------------------------------------------------------------------
/docs/_static/ct_min.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/ct_min.mp4
--------------------------------------------------------------------------------
/docs/_static/documentation_options.js:
--------------------------------------------------------------------------------
1 | var DOCUMENTATION_OPTIONS = {
2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
3 | VERSION: '1.2.19',
4 | LANGUAGE: 'en',
5 | COLLAPSE_INDEX: false,
6 | BUILDER: 'html',
7 | FILE_SUFFIX: '.html',
8 | LINK_SUFFIX: '.html',
9 | HAS_SOURCE: true,
10 | SOURCELINK_SUFFIX: '.txt',
11 | NAVIGATION_WITH_KEYS: false,
12 | SHOW_SEARCH_SUMMARY: true,
13 | ENABLE_SEARCH_SHORTCUTS: true,
14 | };
--------------------------------------------------------------------------------
/docs/_static/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/file.png
--------------------------------------------------------------------------------
/docs/_static/google_analytics.js:
--------------------------------------------------------------------------------
1 | window.dataLayer = window.dataLayer || [];
2 |
3 | function gtag() {
4 | dataLayer.push(arguments);
5 | }
6 | gtag('js', new Date());
7 | gtag('config', 'UA-151005724-3');
--------------------------------------------------------------------------------
/docs/_static/js/badge_only.js:
--------------------------------------------------------------------------------
1 | !function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}});
--------------------------------------------------------------------------------
/docs/_static/js/html5shiv-printshiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML=" ",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document);
--------------------------------------------------------------------------------
/docs/_static/js/html5shiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML=" ",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);
--------------------------------------------------------------------------------
/docs/_static/js/theme.js:
--------------------------------------------------------------------------------
1 | !function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap(""),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(' '),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0
63 | var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
64 | var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
65 | var s_v = "^(" + C + ")?" + v; // vowel in stem
66 |
67 | this.stemWord = function (w) {
68 | var stem;
69 | var suffix;
70 | var firstch;
71 | var origword = w;
72 |
73 | if (w.length < 3)
74 | return w;
75 |
76 | var re;
77 | var re2;
78 | var re3;
79 | var re4;
80 |
81 | firstch = w.substr(0,1);
82 | if (firstch == "y")
83 | w = firstch.toUpperCase() + w.substr(1);
84 |
85 | // Step 1a
86 | re = /^(.+?)(ss|i)es$/;
87 | re2 = /^(.+?)([^s])s$/;
88 |
89 | if (re.test(w))
90 | w = w.replace(re,"$1$2");
91 | else if (re2.test(w))
92 | w = w.replace(re2,"$1$2");
93 |
94 | // Step 1b
95 | re = /^(.+?)eed$/;
96 | re2 = /^(.+?)(ed|ing)$/;
97 | if (re.test(w)) {
98 | var fp = re.exec(w);
99 | re = new RegExp(mgr0);
100 | if (re.test(fp[1])) {
101 | re = /.$/;
102 | w = w.replace(re,"");
103 | }
104 | }
105 | else if (re2.test(w)) {
106 | var fp = re2.exec(w);
107 | stem = fp[1];
108 | re2 = new RegExp(s_v);
109 | if (re2.test(stem)) {
110 | w = stem;
111 | re2 = /(at|bl|iz)$/;
112 | re3 = new RegExp("([^aeiouylsz])\\1$");
113 | re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
114 | if (re2.test(w))
115 | w = w + "e";
116 | else if (re3.test(w)) {
117 | re = /.$/;
118 | w = w.replace(re,"");
119 | }
120 | else if (re4.test(w))
121 | w = w + "e";
122 | }
123 | }
124 |
125 | // Step 1c
126 | re = /^(.+?)y$/;
127 | if (re.test(w)) {
128 | var fp = re.exec(w);
129 | stem = fp[1];
130 | re = new RegExp(s_v);
131 | if (re.test(stem))
132 | w = stem + "i";
133 | }
134 |
135 | // Step 2
136 | re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
137 | if (re.test(w)) {
138 | var fp = re.exec(w);
139 | stem = fp[1];
140 | suffix = fp[2];
141 | re = new RegExp(mgr0);
142 | if (re.test(stem))
143 | w = stem + step2list[suffix];
144 | }
145 |
146 | // Step 3
147 | re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
148 | if (re.test(w)) {
149 | var fp = re.exec(w);
150 | stem = fp[1];
151 | suffix = fp[2];
152 | re = new RegExp(mgr0);
153 | if (re.test(stem))
154 | w = stem + step3list[suffix];
155 | }
156 |
157 | // Step 4
158 | re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
159 | re2 = /^(.+?)(s|t)(ion)$/;
160 | if (re.test(w)) {
161 | var fp = re.exec(w);
162 | stem = fp[1];
163 | re = new RegExp(mgr1);
164 | if (re.test(stem))
165 | w = stem;
166 | }
167 | else if (re2.test(w)) {
168 | var fp = re2.exec(w);
169 | stem = fp[1] + fp[2];
170 | re2 = new RegExp(mgr1);
171 | if (re2.test(stem))
172 | w = stem;
173 | }
174 |
175 | // Step 5
176 | re = /^(.+?)e$/;
177 | if (re.test(w)) {
178 | var fp = re.exec(w);
179 | stem = fp[1];
180 | re = new RegExp(mgr1);
181 | re2 = new RegExp(meq1);
182 | re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
183 | if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
184 | w = stem;
185 | }
186 | re = /ll$/;
187 | re2 = new RegExp(mgr1);
188 | if (re.test(w) && re2.test(w)) {
189 | re = /.$/;
190 | w = w.replace(re,"");
191 | }
192 |
193 | // and turn initial Y back to y
194 | if (firstch == "y")
195 | w = firstch.toLowerCase() + w.substr(1);
196 | return w;
197 | }
198 | }
199 |
200 |
--------------------------------------------------------------------------------
/docs/_static/minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/minus.png
--------------------------------------------------------------------------------
/docs/_static/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/plus.png
--------------------------------------------------------------------------------
/docs/_static/poi_bin.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/poi_bin.mp4
--------------------------------------------------------------------------------
/docs/_static/poi_noise.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/poi_noise.mp4
--------------------------------------------------------------------------------
/docs/_static/poi_refine.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/poi_refine.mp4
--------------------------------------------------------------------------------
/docs/_static/poi_shad.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/poi_shad.mp4
--------------------------------------------------------------------------------
/docs/_static/pygments.css:
--------------------------------------------------------------------------------
1 | pre { line-height: 125%; }
2 | td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
3 | span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
4 | td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
5 | span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
6 | .highlight .hll { background-color: #ffffcc }
7 | .highlight { background: #f8f8f8; }
8 | .highlight .c { color: #3D7B7B; font-style: italic } /* Comment */
9 | .highlight .err { border: 1px solid #FF0000 } /* Error */
10 | .highlight .k { color: #008000; font-weight: bold } /* Keyword */
11 | .highlight .o { color: #666666 } /* Operator */
12 | .highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
13 | .highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
14 | .highlight .cp { color: #9C6500 } /* Comment.Preproc */
15 | .highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
16 | .highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
17 | .highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
18 | .highlight .gd { color: #A00000 } /* Generic.Deleted */
19 | .highlight .ge { font-style: italic } /* Generic.Emph */
20 | .highlight .gr { color: #E40000 } /* Generic.Error */
21 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
22 | .highlight .gi { color: #008400 } /* Generic.Inserted */
23 | .highlight .go { color: #717171 } /* Generic.Output */
24 | .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
25 | .highlight .gs { font-weight: bold } /* Generic.Strong */
26 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
27 | .highlight .gt { color: #0044DD } /* Generic.Traceback */
28 | .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
29 | .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
30 | .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
31 | .highlight .kp { color: #008000 } /* Keyword.Pseudo */
32 | .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
33 | .highlight .kt { color: #B00040 } /* Keyword.Type */
34 | .highlight .m { color: #666666 } /* Literal.Number */
35 | .highlight .s { color: #BA2121 } /* Literal.String */
36 | .highlight .na { color: #687822 } /* Name.Attribute */
37 | .highlight .nb { color: #008000 } /* Name.Builtin */
38 | .highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
39 | .highlight .no { color: #880000 } /* Name.Constant */
40 | .highlight .nd { color: #AA22FF } /* Name.Decorator */
41 | .highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */
42 | .highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
43 | .highlight .nf { color: #0000FF } /* Name.Function */
44 | .highlight .nl { color: #767600 } /* Name.Label */
45 | .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
46 | .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
47 | .highlight .nv { color: #19177C } /* Name.Variable */
48 | .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
49 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */
50 | .highlight .mb { color: #666666 } /* Literal.Number.Bin */
51 | .highlight .mf { color: #666666 } /* Literal.Number.Float */
52 | .highlight .mh { color: #666666 } /* Literal.Number.Hex */
53 | .highlight .mi { color: #666666 } /* Literal.Number.Integer */
54 | .highlight .mo { color: #666666 } /* Literal.Number.Oct */
55 | .highlight .sa { color: #BA2121 } /* Literal.String.Affix */
56 | .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
57 | .highlight .sc { color: #BA2121 } /* Literal.String.Char */
58 | .highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
59 | .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
60 | .highlight .s2 { color: #BA2121 } /* Literal.String.Double */
61 | .highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
62 | .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
63 | .highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
64 | .highlight .sx { color: #008000 } /* Literal.String.Other */
65 | .highlight .sr { color: #A45A77 } /* Literal.String.Regex */
66 | .highlight .s1 { color: #BA2121 } /* Literal.String.Single */
67 | .highlight .ss { color: #19177C } /* Literal.String.Symbol */
68 | .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
69 | .highlight .fm { color: #0000FF } /* Name.Function.Magic */
70 | .highlight .vc { color: #19177C } /* Name.Variable.Class */
71 | .highlight .vg { color: #19177C } /* Name.Variable.Global */
72 | .highlight .vi { color: #19177C } /* Name.Variable.Instance */
73 | .highlight .vm { color: #19177C } /* Name.Variable.Magic */
74 | .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
--------------------------------------------------------------------------------
/docs/_static/seg_adj.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/_static/seg_adj.mp4
--------------------------------------------------------------------------------
/docs/ch4_adv/arbitrary.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Deal with Arbitrary Field Layout — GRID 1.2.19 documentation
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
72 |
73 |
74 |
75 |
76 | GRID
77 |
78 |
79 |
80 |
81 |
82 |
83 | »
84 | Deal with Arbitrary Field Layout
85 |
86 | View page source
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
118 |
119 | Deal with Arbitrary Field Layout
120 |
121 |
122 |
123 | Example of an arbitrary layout
124 |
125 |
126 | An arbitrary field layout is a type of plot arrangement that
127 | there’s no consistant number of plots exisitng in a row/column.
128 | To deal with such scenario, users have to additionally
129 | assign centroids for the extra plots. Make sure every plot in the
130 | image get assigned a centroid, and it’s ok to have some centroids
131 | occupying empty space without plot.
132 |
133 |
134 |
135 | The way to define centroids for an arbitrary layout
136 |
137 |
138 |
139 |
140 |
141 | GRID will automatically detect whether the centroid has plot occupied or not,
142 | shrinking the space of the empty spots and
143 | expanding borders for ones that really cover plots.
144 |
145 |
146 |
147 |
148 |
149 |
166 |
167 |
168 |
169 |
170 |
175 |
176 |
177 |
--------------------------------------------------------------------------------
/docs/ch4_adv/dl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Generate Datasets for Deep Learning — GRID 1.2.19 documentation
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
71 |
72 |
73 |
74 |
75 | GRID
76 |
77 |
78 |
79 |
80 |
81 |
82 | »
83 | Generate Datasets for Deep Learning
84 |
85 | View page source
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
117 |
118 | Generate Datasets for Deep Learning
119 | Will be done by the end of August 2020.
120 |
121 |
122 |
123 |
124 |
125 |
141 |
142 |
143 |
144 |
145 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/docs/demo/features.rst:
--------------------------------------------------------------------------------
1 | Getting Started with Sphinx
2 | ===========================
3 |
4 | .. meta::
5 | :description lang=en: Get started writing technical documentation with Sphinx and publishing to Read the Docs.
6 |
7 |
8 | Sphinx is a powerful documentation generator that
9 | has many great features for writing technical documentation including:
10 |
11 | * Generate web pages, printable PDFs, documents for e-readers (ePub),
12 | and more all from the same sources
13 | * You can use reStructuredText or :ref:`Markdown `
14 | to write documentation
15 | * An extensive system of cross-referencing code and documentation
16 | * Syntax highlighted code samples
17 | * A vibrant ecosystem of first and third-party extensions_
18 |
19 | .. _extensions: http://www.sphinx-doc.org/en/master/ext/builtins.html#builtin-sphinx-extensions
20 |
21 |
22 | Quick start video
23 | -----------------
24 |
25 | This screencast will help you get started or you can
26 | :ref:`read our guide below `.
27 |
28 | .. raw:: html
29 |
30 |
31 | VIDEO
32 |
33 |
34 |
35 | Quick start
36 | -----------
37 |
38 | Assuming you have Python already, `install Sphinx`_:
39 |
40 | .. prompt:: bash $
41 |
42 | pip install sphinx
43 |
44 | Create a directory inside your project to hold your docs:
45 |
46 | .. prompt:: bash $
47 |
48 | cd /path/to/project
49 | mkdir docs
50 |
51 | Run ``sphinx-quickstart`` in there:
52 |
53 | .. prompt:: bash $
54 |
55 | cd docs
56 | sphinx-quickstart
57 |
58 | This quick start will walk you through creating the basic configuration; in most cases, you
59 | can just accept the defaults. When it's done, you'll have an ``index.rst``, a
60 | ``conf.py`` and some other files. Add these to revision control.
61 |
62 | Now, edit your ``index.rst`` and add some information about your project.
63 | Include as much detail as you like (refer to the reStructuredText_ syntax
64 | or `this template`_ if you need help). Build them to see how they look:
65 |
66 | .. prompt:: bash $
67 |
68 | make html
69 |
70 | Your ``index.rst`` has been built into ``index.html``
71 | in your documentation output directory (typically ``_build/html/index.html``).
72 | Open this file in your web browser to see your docs.
73 |
74 | .. figure:: ../_static/images/first-steps/sphinx-hello-world.png
75 | :figwidth: 500px
76 | :target: ../_static/images/first-steps/sphinx-hello-world.png
77 |
78 | Your Sphinx project is built
79 |
80 | Edit your files and rebuild until you like what you see, then commit your changes and push to your public repository.
81 | Once you have Sphinx documentation in a public repository, you can start using Read the Docs
82 | by :doc:`importing your docs `.
83 |
84 | .. _install Sphinx: http://sphinx-doc.org/install.html
85 | .. _reStructuredText: http://sphinx-doc.org/rest.html
86 | .. _this template: https://www.writethedocs.org/guide/writing/beginners-guide-to-docs/#id1
87 |
88 | Using Markdown with Sphinx
89 | --------------------------
90 |
91 | You can use Markdown and reStructuredText in the same Sphinx project.
92 | We support this natively on Read the Docs, and you can do it locally:
93 |
94 | .. prompt:: bash $
95 |
96 | pip install recommonmark
97 |
98 | Then in your ``conf.py``:
99 |
100 | .. code-block:: python
101 |
102 | extensions = ['recommonmark']
103 |
104 | .. warning:: Markdown doesn't support a lot of the features of Sphinx,
105 | like inline markup and directives. However, it works for
106 | basic prose content. reStructuredText is the preferred
107 | format for technical documentation, please read `this blog post`_
108 | for motivation.
109 |
110 | .. _this blog post: https://www.ericholscher.com/blog/2016/mar/15/dont-use-markdown-for-technical-docs/
111 |
112 |
113 | External resources
114 | ------------------
115 |
116 | Here are some external resources to help you learn more about Sphinx.
117 |
118 | * `Sphinx documentation`_
119 | * `RestructuredText primer`_
120 | * `An introduction to Sphinx and Read the Docs for technical writers`_
121 |
122 | .. _Sphinx documentation: http://www.sphinx-doc.org/
123 | .. _RestructuredText primer: http://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html
124 | .. _An introduction to Sphinx and Read the Docs for technical writers: https://www.ericholscher.com/blog/2016/jul/1/sphinx-and-rtd-for-writers/
125 |
126 |
127 |
128 | .. csv-table:: GRID Map file
129 | :file: res/demo_map.csv
130 | :header-rows: 0
131 |
132 |
--------------------------------------------------------------------------------
/docs/demo/main.rst:
--------------------------------------------------------------------------------
1 | Read the Docs: Documentation Simplified
2 | =======================================
3 |
4 | .. meta::
5 | :description lang=en: Automate building, versioning, and hosting of your technical documentation continuously on Read the Docs.
6 |
7 | `Read the Docs`_ simplifies software documentation
8 | by building, versioning, and hosting of your docs, automatically.
9 | Think of it as *Continuous Documentation*.
10 |
11 | Never out of sync |:arrows_counterclockwise:|
12 | Whenever you push code to your favorite version control system,
13 | whether that is Git, Mercurial, Bazaar, or Subversion,
14 | Read the Docs will automatically build your docs
15 | so your code and documentation are always up-to-date.
16 | Read more about :doc:`/webhooks`.
17 |
18 | Multiple versions |:card_index_dividers:|
19 | Read the Docs can host and build multiple versions of your docs
20 | so having a 1.0 version of your docs and a 2.0 version
21 | of your docs is as easy as having a separate branch or tag in your version control system.
22 | Read more about :doc:`/versions`.
23 |
24 | Open Source and User Focused |:heartbeat:|
25 | Our code is free and `open source `_.
26 | :doc:`Our company ` is bootstrapped and 100% user focused.
27 | |org_brand| hosts documentation for over 100,000 large
28 | and small open source projects,
29 | in almost every human and computer language.
30 | |com_brand| supports hundreds of organizations with product and internal documentation.
31 |
32 | .. _Read the docs: https://readthedocs.org/
33 |
34 | You can find out more about our all the :doc:`/features` in these pages.
35 |
36 | First steps
37 | -----------
38 |
39 | Are you new to software documentation
40 | or are you looking to use your existing docs with Read the Docs?
41 | Learn about documentation authoring tools such as Sphinx and MkDocs
42 | to help you create fantastic documentation for your project.
43 |
44 | * **Getting started**:
45 | :doc:`With Sphinx ` |
46 | :doc:`With MkDocs ` |
47 | :doc:`Feature Overview ` |
48 | :doc:`/choosing-a-site`
49 |
50 | * **Importing your existing documentation**:
51 | :doc:`Import guide `
52 |
53 |
54 | .. toctree::
55 | :maxdepth: 2
56 | :hidden:
57 | :caption: First steps
58 |
59 | /intro/getting-started-with-sphinx
60 | /intro/getting-started-with-mkdocs
61 |
62 | /intro/import-guide
63 | /features
64 | /choosing-a-site
65 |
66 |
67 | Getting started with Read the Docs
68 | -----------------------------------
69 |
70 | Learn more about configuring your automated documentation builds
71 | and some of the core features of Read the Docs.
72 |
73 | * **Overview of core features**:
74 | :doc:`Incoming webhooks ` |
75 | :doc:`/custom_domains` |
76 | :doc:`/versions` |
77 | :doc:`/downloadable-documentation` |
78 | :doc:`/hosting` |
79 | :doc:`/server-side-search`
80 |
81 | * **Connecting with GitHub, BitBucket, or GitLab**:
82 | :doc:`Connecting your VCS account ` |
83 | :doc:`VCS webhooks `
84 |
85 | * **Read the Docs build process**:
86 | :doc:`Configuration reference ` |
87 | :doc:`Build process ` |
88 | :doc:`/badges` |
89 |
90 | * **Troubleshooting**:
91 | :doc:`/support` |
92 | :doc:`Frequently asked questions `
93 |
94 | .. toctree::
95 | :maxdepth: 1
96 | :hidden:
97 | :caption: Getting started
98 |
99 | /config-file/index
100 | /webhooks
101 | /custom_domains
102 | /versions
103 | /downloadable-documentation
104 | /server-side-search
105 | /hosting
106 |
107 | /connected-accounts
108 |
109 | /builds
110 | /badges
111 |
112 | /support
113 | /faq
114 |
115 |
116 | Step-by-step Guides
117 | -------------------
118 |
119 | These guides will help walk you through specific use cases
120 | related to Read the Docs itself, documentation tools like Sphinx and MkDocs
121 | and how to write successful documentation.
122 |
123 | * :doc:`/guides/tools`
124 | * :doc:`/guides/platform`
125 | * :doc:`/guides/commercial`
126 |
127 | .. toctree::
128 | :maxdepth: 2
129 | :hidden:
130 | :caption: Step-by-step Guides
131 |
132 | /guides/tools
133 | /guides/platform
134 | /guides/commercial
135 |
136 | Advanced features of Read the Docs
137 | ----------------------------------
138 |
139 | Read the Docs offers many advanced features and options.
140 | Learn more about these integrations and how you can get the most
141 | out of your documentation and Read the Docs.
142 |
143 | * **Advanced project configuration**:
144 | :doc:`subprojects` |
145 | :doc:`Single version docs `
146 |
147 | * **Multi-language documentation**:
148 | :doc:`Translations and localization `
149 |
150 | .. TODO: Move user-defined to Getting started, they are core functionality
151 |
152 | * **Redirects**:
153 | :doc:`User defined redirects ` |
154 | :doc:`Automatic redirects `
155 |
156 | * **Versions**
157 | :doc:`Automation rules `
158 |
159 | * **Topic specific guides**:
160 | :doc:`How-to guides `
161 |
162 | * **Extending Read the Docs**:
163 | :doc:`REST API `
164 |
165 | .. toctree::
166 | :maxdepth: 2
167 | :hidden:
168 | :glob:
169 | :caption: Advanced features
170 |
171 | subprojects
172 | single_version
173 |
174 | localization
175 |
176 | user-defined-redirects
177 | automatic-redirects
178 |
179 | automation-rules
180 |
181 |
182 | api/index
183 |
184 |
185 | The Read the Docs project and organization
186 | ------------------------------------------
187 |
188 | Learn about Read the Docs, the project and the company,
189 | and find out how you can get involved and contribute to the development and success
190 | of Read the Docs and the larger software documentation ecosystem.
191 |
192 | * **Getting involved with Read the Docs**:
193 | :doc:`Contributing ` |
194 | :doc:`Development setup ` |
195 | :doc:`roadmap` |
196 | :doc:`Code of conduct `
197 |
198 | * **Policies & Process**:
199 | :doc:`security` |
200 | :doc:`Privacy policy ` |
201 | :doc:`Terms of service ` |
202 | :doc:`DMCA takedown policy ` |
203 | :doc:`Policy for abandoned projects ` |
204 | :doc:`Release notes & changelog `
205 |
206 | * **The people and philosophy behind Read the Docs**:
207 | :doc:`About Us ` |
208 | :doc:`Team ` |
209 | :doc:`Open source philosophy ` |
210 | :doc:`Our story `
211 |
212 | * **Financial and material support**:
213 | :doc:`advertising/index` |
214 | :doc:`Sponsors `
215 |
216 | * **Read the Docs for Business**:
217 | :doc:`Support and additional features `
218 |
219 | * **Running your own version of Read the Docs**:
220 | :doc:`Private installations `
221 |
222 |
223 | .. toctree::
224 | :maxdepth: 1
225 | :hidden:
226 | :caption: About Read the Docs
227 |
228 | contribute
229 | development/index
230 | roadmap
231 | gsoc
232 | code-of-conduct
233 |
234 | security
235 | privacy-policy
236 | terms-of-service
237 | dmca/index
238 | abandoned-projects
239 | changelog
240 |
241 | about
242 | team
243 | open-source-philosophy
244 | story
245 |
246 | advertising/index
247 | sponsors
248 |
249 | commercial/index
250 |
251 | custom_installs/index
252 |
253 |
254 |
255 |
256 |
257 |
258 | .. figure:: ../_static/images/first-steps/sphinx-hello-world.png
259 | :figwidth: 500px
260 | :target: ../_static/images/first-steps/sphinx-hello-world.png
261 |
262 | Your Sphinx project is built
263 |
--------------------------------------------------------------------------------
/docs/genindex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Index — GRID 1.2.19 documentation
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
69 |
70 |
71 |
72 |
73 | GRID
74 |
75 |
76 |
77 |
78 |
79 |
80 | »
81 | Index
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
Index
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
114 |
115 |
116 |
117 |
118 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/docs/grid.bib:
--------------------------------------------------------------------------------
1 | @article{Chen and Zhang:2020,
2 | author = {Chunpeng James Chen and Zhiwu Zhang},
3 | title = {GRID: A Python Package for Field Plot Phenotyping Using Aerial Images},
4 | month = may,
5 | year = 2020,
6 | journal = {Remote Sensing},
7 | volume = 12,
8 | issue = 11,
9 | pages = 1697
10 | doi = {10.3390/rs12111697},
11 | url = {https://doi.org/10.3390/rs12111697}
12 | }
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=source
11 | set BUILDDIR=build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/docs/objects.inv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/docs/objects.inv
--------------------------------------------------------------------------------
/docs/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Search — GRID 1.2.19 documentation
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
72 |
73 |
74 |
75 |
76 | GRID
77 |
78 |
79 |
80 |
81 |
82 |
83 | »
84 | Search
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | Please activate JavaScript to enable the search functionality.
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
122 |
123 |
124 |
125 |
126 |
131 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
--------------------------------------------------------------------------------
/grid/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = "Chun-Peng James Chen "
2 | __version__ = "1.3.13"
3 | __update__ = "November 27, 2024"
4 |
--------------------------------------------------------------------------------
/grid/__init__.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/__init__.pyc
--------------------------------------------------------------------------------
/grid/__main__.py:
--------------------------------------------------------------------------------
1 | # imports
2 | import subprocess
3 | import json
4 | import sys
5 | from urllib import request
6 | from pkg_resources import parse_version
7 |
8 | # basic imports
9 | import sys
10 | import os
11 |
12 | # 3rd party imports
13 | from PyQt6.QtWidgets import QApplication
14 | from PyQt6.QtCore import QTimer
15 | import qdarkstyle
16 |
17 |
18 | # self imports
19 | from grid.gridGUI import *
20 | from grid.__init__ import __version__, __update__
21 |
22 |
23 | def main():
24 | if "__main__" not in sys.argv[0]:
25 | # prevent from re-show welcome message in gridGUI
26 | # welcome message
27 | print("~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~")
28 | print(" Welcome to GRID Ver.%s " % __version__)
29 | print("~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~")
30 | print("Author : James Chen ")
31 | print("Last update : %s " % __update__)
32 | print("User manual : https://poissonfish.github.io/GRID/")
33 | print("~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~")
34 | print("Recent update ")
35 | print(" - Now you can launch GRID by typing 'GRID' in terminal")
36 | print("~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~")
37 |
38 | # self update
39 | try:
40 | url = "https://pypi.python.org/pypi/photo_grid/json"
41 | releases = json.loads(request.urlopen(url).read())["releases"]
42 | new_version = sorted(releases, key=parse_version, reverse=True)[0]
43 | if __version__ != new_version:
44 | # Dialog
45 | ans = None
46 | bol_ans = None
47 | possible_pos_ans = ["y", "Y", "yes"]
48 | possible_neg_ans = ["n", "N", "no"]
49 |
50 | while bol_ans is None:
51 | ans = input(
52 | "A newer version of GRID (ver. %s) is now available, upgrade? (y/n) "
53 | % new_version
54 | )
55 | if ans in possible_pos_ans:
56 | bol_ans = True
57 | elif ans in possible_neg_ans:
58 | bol_ans = False
59 |
60 | if bol_ans:
61 | subprocess.check_call(
62 | [
63 | sys.executable,
64 | "-m",
65 | "pip",
66 | "install",
67 | "photo_grid==%s" % new_version,
68 | "--upgrade",
69 | ]
70 | )
71 | print("\n")
72 | print("~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~")
73 | print(" Please re-launch GRID to finish the update")
74 | print("~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~")
75 | print("\n")
76 | quit()
77 | except Exception:
78 | print("\n")
79 | print("~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~")
80 | print(" Sorry, we currently have issue updating your GRID.")
81 | print("~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~*~~~~~~~~~")
82 | print("\n")
83 |
84 | app = QApplication(sys.argv)
85 | if "--light" not in sys.argv:
86 | app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
87 |
88 | grid = GRID_GUI()
89 | timer = QTimer()
90 | timer.timeout.connect(lambda: None)
91 | timer.start(100)
92 | app.exec()
93 |
94 |
95 | if __name__ == "__main__":
96 | main()
97 |
--------------------------------------------------------------------------------
/grid/archive/0611_shapefile.py:
--------------------------------------------------------------------------------
1 | import matplotlib.pyplot as plt
2 | import cv2
3 | import numpy as np
4 | from io import BytesIO as StringIO
5 | import shapefile
6 | import numpy
7 | import rasterio
8 | import rasterio.mask
9 | import os
10 |
11 | os.chdir("..")
12 | sys.path
13 | sys.path.remove("/Users/jameschen/Dropbox/photo_grid/grid")
14 | os.chdir("/Users/jameschen/Dropbox/photo_grid/")
15 | import grid as gd
16 |
17 | #
18 | os.chdir("/Users/jameschen/Dropbox/photo_grid/test/Jacob")
19 | f_tif = rasterio.open('RGB-integer.tif')
20 | f_sf = shapefile.Reader("jacob.shp")
21 |
22 | row_max = -1
23 | col_max = -1
24 | pts_crop = [(0, 0), (0, 0), (0, 0), (0, 0)]
25 |
26 | rec = f_sf.shapeRecords()
27 | n_rec = len(rec)
28 |
29 | for i in range(n_rec):
30 | # find four corners
31 | # [[W, N], [E, N], [E, S], [W, S]]
32 | # (0, 0), (0, m), (m, m), (m, 0)
33 | pts = rec[i].shape.points
34 | attr = rec[i].record
35 | row = attr[1]
36 | col = attr[2]
37 |
38 | if row == 0 and col == 0:
39 | # NW
40 | pts_crop[0] = pts[0]
41 | elif row == 0 and col > col_max:
42 | # NE
43 | pts_crop[1] = pts[1]
44 | elif row > row_max and col == 0:
45 | # SW
46 | pts_crop[3] = pts[3]
47 | elif row > row_max and col > col_max:
48 | # SE
49 | pts_crop[2] = pts[2]
50 |
51 | pts_crop = [invAffine(pts_crop[i], f_tif.transform) for i in range(4)]
52 |
53 |
54 | pts = [invAffine(pts[i], f_tif.transform) for i in range(4)]
55 | ptPlt = np.array(pts_crop).transpose()
56 | ptSm = np.array(pts).transpose()
57 | plt.scatter(ptPlt[0], ptPlt[1])
58 | plt.scatter(ptSm[0], ptSm[1])
59 |
60 |
61 | def invAffine(pt, affine):
62 | """
63 | convert GIS coordinate to (x, y)
64 |
65 | NOTE:
66 | # a = width of a pixel
67 | # b = row rotation(typically zero)
68 | # c = x-coordinate of the center of the upper-left pixel
69 | # d = column rotation(typically zero)
70 | # e = height of a pixel(typically negative)
71 | # f = y-coordinate of the center of the upper-left pixel
72 | """
73 | # transformation
74 | xg = (pt[0] - affine[2]) / affine[0]
75 | yg = (pt[1] - affine[5]) / affine[4]
76 |
77 | # return
78 | return (xg, yg)
79 |
80 |
81 |
82 |
83 | pt = (30, 50)
84 | xy = affine * pt
85 | invAffine(xy, affine)
86 |
87 |
88 |
89 |
90 |
91 | # generate sorted source point
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/grid/archive/0615_zz_image.r:
--------------------------------------------------------------------------------
1 | ############ ############ ############
2 | # Date: Jun 15, 2020
3 | # Author: Chunpeng James Chen
4 | # Description:
5 | # It's a code showing how to load an image into a r-compatible data.frame
6 | ############ ############ ############
7 |
8 | # DEPENDENCIES
9 | ############ ############ ############
10 |
11 | # install.packages("imager")
12 | library(imager)
13 |
14 | # FUNCTIONS
15 | ############ ############ ############
16 |
17 | # Description
18 | # convert imager object to data.frame (cols: x, y, c1, c2...)
19 | # Input
20 | # image: image object loaded from library imager
21 | # Output
22 | # df: a data.frame containing information of xy coordinates and channel values
23 | img2df <- function(image) {
24 | w <- dim(image)[1]
25 | h <- dim(image)[2]
26 | d <- 3
27 | df <- matrix(image[,, 1, 1:d], nrow=h * w, ncol=d) %>%
28 | data.frame(x=rep(1 : w, length=w * h),
29 | y=rep(1 : h, each=w),.)
30 | names(df) <- c("x", "y", paste0("c", 1:d))
31 | return (df)
32 | }
33 |
34 | # Description
35 | # convert an image file to data.frame
36 | # Input
37 | # filename: file path to where the file is stored
38 | # Output
39 | # df: a data.frame containing information of xy coordinates and channel values
40 | file2df <- function(filename) {
41 | filename %>%
42 | load.image() %>%
43 | img2df() %>%
44 | return()
45 | }
46 |
47 | # Description
48 | # convert a data.frame (col: x, y, c1, c2 ...) to a imager object
49 | # Input
50 | # df: a dataframe containing information of xy coordinates and channel values
51 | # Output
52 | # img: a imagery object which is ready to be ploted
53 | df2img <- function(df) {
54 | w = max(df$x)
55 | h = max(df$y)
56 | d = ncol(df) - 2
57 | subset(df, select=-c(x, y)) %>%
58 | as.matrix() %>%
59 | as.vector() %>%
60 | as.cimg(dim=c(w, h, 1, d)) %>%
61 | return()
62 | }
63 |
64 | # Description
65 | # save an imager object as an image file
66 | # Input
67 | # image: imager object or 2d matrix (single channel image)
68 | # filename: a path where the image will be saved
69 | # Output
70 | # NA
71 | img2file <- function(image, filename) {
72 | cimg <- as.cimg(image)
73 | save.image(cimg, filename)
74 | }
75 |
76 | # SAMPLE CODE
77 | ############ ############ ############
78 | # specify file name
79 | filename <- "test.png"
80 |
81 | # get data.frame from a file (xy coordinates + 3 channels)
82 | # OPTION 1
83 | img <- load.image(filename)
84 | df <- img2df(img)
85 | # OPTION 2
86 | df <- file2df(filename)
87 |
88 | # get PCA data.frame (xy coordinates + PCs)
89 | mat_pc <- prcomp(df[, 3 : (3 + 2)], scale=T, center=T)$x
90 | df_pc <- data.frame(df[, c("x", "y")], mat_pc)
91 |
92 | # get PCA image
93 | img_pc <- df2img(df_pc)
94 |
95 | # plot original image
96 | plot(img)
97 |
98 | # plot index: (c1 - c2) / (c1 + c2)
99 | c1 = img[,, 1]
100 | c2 = img[,, 2]
101 | img_index = (c1 - c2) / (c1 + c2)
102 | heatmap(img_index, Rowv=NA, Colv=NA)
103 |
104 | # plot all 3 PCs
105 | plot(img_pc)
106 |
107 | # plot the 2nd PC
108 | heatmap(img_pc[, , 2], Rowv=NA, Colv=NA)
109 |
110 | # plot (pc1-pc2)/(pc1+pc2)
111 | pc1 = img_pc[, , 1]
112 | pc2 = img_pc[, , 2]
113 | img_index_pc = (pc1 - pc2) / (pc1 + pc2)
114 | heatmap(img_index_pc, Rowv=NA, Colv=NA)
115 |
116 | # save images
117 | img2file(img_index, "index.png")
118 | img2file(img_pc, "pc.png")
119 | img2file(img_pc[,, 2], "pc2.png")
120 |
--------------------------------------------------------------------------------
/grid/archive/CPU_Agent.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import QRect
2 | from .Misc import Dir
3 |
4 | class Agent():
5 | def __init__(self, name, row, col, imgH, imgW):
6 | '''
7 | '''
8 | self.name = name
9 | self.row, self.col = row, col
10 | self.imgH, self.imgW = int(imgH), int(imgW)
11 | self.y, self.x = 0, 0
12 | self.y_reset, self.x_reset = 0, 0
13 | self.pre_rg_W, self.pre_rg_H = range(0), range(0)
14 | self.border, self.border_reset = dict(), dict()
15 | for dir in list([Dir.NORTH, Dir.EAST, Dir.SOUTH, Dir.WEST]):
16 | self.border[dir.name] = 0
17 | self.border_reset[dir.name] = 0
18 | def get_col(self):
19 | '''
20 | '''
21 | return self.col
22 | def get_row(self):
23 | '''
24 | '''
25 | return self.row
26 | def get_coordinate(self):
27 | '''
28 | '''
29 | return self.x, self.y
30 | def get_pre_dim(self, isHeight=True):
31 | '''
32 | '''
33 | return self.pre_rg_H if isHeight else self.pre_rg_W
34 | def get_border(self, dir):
35 | return self.border[dir.name]
36 | def get_rect(self):
37 | x = self.get_border(Dir.WEST)
38 | y = self.get_border(Dir.NORTH)
39 | w = self.get_border(Dir.EAST) - x
40 | h = self.get_border(Dir.SOUTH) - y
41 | return QRect(x, y, w, h)
42 | def get_score_area(self, dir, img):
43 | '''
44 | Will ragne from 0 to 1
45 | '''
46 | isH = dir.value%2 # E->1, S->0
47 | rg = self.get_pre_dim(isHeight=isH)
48 | bd = self.get_border(dir)
49 | # print("==== row:%d, col:%d ====" %(self.row, self.col))
50 | # print(rg)
51 | # print(bd)
52 | return img[rg, bd].mean() if isH else img[bd, rg].mean()
53 | def get_score_grid(self, dir):
54 | '''
55 | Will ragne from 0 to 1
56 | '''
57 | isWE = dir.value%2 # is W, E or N, S
58 | pt_center = self.x if isWE else self.y
59 | pt_cur = self.get_border(dir)
60 | return abs(pt_cur-pt_center)
61 | def set_coordinate(self, x, y):
62 | '''
63 | '''
64 | self.x, self.y = int(x), int(y)
65 | self.x_reset, self.y_reset = int(x), int(y)
66 | self.set_border(Dir.NORTH, y)
67 | self.set_border(Dir.SOUTH, y)
68 | self.set_border(Dir.WEST, x)
69 | self.set_border(Dir.EAST, x)
70 | def set_pre_dim(self, rg):
71 | '''
72 | '''
73 | self.pre_rg_W = range(rg['WEST'], rg['EAST'])
74 | self.pre_rg_H = range(rg['NORTH'], rg['SOUTH'])
75 | self.x = int((rg['EAST']+rg['WEST'])/2)
76 | self.y = int((rg['NORTH']+rg['SOUTH'])/2)
77 | self.x_reset, self.y_reset = self.x, self.y
78 | for dir in list([Dir.NORTH, Dir.WEST, Dir.SOUTH, Dir.EAST]):
79 | self.border_reset[dir.name] = self.border[dir.name]
80 | def set_border(self, dir, value):
81 | '''
82 | '''
83 | self.border[dir.name] = int(value)
84 | self.check_border()
85 | def update_border(self, dir, value):
86 | '''
87 | '''
88 | self.border[dir.name] += int(value)
89 | self.check_border()
90 | def update_coordinate(self, val, axis=0):
91 | '''
92 | '''
93 | val = int(val)
94 | if axis==0:
95 | self.y += val
96 | self.border[Dir.NORTH.name] += val
97 | self.border[Dir.SOUTH.name] += val
98 | elif axis==1:
99 | self.x += val
100 | self.border[Dir.WEST.name] += val
101 | self.border[Dir.EAST.name] += val
102 | self.check_border()
103 | def check_border(self):
104 | if self.border[Dir.NORTH.name]<0:
105 | self.border[Dir.NORTH.name] = 0
106 | if self.border[Dir.WEST.name]<0:
107 | self.border[Dir.WEST.name] = 0
108 | if self.border[Dir.SOUTH.name]>=self.imgH:
109 | self.border[Dir.SOUTH.name] = self.imgH-1
110 | if self.border[Dir.EAST.name]>=self.imgW:
111 | self.border[Dir.EAST.name] = self.imgW-1
112 | def set_save(self, save=False):
113 | "do nothing"
114 | def reset_coordinate(self):
115 | self.x = self.x_reset
116 | self.y = self.y_reset
117 | self.reset_border()
118 | def reset_border(self):
119 | for dir in list([Dir.NORTH, Dir.WEST, Dir.SOUTH, Dir.EAST]):
120 | self.border[dir.name] = self.border_reset[dir.name]
121 |
--------------------------------------------------------------------------------
/grid/archive/Misc.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import pandas as pd
3 | from enum import Enum
4 | from PyQt5.QtWidgets import *
5 | from PyQt5.QtCore import *
6 | from PyQt5.QtGui import *
7 |
8 |
9 |
10 | def get_peak(img, map, n_smooth=100, axis=0):
11 | '''
12 | '''
13 | from scipy.signal import find_peaks
14 | import numpy as np
15 | # compute signal
16 | ls_mean = img.mean(axis=(not axis)*1) # 0:nrow
17 | # gaussian smooth signal
18 | for i in range(n_smooth):
19 | ls_mean = np.convolve(np.array([1, 2, 4, 2, 1])/10, ls_mean, mode='same')
20 | peaks, _ = find_peaks(ls_mean)
21 | if map is not None:
22 | if len(peaks) > map.shape[axis]:
23 | while len(peaks) > map.shape[axis]:
24 | ls_diff = [peaks[i+1]-peaks[i] for i in range(len(peaks)-1)]
25 | idx_diff = np.argmin(ls_diff)
26 | idx_kick = idx_diff if (ls_mean[peaks[idx_diff]] < ls_mean[peaks[idx_diff+1]]) else (idx_diff+1)
27 | peaks = np.delete(peaks, idx_kick)
28 | elif len(peaks) < map.shape[axis]:
29 | while len(peaks) < map.shape[axis]:
30 | ls_diff = [peaks[i+1]-peaks[i] for i in range(len(peaks)-1)]
31 | idx_diff = np.argmax(ls_diff)
32 | peak_insert = (peaks[idx_diff]+peaks[idx_diff+1])/2
33 | peaks = np.sort(np.append(peaks, int(peak_insert)))
34 | return peaks, ls_mean
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/grid/archive/archive.py:
--------------------------------------------------------------------------------
1 | def read_jpg(filename):
2 | from PIL import Image
3 | Image.MAX_IMAGE_PIXELS = 1e+9
4 | img = np.array(Image.open(filename)).astype(np.uint8)
5 | return img
6 |
7 |
8 | def read_tiff(filename, bands=None, xBSize=5000, yBSize=5000):
9 | '''import'''
10 | import gdal
11 | from tqdm import tqdm_gui
12 | '''program'''
13 | ds = gdal.Open(filename)
14 | gdal.UseExceptions()
15 | nrow = ds.RasterYSize
16 | ncol = ds.RasterXSize
17 | if bands == None:
18 | bands = range(ds.RasterCount)
19 | data = np.zeros((nrow, ncol, len(bands)))
20 | for b in bands:
21 | band = ds.GetRasterBand(b+1)
22 | for i in tqdm_gui(range(0, nrow, yBSize), desc="Channel %d/%d" % (b, len(bands)-1), leave=False):
23 | if i + yBSize < nrow:
24 | numRows = yBSize
25 | else:
26 | numRows = nrow - i
27 | for j in range(0, ncol, xBSize):
28 | if j + xBSize < ncol:
29 | numCols = xBSize
30 | else:
31 | numCols = ncol - j
32 | data[i:(i+numRows), j:(j+numCols),
33 | b] = band.ReadAsArray(j, i, numCols, numRows)
34 | return data.astype(np.uint8)
35 |
36 |
37 | def write_tiff(array, outname):
38 | driver = gdal.GetDriverByName("GTiff")
39 | out_info = driver.Create(outname+".tif",
40 | array.shape[1], # x
41 | array.shape[0], # y
42 | array.shape[2], # channels
43 | gdal.GDT_Byte)
44 | for i in range(array.shape[2]):
45 | out_info.GetRasterBand(i+1).WriteArray(array[:, :, i])
46 |
--------------------------------------------------------------------------------
/grid/archive/grid2.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from PyQt5.QtWidgets import *
3 | from PyQt5.QtCore import *
4 | from PyQt5.QtGui import *
5 | from .CPU_Agent import *
6 | from .CPU_Field import *
7 | from .GPU_Input import *
8 | from .GPU_Cropper import *
9 | from .GPU_Kmeaner import *
10 | from .GPU_Anchor import *
11 | from .GPU_Output import *
12 |
13 | class GRID(QMainWindow):
14 | def __init__(self):
15 | super().__init__()
16 | self.setStyleSheet("""
17 | QWidget {\
18 | font: 20pt Trebuchet MS
19 | }
20 | QGroupBox::title{
21 | subcontrol-origin: margin;
22 | left: 10px;
23 | padding: 0 3px 0 3px;
24 | }
25 | QGroupBox {
26 | border: 1px solid gray;
27 | border-radius: 9px;
28 | margin-top: 0.5em;
29 | }
30 | """)
31 | '''attr'''
32 | # GUI components
33 | self.pn_content = QWidget()
34 | self.pn_main = QStackedWidget()
35 | self.pn_navi = QWidget()
36 | self.bt_next = QPushButton()
37 | self.bt_back = QPushButton()
38 | self.Layout = None
39 | # params
40 | self.params = dict()
41 | # image-related
42 | self.img_raw = None
43 | self.img_crop = None
44 | self.img_bin = None
45 | self.k_center = None
46 | # info-=-
47 | self.title = "GRID"
48 | self.width = 1440
49 | self.height = 900
50 | '''initialize UI'''
51 | self.initUI()
52 | def initUI(self):
53 | self.setWindowTitle(self.title)
54 | self.setMinimumSize(self.width, self.height)
55 | '''first input'''
56 | self.show_input()
57 | '''set up windows'''
58 | center = QApplication.desktop().availableGeometry().center()
59 | rect = self.geometry()
60 | rect.moveCenter(center)
61 | self.setGeometry(rect)
62 | def show_input(self, isNewImg=True):
63 | '''input panel'''
64 | if isNewImg:
65 | self.pn_main.addWidget(Panel_Input())
66 | else:
67 | self.pn_main.removeWidget(self.pn_main.widget(Panels.CROPPER.value))
68 | self.pn_main.setCurrentIndex(Panels.INPUT.value)
69 | '''navigation bar'''
70 | self.assemble_navigation(name_next="Load Files ->", oneSide=True)
71 | self.bt_next.clicked.connect(lambda: self.show_cropper(isNewImg=True))
72 | '''finalize'''
73 | self.assemble_and_show()
74 | def show_cropper(self, isNewImg=True):
75 | '''input panel'''
76 | if isNewImg:
77 | self.params['raw'], self.params['map'] = self.pn_main.widget(Panels.INPUT.value).get_img()
78 | self.pn_main.addWidget(Panel_Cropper(np_img=self.params['raw']))
79 | else:
80 | self.pn_main.removeWidget(self.pn_main.widget(Panels.KMEANER.value))
81 | self.pn_main.setCurrentIndex(Panels.CROPPER.value)
82 | '''navigation bar'''
83 | self.assemble_navigation()
84 | self.bt_back.clicked.connect(lambda: self.show_input(isNewImg=False))
85 | self.bt_next.clicked.connect(lambda: self.show_kmeaner(isNewImg=True))
86 | '''finalize'''
87 | self.assemble_and_show()
88 | def show_kmeaner(self, isNewImg=True):
89 | '''input panel'''
90 | if isNewImg:
91 | self.params['crop'] = self.pn_main.widget(Panels.CROPPER.value).get_img()
92 | self.pn_main.addWidget(Panel_Kmeaner(np_img=self.params['crop']))
93 | else:
94 | self.pn_main.removeWidget(self.pn_main.widget(Panels.ANCHOR.value))
95 | self.pn_main.setCurrentIndex(Panels.KMEANER.value)
96 | '''navigation bar'''
97 | self.assemble_navigation()
98 | self.bt_back.clicked.connect(lambda: self.show_cropper(isNewImg=False))
99 | self.bt_next.clicked.connect(lambda: self.show_anchor(isNewImg=True))
100 | '''finalize'''
101 | self.assemble_and_show()
102 | def show_anchor(self, isNewImg=True):
103 | '''input panel'''
104 | if isNewImg:
105 | self.params['crop'], self.params['k'], self.params['bin'], self.params['ch_nir'], self.params['ch_red'], self.params['ls_bin'] = self.pn_main.widget(Panels.KMEANER.value).get_img()
106 | self.pn_main.addWidget(Panel_Anchor(img=self.params['bin'], map=self.params['map']))
107 | else:
108 | self.pn_main.removeWidget(self.pn_main.widget(Panels.OUTPUT.value))
109 | self.pn_main.setCurrentIndex(Panels.ANCHOR.value)
110 | '''navigation bar'''
111 | self.assemble_navigation()
112 | self.bt_back.clicked.connect(lambda: self.show_kmeaner(isNewImg=False))
113 | self.bt_next.clicked.connect(lambda: self.show_output(isNewImg=True))
114 | '''finalize'''
115 | self.assemble_and_show()
116 | def show_output(self, isNewImg=True):
117 | '''input panel'''
118 | if isNewImg:
119 | self.params['anchors'], self.params['nc'], self.params['nr'] = self.pn_main.widget(Panels.ANCHOR.value).get_anchors()
120 | self.pn_main.addWidget(Panel_Output(**self.params))
121 | self.pn_main.setCurrentIndex(Panels.OUTPUT.value)
122 | # test
123 | self.test()
124 | # test
125 | '''navigation bar'''
126 | self.assemble_navigation(name_next="Finish")
127 | self.bt_back.clicked.connect(lambda: self.show_anchor(isNewImg=False))
128 | self.bt_next.clicked.connect(self.finish)
129 | '''finalize'''
130 | self.assemble_and_show()
131 | def finish(self):
132 | msgBox = QMessageBox()
133 | msgBox.setIcon(QMessageBox.Information)
134 | msgBox.setText("Start another job?")
135 | msgBox.setWindowTitle("Finish")
136 | msgBox.setStandardButtons(QMessageBox.Cancel | QMessageBox.Yes | QMessageBox.Save)
137 | returnValue = msgBox.exec()
138 | if returnValue == QMessageBox.Yes:
139 | self.pn_main.widget(Panels.OUTPUT.value).output()
140 | self.show_input()
141 | elif returnValue == QMessageBox.Save:
142 | self.pn_main.widget(Panels.OUTPUT.value).output()
143 | self.show_output(isNewImg=False)
144 | def assemble_navigation(self, name_next="Next ->", name_back="<- Back", oneSide=False):
145 | self.pn_navi = QWidget()
146 | self.bt_next = QPushButton(name_next)
147 | self.bt_back = QPushButton(name_back)
148 | layout_navi = QHBoxLayout()
149 | if oneSide:
150 | layout_navi.addStretch(1)
151 | else:
152 | layout_navi.addWidget(self.bt_back)
153 | layout_navi.addWidget(self.bt_next)
154 | self.pn_navi.setLayout(layout_navi)
155 | def assemble_and_show(self):
156 | self.Layout = QVBoxLayout()
157 | self.Layout.addWidget(self.pn_main, Qt.AlignCenter)
158 | self.Layout.addWidget(self.pn_navi)
159 | self.pn_content = QWidget()
160 | self.pn_content.setLayout(self.Layout)
161 | self.setCentralWidget(self.pn_content)
162 | self.show()
163 | def test(self):
164 | import json
165 | with open('anchors', 'w') as fout:
166 | json.dump(self.params['anchors'], fout)
167 | np.save("img_crop", self.params['crop'])
168 | np.save("img_bin", self.params['bin'])
169 | np.save("map", self.params['map'])
170 | np.save("img_k", self.params['k'])
171 | np.save("ls_bin", self.params['ls_bin'])
172 | print("nc:%d"%(self.params['nc']))
173 | print("nr:%d"%(self.params['nr']))
174 |
--------------------------------------------------------------------------------
/grid/archive/test.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import sys
3 | import grid as gd
4 | import pandas as pd
5 | import numpy as np
6 |
7 | import matplotlib.pyplot as plt
8 | from matplotlib import patches
9 | from matplotlib.lines import Line2D
10 | # 3rd party imports
11 | from PyQt5.QtWidgets import *
12 | from PyQt5.QtCore import *
13 | from PyQt5.QtGui import *
14 |
15 | from grid.gridGUI import *
16 |
17 |
18 | grid = gd.GRID()
19 | grid.loadData("/Users/jameschen/Dropbox/UAV/James/Alfalfa/20190505RGB_RDNIR_H.tif")
20 | grid.cropImg()
21 |
22 | grid.binarizeImg(k=3, lsSelect=[0])
23 | grid.imgs.get("crop")
24 |
25 | # grid.loadData("/Users/jameschen/Dropbox/James Chen/GRID/Modeling/Rhombus.jpg")
26 | grid.loadData("/Users/jameschen/demo.png", pathMap="/Users/jameschen/demo.csv")
27 | grid.binarizeImg(k=3, lsSelect=[0])
28 | grid.findPlots()
29 | grid.cpuSeg(outplot=False)
30 |
31 | grid.save()
32 |
33 | dt_TE = grid.getDfIndex(ch_1=3, ch_2=0, isContrast=True, name_index="ttt")
34 | dt_org = grid.map.dt
35 |
36 | dt_TE[:10]
37 | dt_org[:10]
38 | dt_TE['var']
39 | dt_org['var']
40 | pd.merge(dt_org, dt_TE, on='var', how='left')
41 |
42 |
43 | # find best angle
44 | # plot
45 | grid = gd.GRID()
46 | grid.loadData("/Users/jameschen/Dropbox/James Chen/GRID/Prototype/Rhombus Pumptree.jpg")
47 | grid.binarizeImg(k=5, lsSelect=[3, 4], valShad=0, valSmth=3, outplot=True)
48 | grid.findPlots(nCol=5, nRow=6, nSmooth=0, outplot=True)
49 | grid.map.angles
50 | plt.imshow(grid.map.imgs[1])
51 | plt.plot(grid.map.imgs[1].sum(axis=0))
52 | plt.show()
53 |
54 | signal = grid.map.imgs[1].mean(axis=0)
55 | # gaussian smooth
56 | for i in range(3):
57 | signal = np.convolve(
58 | np.array([1, 2, 4, 2, 1])/10, signal, mode='same')
59 | peaks, _ = find_peaks(signal)
60 | peaks
61 | plt.plot(signal)
62 | plt.show()
63 |
64 |
65 | app = QApplication(sys.argv)
66 | grid = PnAnchor(grid)
67 |
68 |
69 |
70 | # TEST code
71 | # cp -r grid/* env/lib/python3.6/site-packages/grid/ | python3 -m grid
72 |
73 | # GUI TEST
74 | grid = gd.GRID()
75 | grid.loadData(
76 | "/Users/jameschen/Dropbox/James_Git/FN/data/demo.png")
77 | grid.binarizeImg(k=3, lsSelect=[0, 1], valShad=0, valSmth=0, outplot=False)
78 | app = QApplication(sys.argv)
79 | grid = PnAnchor(grid)
80 |
81 |
82 | # ZZ FINAL TEST
83 | grid = gd.GRID()
84 | grid.loadData(
85 | "/Users/jameschen/Dropbox/James Chen/GRID/Prototype/F5SAS_Overview.jpg")
86 | grid.binarizeImg(k=9, lsSelect=[0,1,2,3], valShad=0, valSmth=10, outplot=True)
87 | grid.findPlots(outplot=True)
88 | grid.cpuSeg(outplot=True)
89 |
90 |
91 |
92 | grid = gd.GRID()
93 | grid.loadData(
94 | "/Users/jameschen/Dropbox/James_Git/FN/data/demo.png")
95 | grid.binarizeImg(k=3, lsSelect=[0, 1], valShad=0, valSmth=0, outplot=True)
96 | grid.findPlots(outplot=True)
97 | grid.cpuSeg(outplot=True)
98 |
99 | grid = gd.GRID()
100 | grid.loadData("/Users/jameschen/Dropbox/James Chen/GRID/Modeling/Rhombus.jpg")
101 | grid.binarizeImg(k=5, lsSelect=[4], valShad=0, valSmth=0, outplot=False)
102 | grid.findPlots(outplot=False)
103 |
104 |
105 | grid.cpuSeg(outplot=True)
106 |
107 |
108 | img = grid.imgs.get("binSeg")
109 |
110 | def rotateBinNdArray(img, angel):
111 | # create border for the image
112 | img[:, 0] = 1
113 | img[0, :] = 1
114 | img[:, -1] = 1
115 | img[-1, :] = 1
116 |
117 | # padding
118 | sizePad = max(img.shape)
119 | imgP = np.pad(img, [sizePad, sizePad], 'constant')
120 |
121 | # rotate
122 | pivot = tuple((np.array(imgP.shape[:2])/2).astype(int))
123 | matRot = cv2.getRotationMatrix2D(pivot, angel, 1.0)
124 | imgR = cv2.warpAffine(
125 | imgP.astype(np.float32), matRot, imgP.shape, flags=cv2.INTER_LINEAR).astype(np.int8)
126 |
127 | # crop
128 | sigX = np.where(imgR.sum(axis=0)!=0)[0]
129 | sigY = np.where(imgR.sum(axis=1)!=0)[0]
130 | imgC = imgR[sigY[0]:sigY[-1], sigX[0]:sigX[-1]]
131 |
132 | # return
133 | return imgC
134 |
135 | angel = 60
136 | imgR = rotateBinNdArray(img, angel)
137 | ictA = gd.findPeaks(imgR, axis=1)[0] * (1/np.sin(np.pi/180*angel))
138 | slpA = -1/np.tan(np.pi/180*angel)
139 |
140 |
141 |
142 |
143 |
144 | plt.imshow(img)
145 |
146 | def
147 | for intercept in ictA:
148 | axes = plt.gca()
149 | x_vals = np.array(axes.get_xlim())
150 | y_vals = intercept + slpA * x_vals
151 | plt.plot(x_vals, y_vals, '--')
152 |
153 | plt.show()
154 |
155 |
156 |
157 | plt.plot(imgR.mean(axis=0))
158 | plt.show()
159 | plt.imshow(imgR)
160 | plt.show()
161 |
162 |
163 |
164 | def getFourierTransform(sig):
165 | sigf = np.fft.fft(sig)/len(sig)
166 | # return sigf[2:int(len(sigf)/2)]
167 | return sigf[2:25]
168 |
169 | import math
170 |
171 | math.degrees(np.pi/180)
172 |
173 | def getCardY(value, deg):
174 | return value * (np.cos(np.pi/180*deg))
175 |
176 |
177 | getCardY(4, deg=30)
178 |
179 |
180 |
181 | np.tan(np.pi/180*45)
182 |
183 |
184 | lsPxRow, _ = findPeaks(GImg.get("binSeg"), nPeaks=self.nRow, axis=0, nSmooth=nSmooth)
185 |
186 |
187 | row = 9
188 | col = 3
189 | degs = []
190 | sigs = []
191 | maxs = []
192 | for i in range(row):
193 | deg = i*15
194 | degs.append(deg)
195 | imgr = rotateBinNdArray(img, deg)
196 | sigr = imgr.mean(axis=0)
197 | sigrf = getFourierTransform(sigr)
198 | sigabs = abs(sigrf)
199 | plt.subplot(row, col, 1+i*col+0)
200 | plt.imshow(imgr)
201 | plt.subplot(row, col, 1+i*col+1)
202 | plt.plot(sigr)
203 | plt.subplot(row, col, 1+i*col+2)
204 | plt.ylim(0, 0.15)
205 | plt.plot(sigabs)
206 | sigs.append(round(sum(sigabs), 2))
207 | maxs.append(round(max(sigabs), 2))
208 |
209 | print(degs)
210 | print(sigs)
211 | print(maxs)
212 | plt.show()
213 |
214 |
215 |
216 | ########
217 |
218 | pil = Image.fromarray(np.uint8(img*255))
219 |
220 | plt.imshow(pil.rotate(45))
221 | plt.show()
222 |
223 | npimg = np.asarray(pil.rotate(45), dtype=np.uint8)/255
224 | plt.imshow(npimg)
225 | plt.show()
226 |
227 | # rotate
228 | rotation_matrix = cv2.getRotationMatrix2D((num_cols/2, num_rows/2), 30, 1)
229 | img_rotation = cv2.warpAffine(img, rotation_matrix, (num_cols, num_rows))
230 | cv2.imshow('Rotation', img_rotation)
231 | cv2.waitKey()
232 |
233 |
234 | num_rows, num_cols = img.shape[:2]
235 |
236 | translation_matrix = np.float32(
237 | [[1, 0, int(0.5*num_cols)], [0, 1, int(0.5*num_rows)]])
238 |
239 | rotation_matrix=cv2.getRotationMatrix2D((num_cols, num_rows), 30, img_translation=cv2.warpAffine(img, translation_matrix, 1))
240 |
241 | img_rotation = cv2.warpAffine(img_translation, rotation_matrix, (2*num_cols, 2*num_rows))
242 |
243 | cv2.imshow('Rotation', img_rotation)
244 | cv2.waitKey()
245 |
246 |
247 |
248 |
249 |
250 | grid = gd.GRID()
251 | grid.run(pathImg="/Users/jameschen/Dropbox/James_Git/FN/data/demo.png",
252 | lsSelect=[0, 1], valShad=0, valSmth=5,
253 | nRow=11, nCol=7)
254 | grid.output()
255 |
256 | grid = gd.GRID()
257 | grid.run(pathImg="/Users/jameschen/Dropbox/James_Git/FN/data/demo.png",
258 | preset="/Users/jameschen/GRID.grid", outplot=True)
259 |
260 | grid = gd.GRID()
261 |
262 |
263 |
264 |
265 |
266 |
267 | grid.findPlots(nRow=11, nCol=7, plot=True)
268 | grid.cpuSeg(plot=True)
269 |
270 | # display seg
271 | # Create figure and axes
272 | fig, ax = plt.subplots(1)
273 | # Display the image
274 | ax.imshow(grid.imgs.get('visSeg'))
275 | for row in range(11):
276 | for col in range(7):
277 | recAg = grid.agents.get(row=row, col=col).getQRect()
278 | rect = patches.Rectangle(
279 | (recAg.x(), recAg.y()), recAg.width(), recAg.height(),
280 | linewidth=1, edgecolor='r', facecolor='none')
281 | ax.add_patch(rect)
282 |
283 | plt.show()
284 |
285 | # preview for fin
286 | fig, ax = plt.subplots()
287 | ax.imshow(grid.imgs.get('visSeg'))
288 | for row in range(11):
289 | for col in range(7):
290 | agent = grid.agents.get(row=row, col=col)
291 | recAg = agent.getQRect()
292 | line1, line2 = pltCross(agent.x, agent.y, width=1)
293 | rect = patches.Rectangle(
294 | (recAg.x(), recAg.y()), recAg.width(), recAg.height(),
295 | linewidth=1, edgecolor='r', facecolor='none')
296 | ax.add_line(line1)
297 | ax.add_line(line2)
298 | ax.add_patch(rect)
299 |
300 | plt.show()
301 |
302 | plt.imshow(grid.imgs.get("raw"))
303 |
304 | pltImShow(grid.imgs.get("raw"))
305 |
306 | pltSegPlot(grid.agents, grid.imgs.get("visSeg"))
307 |
308 |
309 | def test(a, b, c=0):
310 | return a+b+c
311 |
312 | parm = {
313 | "a":1,
314 | "b":3,
315 | "c":4,
316 | "d":5,
317 | }
318 |
319 | test(**parm)
320 |
--------------------------------------------------------------------------------
/grid/archive/test.r:
--------------------------------------------------------------------------------
1 | required_pkg = c("MASS", "LDheatmap", "genetics", "EMMREML", "biganalytics",
2 | "ape", "bigmemory", "gplots", "compiler", "scatterplot3d",
3 | "R.utils", "data.table", "magrittr", "ggplot2", "rrBLUP", "BGLR")
4 | missing_pkg = required_pkg[!(required_pkg %in% installed.packages()[,"Package"])]
5 | if(length(missing_pkg))
6 | install.packages(missing_pkg, repos="http://cran.rstudio.com/")
7 |
8 | tryCatch({
9 | # for R 3.5 and above
10 | if (!requireNamespace("BiocManager", quietly = TRUE))
11 | install.packages("BiocManager")
12 | BiocManager::install("multtest")
13 | BiocManager::install("snpStats")
14 | }, error = function(e) {
15 | # for earlier version of R (< 3.5)
16 | source("http://www.bioconductor.org/biocLite.R")
17 | biocLite("multtest")
18 | biocLite("snpStats")
19 | })
20 |
--------------------------------------------------------------------------------
/grid/archive/testAnchor.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import sys
3 | import grid as gd
4 | import pandas as pd
5 | import numpy as np
6 |
7 | import matplotlib.pyplot as plt
8 | from matplotlib import patches
9 | from matplotlib.lines import Line2D
10 | # 3rd party imports
11 | from PyQt5.QtWidgets import *
12 | from PyQt5.QtCore import *
13 | from PyQt5.QtGui import *
14 |
15 | # GUI TEST
16 | grid = gd.GRID()
17 | grid.loadData(
18 | "/Users/jameschen/Dropbox/James_Git/FN/data/demo.png")
19 | grid.binarizeImg(k=3, lsSelect=[0, 1], valShad=0, valSmth=0, outplot=False)
20 | app = QApplication(sys.argv)
21 | grid = PnAnchor(grid)
22 |
--------------------------------------------------------------------------------
/grid/archive/testFindAngel.py:
--------------------------------------------------------------------------------
1 | import timeit
2 | import math
3 | import cv2
4 | import grid as gd
5 | import pandas as pd
6 |
7 | import matplotlib.pyplot as plt
8 | from matplotlib import patches
9 | from matplotlib.lines import Line2D
10 |
11 |
12 | # find best angle
13 | import numpy as np
14 |
15 | grid = gd.GRID()
16 | # grid.loadData(
17 | # "/Users/jameschen/Dropbox/James_Git/FN/data/demo.png")
18 | grid.loadData("/Users/jameschen/Dropbox/James Chen/GRID/Modeling/Rhombus.jpg")
19 | grid.binarizeImg(k=5, lsSelect=[4], valShad=0, valSmth=0, outplot=False)
20 | grid.findPlots(outplot=False)
21 | grid.cpuSeg(outplot=True)
22 |
23 | gd.pltSegPlot(grid.agents, grid.imgs.get("visSeg"), isRect=True)
24 |
25 | dt = grid.map.dt
26 | grid.map.nRow
27 | grid.map.nCol
28 |
29 | entry = dt[(dt.row == 0) & (dt.col == 1)].iloc[0]
30 | co = (dt.row == 0) & (dt.col == 1)
31 |
32 | entry["row"]
33 | entry["pt"]
34 |
35 | grid.cpuSeg(outplot=True)
36 |
37 |
38 | img = grid.imgs.get("binSeg")
39 |
40 |
41 | def rotateBinNdArray(img, angel):
42 | # create border for the image
43 | img[:, 0] = 1
44 | img[0, :] = 1
45 | img[:, -1] = 1
46 | img[-1, :] = 1
47 |
48 | # padding
49 | sizePad = max(img.shape)
50 | imgP = np.pad(img, [sizePad, sizePad], "constant")
51 |
52 | # rotate
53 | pivot = tuple((np.array(imgP.shape[:2]) / 2).astype(int))
54 | matRot = cv2.getRotationMatrix2D(pivot, angel, 1.0)
55 | imgR = cv2.warpAffine(
56 | imgP.astype(np.float32), matRot, imgP.shape, flags=cv2.INTER_LINEAR
57 | ).astype(np.int8)
58 |
59 | # crop
60 | sigX = np.where(imgR.sum(axis=0) != 0)[0]
61 | sigY = np.where(imgR.sum(axis=1) != 0)[0]
62 | imgC = imgR[sigY[0] : sigY[-1], sigX[0] : sigX[-1]]
63 |
64 | # return
65 | return imgC
66 |
67 |
68 | def getFourierTransform(sig):
69 | sigf = abs(np.fft.fft(sig) / len(sig))
70 | return sigf[2 : int(len(sigf) / 2)]
71 | # return sigf[2:25]
72 |
73 |
74 | def getCardIntercept(lsValues, angel):
75 | coef = 1 if angel == 0 else (1 / np.sin(np.pi / 180 * angel))
76 | return lsValues * coef
77 |
78 |
79 | def getLineABC(slope, intercept):
80 | if np.isinf(slope):
81 | A = 1
82 | B = 0
83 | C = intercept
84 | else:
85 | A = slope
86 | B = -1
87 | C = -intercept
88 | return A, B, C
89 |
90 |
91 | def solveLines(slope1, intercept1, slope2, intercept2):
92 | A1, B1, C1 = getLineABC(slope1, intercept1)
93 | A2, B2, C2 = getLineABC(slope2, intercept2)
94 | D = A1 * B2 - A2 * B1
95 | Dx = C1 * B2 - B1 * C2
96 | Dy = A1 * C2 - C1 * A2
97 | if D != 0:
98 | x, y = Dx / D, Dy / D
99 | return x, y
100 | else:
101 | return False
102 |
103 |
104 | img = grid.imgs.get("binSeg")
105 |
106 | degRot = range(0, 90 + 1, 15)
107 |
108 | # find 2 axes
109 | sc = []
110 | for angel in degRot:
111 | imgR = rotateBinNdArray(img, angel)
112 | sig = imgR.mean(axis=0)
113 | sigFour = getFourierTransform(sig)
114 | sc.append(max(sigFour))
115 |
116 |
117 | def plotLine(axes, slope, intercept):
118 | if abs(slope) > 1e9:
119 | # vertical line
120 | y_vals = np.array(axes.get_ylim())
121 | x_vals = np.repeat(intercept, len(y_vals))
122 | else:
123 | # usual line
124 | x_vals = np.array(axes.get_xlim())
125 | y_vals = intercept + slope * x_vals
126 | axes.plot(x_vals, y_vals, "--", color="red")
127 |
128 |
129 | def pltCross(x, y, size=3, width=1, color="red"):
130 | pt1X = [x - size, x + size]
131 | pt1Y = [y - size, y + size]
132 | line1 = Line2D(pt1X, pt1Y, linewidth=width, color=color)
133 | pt2X = [x - size, x + size]
134 | pt2Y = [y + size, y - size]
135 | line2 = Line2D(pt2X, pt2Y, linewidth=width, color=color)
136 | return line1, line2
137 |
138 |
139 | # plotting
140 | fig, ax = plt.subplots()
141 | ax.imshow(img)
142 | for i in range(2):
143 | for intercept in intercepts[i]:
144 | plotLine(ax, slopes[i], intercept)
145 | for pt in pts:
146 | line1, line2 = pltCross(pt[0], pt[1], width=1)
147 | ax.add_line(line1)
148 | ax.add_line(line2)
149 |
150 | plt.show()
151 |
152 |
153 | # DEMO
154 | row = 9
155 | col = 3
156 | degs = []
157 | sigs = []
158 | maxs = []
159 | for i in range(row):
160 | deg = i * 15
161 | degs.append(deg)
162 | imgr = rotateBinNdArray(img, deg)
163 | sigr = imgr.mean(axis=0)
164 | sigrf = getFourierTransform(sigr)
165 | sigabs = abs(sigrf)
166 | plt.subplot(row, col, 1 + i * col + 0)
167 | plt.imshow(imgr)
168 | plt.subplot(row, col, 1 + i * col + 1)
169 | plt.plot(sigr)
170 | plt.subplot(row, col, 1 + i * col + 2)
171 | plt.ylim(0, 0.15)
172 | plt.plot(sigabs)
173 | sigs.append(round(sum(sigabs), 2))
174 | maxs.append(round(max(sigabs), 2))
175 |
176 | print(degs)
177 | print(sigs)
178 | print(maxs)
179 | plt.show()
180 |
--------------------------------------------------------------------------------
/grid/archive/testRecoverSize.py:
--------------------------------------------------------------------------------
1 | import math
2 | import cv2
3 | import os
4 | import sys
5 | import grid as gd
6 | import pandas as pd
7 | import numpy as np
8 |
9 | import matplotlib.pyplot as plt
10 | from matplotlib import patches
11 | from matplotlib.lines import Line2D
12 |
13 |
14 | # seedling "/Users/jameschen/Dropbox/photo_grid/test/pheno/lsh_20200223.tif"
15 | # [[7931.0036832412525, 6546.418047882136], [6971.510128913444, 8684.02394106814],
16 | # [2295.497237569061, 6595.0], [3218.5543278084715, 4408.812154696133]]
17 | # matured "/Users/jameschen/Dropbox/photo_grid/test/pheno/lsh_20200331.tif"
18 | # [[5450.830570902393, 4299.983425414364], [7668.826887661141, 5293.896869244935],
19 | # [6706.300184162062, 7407.270718232044], [4519.690607734807, 6455.206261510129]]
20 |
21 |
22 | grid = gd.GRID()
23 | grid.loadData(
24 | "/Users/jameschen/Dropbox/photo_grid/test/pheno/lsh_20200223.tif")
25 | pts = np.array([[7931.0036832412525, 6546.418047882136, 1],
26 | [6971.510128913444, 8684.02394106814, 1],
27 | [2295.497237569061, 6595.0, 1],
28 | [3218.5543278084715, 4408.812154696133, 1]], dtype=np.float32)
29 | grid.cropImg(pts=pts)
30 |
31 | grid.binarizeImg(k=3, lsSelect=[0, 1], valShad=0, valSmth=0, outplot=False)
32 |
33 | img = grid.imgs.get("crop")
34 |
35 | shape = img.shape
36 |
37 |
38 | pts = np.array([[7931.0036832412525, 6546.418047882136, 1],
39 | [6971.510128913444, 8684.02394106814, 1],
40 | [2295.497237569061, 6595.0, 1],
41 | [3218.5543278084715, 4408.812154696133, 1]], dtype=np.float32)
42 |
43 | pts2 = np.float32([[0, 0, 1],
44 | [shape[0], 0, 1],
45 | [0, shape[1], 1],
46 | [shape[0], shape[1], 1]])
47 |
48 |
49 | pts = np.array([[7931.0036832412525, 6546.418047882136],
50 | [6971.510128913444, 8684.02394106814],
51 | [2295.497237569061, 6595.0],
52 | [3218.5543278084715, 4408.812154696133]], dtype=np.float32)
53 |
54 | pts2 = np.float32([[0, 0],
55 | [shape[0], 0],
56 | [0, shape[1]],
57 | [shape[0], shape[1]]])
58 |
59 | M = cv2.getPerspectiveTransform(pts2, pts)
60 |
61 | np.matmul(M, pts2.transpose()).transpose()
62 | pts
63 |
64 | pts.shape
65 | M.shape
66 |
67 |
68 | st = cv2.warpPerspective(img, M, (shape[0], shape[1]))
69 |
70 | dst.shape
71 | dst = np.array(dst).astype(np.uint8)
72 |
73 | #######
74 | pts1 = np.float32([[200, 200], [600, 300],
75 | [100, 800], [500, 900]])
76 | pts13 = np.float32([[200, 200, 1], [600, 300, 1],
77 | [100, 800, 1], [500, 900, 1]])
78 | fix = 123
79 | pts2 = np.float32([[0, 0], [fix, 0],
80 | [0, fix], [fix, fix]])
81 | pts23 = np.float32([[0, 0, 1], [fix, 0, 1],
82 | [0, fix, 1], [fix, fix, 1]])
83 |
84 | M = cv2.getPerspectiveTransform(pts1, pts2)
85 |
86 | recover_scale(pts2, M)
87 |
88 | pts2_f = np.matmul(M, pts13.transpose())
89 | pts2
90 | pts2_f.transpose()
91 |
92 | pts1_f = np.matmul(pts23, M)
93 | pts1_f
94 |
95 | app = QApplication(sys.argv)
96 | grid = PnAnchor(grid)
97 |
98 |
99 | pts1_r = np.matmul(np.linalg.inv(M), pts23.transpose()).transpose()
100 | i = 0
101 |
102 | ls = [pts1_r[i, :2] for i in range(len(pts1_r))]
103 | np.matrix(ls)
104 |
105 | pts1
106 |
107 | pts2.shape
108 | [list(pts2[i, :]) + [1] for i in range(4)]
109 | pts23.shape
110 |
111 | pts23
112 |
113 |
114 | M.shape
115 | np.linalg.inv(pts1)
116 |
117 | pts1.shape
118 |
119 |
120 | def recover_scale(mat_in, mat_H):
121 | """
122 | recover the cropped shaped into original scale
123 |
124 | parameters
125 | ----------
126 | mat_in: 4 x 2 matrix
127 | mat_H: 3 x 3 matrix
128 | """
129 |
130 | n_points = len(mat_in)
131 | # conver mat_in into 4 x 3 matrix
132 | mat_in = np.array([list(mat_in[i, :]) + [1] for i in range(4)])
133 |
134 | # solve recovered matrix
135 | mat_recover = np.matmul(np.linalg.inv(mat_H), mat_in.transpose())
136 |
137 | # transpose back to the right dimension (4 x 3)
138 | mat_recover = mat_recover.transpose()
139 |
140 | # extract the first 2 elements in each point (4 x 2)
141 | mat_recover = [mat_recover[i, :2] for i in range(n_points)]
142 |
143 | # return
144 | return np.array(np.matrix(mat_recover))
145 |
146 |
147 | pts1 = np.float32([[200, 200], [600, 300],
148 | [100, 800], [500, 900]])
149 | pts13 = np.float32([[200, 200, 1], [600, 300, 1],
150 | [100, 800, 1], [500, 900, 1]])
151 | fix = 123
152 | pts2 = np.float32([[0, 0], [fix, 0],
153 | [0, fix], [fix, fix]])
154 | pts23 = np.float32([[0, 0, 1], [fix, 0, 1],
155 | [0, fix, 1], [fix, fix, 1]])
156 |
157 | M = cv2.getPerspectiveTransform(pts1, pts2)
158 |
159 | recover_scale(pts2, M)
160 |
161 |
162 | np.rot90(pts1, 2)
163 |
164 | import math
165 |
166 | np.cos(np.pi/180*0)
167 |
168 | pts1 = np.float32([[400, 200], [600, 600],
169 | [300, 800], [500, 1200]])
170 | pts1 = np.float32([[200, 400], [800, 600],
171 | [200, 600], [800, 400]])
172 | origin = np.median(pts1, axis=0)
173 | # ptr1 = np.array([rotatePts((500, 500), pts1[i], 90) for i in range(4)])
174 | ptr1 = rotatePts(pts1, 90, (500, 500))
175 | plt.scatter(pts1.transpose()[0], pts1.transpose()[1])
176 | plt.scatter(ptr1.transpose()[0], ptr1.transpose()[1])
177 |
178 |
179 | M = cv2.getPerspectiveTransform(pts, pts2)
180 | dst = cv2.warpPerspective(img, M, (shape[0], shape[1]))
181 | transformed_points = cv2.warpPerspective(
182 | p_array, matrix, (2, 1), cv2.WARP_INVERSE_MAP)
183 |
184 | def rotatePts(pts, angle, org=(0, 0)):
185 | """
186 | ----------
187 | Parameters
188 | ----------
189 | """
190 | ox, oy = org
191 | ptx = np.array([pts[i, 0] for i in range(len(pts))])
192 | pty = np.array([pts[i, 1] for i in range(len(pts))])
193 | qx = ox + math.cos(math.radians(angle))*(ptx - ox) - \
194 | math.sin(math.radians(angle))*(pty - oy)
195 | qy = oy + math.sin(math.radians(angle))*(ptx - ox) + \
196 | math.cos(math.radians(angle))*(pty - oy)
197 | qpts = [[qx[i], qy[i]] for i in range(len(pts))]
198 | return np.array(qpts)
199 |
200 | ox, oy = origin
201 | px, py = point
202 |
203 | ag = np.pi / 180 * angle
204 | qx = ox + np.cos(ag) * (px - ox) - np.sin(ag) * (py - oy)
205 | qy = oy + np.sin(ag) * (px - ox) + np.cos(ag) * (py - oy)
206 | return qx, qy
207 |
208 |
--------------------------------------------------------------------------------
/grid/archive/test_shapefile.py:
--------------------------------------------------------------------------------
1 | from io import BytesIO as StringIO
2 | import shapefile
3 | import numpy
4 | import rasterio
5 | import rasterio.mask
6 | import fiona
7 | import os
8 |
9 | os.chdir("/Users/jameschen/Dropbox/photo_grid/test/Jacob")
10 | os.listdir()
11 |
12 |
13 | f = rasterio.open('RGB-integer.tif')
14 | f.profile
15 | f.width
16 | f.height
17 |
18 | f.bounds
19 | # BoundingBox(left=474888.6157, bottom=5140151.9396, right=474942.6952, top=5140222.4708)
20 | # ^, ->
21 | f.transform * (0, 0)
22 |
23 | [list(f.transform * pts[i]) for i in range(4)]
24 |
25 | f.transform * (f.width, f.height)
26 | f.close()
27 |
28 | with rasterio.open('RGB-integer.tif') as dataset:
29 |
30 | # Read the dataset's valid data mask as a ndarray.
31 | mask = dataset.dataset_mask()
32 |
33 | # Extract feature shapes and values from the array.
34 | for geom, val in rasterio.features.shapes(
35 | mask, transform=dataset.transform):
36 |
37 | # Transform shapes from the dataset's own coordinate
38 | # reference system to CRS84 (EPSG:4326).
39 | geom = rasterio.warp.transform_geom(
40 | dataset.crs, 'EPSG:4326', geom, precision=6)
41 |
42 | # Print GeoJSON shapes to stdout.
43 | print(geom)
44 |
45 | plt.imshow(mask)
46 | geom['type']
47 | list(geom)
48 |
49 |
50 | os.chdir("/Users/jameschen/Dropbox/photo_grid/data/shapefile")
51 |
52 | file_sf = shapefile.Reader("IPNI_N_Trial_overlay.shp")
53 | file_fi = fiona.open("IPNI_N_Trial_overlay.shp", "r")
54 | len(file_sf)
55 | i = 150
56 | file_fi[i]
57 |
58 | file_sf.record(0)
59 | rec = file_sf.shapeRecords()
60 | rec[i].__dict__
61 | rec[i].record
62 | rec[i].shape.points
63 | rec[i].shape.__dict__
64 |
65 |
66 | file_sf[i].point
67 | file_sf.bbox
68 | print(file_sf)
69 |
70 | # writer
71 | w = shapefile.Writer("test")
72 | w.field('id', 'C', 20, 20)
73 | w.field("mean", 'N', 8, 3)
74 | # w.field('name2', 'C')
75 | w.poly([[[122, 37], [117, 36], [115, 32], [118, 20], [113, 24]]])
76 | w.record(**dict({'id': 'polygon2', "mean": 3.525}))
77 | w.poly([[[122, 37], [118, 36], [105, 32], [118, 23], [113, 24]]])
78 | w.record(**dict({'id': 'polygon2', "mean": 3.525}))
79 | w.close()
80 |
81 | r = shapefile.Reader('test')
82 | r.record(0)
83 | r.shapeRecords()[0].shape.points
84 | r.record(1)
85 |
86 | r.close()
87 |
88 | r.__dict__
89 |
90 |
91 | # fiona
92 | ftest = fiona.open("/Users/jameschen/GRID.shp", "r")
93 | ftest.__dict__
94 | ftest[0]
95 | ftest.close()
96 |
97 | file_fi.__dict__
98 | np.array(file_fi[0]["geometry"]["coordinates"][0]).round()
99 |
100 |
101 | ######
102 |
103 | # imports
104 | from scipy.stats import pearsonr
105 | from sklearn.linear_model import LogisticRegressionCV, LogisticRegression
106 | from sklearn.datasets import load_iris
107 | from sklearn.mixture import GaussianMixture
108 | from matplotlib.path import Path
109 | from sklearn.cluster import KMeans
110 | from scipy.signal import find_peaks
111 | from scipy.signal import convolve2d
112 | import grid as gd
113 | from PIL import Image
114 | import os
115 | import sys
116 | import numpy as np
117 | import pandas as pd
118 | import h5py as h5
119 | import cv2
120 | import random
121 | import warnings
122 | import matplotlib.pyplot as plt
123 | import matplotlib.patches as patches
124 | import math
125 |
126 | warnings.filterwarnings("ignore")
127 |
128 | # global params
129 | _RGB = (68, 51, 17)
130 | _HOME = os.path.expanduser("~")
131 |
132 | # self imports
133 | os.chdir(os.path.join(_HOME, "Dropbox", "James_Git"))
134 | import os
135 | os.chdir("..")
136 | sys.path
137 | sys.path.remove("/Users/jameschen/Dropbox/photo_grid/grid")
138 | import grid as gd
139 |
140 | # load image
141 | grid = gd.GRID()
142 | grid.loadData(
143 | "/Users/jameschen/Dropbox/James Chen/Projects/GRID/Prototype/GRID_Demo_Croped.jpg")
144 | grid.binarizeImg(k=3, features=[0, 1],
145 | lsSelect=[0],
146 | valShad=10, valSmth=5, outplot=True)
147 | grid.findPlots(nRow=23, nCol=12)
148 | grid.cpuSeg(outplot=True)
149 |
150 | grid.save(prefix="test")
151 |
152 |
153 | imgH = grid.map.imgH
154 | imgW = grid.map.imgW
155 |
156 | dt = pd.read_csv("~/test_data.csv")
157 | cols = dt.columns
158 |
159 | for col in cols:
160 | instance = dt[col][0]
161 |
162 | if isinstance(instance, object):
163 | # characters
164 | mode = "C"
165 | arg1, arg2 = 20, 20
166 | else:
167 | # integer, floating
168 | mode = "N"
169 | arg1, arg2 = 10, 10
170 |
171 | f.field(col, mode, arg1, arg2)
172 |
173 | for idx, entry in dt.iterrows():
174 | # get agents
175 | row = entry["row"]
176 | col = entry["col"]
177 | agent = grid.agents.get(row, col)
178 |
179 | # polygon
180 | bN = imgH - agent.border["NORTH"]
181 | bW = agent.border["WEST"]
182 | bS = imgH - agent.border["SOUTH"]
183 | bE = agent.border["EAST"]
184 | f.poly([[[bW, bN], [bE, bN], [bE, bS], [bW, bS], [bW, bN]]])
185 |
186 | # attributes
187 | dc = {c: entry[c] for c in dt.columns}
188 | f.record(**dict(dc))
189 |
190 |
191 |
--------------------------------------------------------------------------------
/grid/archive/thread.py:
--------------------------------------------------------------------------------
1 |
2 | class Prog(QWidget):
3 | def __init__(self):
4 | super().__init__()
5 | layout = QVBoxLayout(self)
6 |
7 | # Create a progress bar and a button and add them to the main layout
8 | self.progressBar = QProgressBar(self)
9 | self.progressBar.setRange(0, 5)
10 | layout.addWidget(self.progressBar)
11 | button = QPushButton("Start", self)
12 | layout.addWidget(button)
13 |
14 | button.clicked.connect(self.onStart)
15 |
16 | self.myLongTask = TaskThread()
17 | self.myLongTask.taskFinished.connect(self.onFinished)
18 |
19 | def activate(self):
20 | for _ in range(5):
21 | self.onStart()
22 | time.sleep(1)
23 |
24 | def onStart(self):
25 | # self.progressBar.setRange(0,0)
26 | self.myLongTask.start()
27 |
28 | def onFinished(self):
29 | # Stop the pulsation
30 | value = self.progressBar.value()
31 | # self.progressBar.setRange(0,1)
32 | self.progressBar.setValue(value+1)
33 |
34 |
35 | class TaskThread(QThread):
36 | taskFinished = pyqtSignal()
37 |
38 | def run(self):
39 | # time.sleep(1)
40 | print("run")
41 | self.taskFinished.emit()
42 |
--------------------------------------------------------------------------------
/grid/benchmark.py:
--------------------------------------------------------------------------------
1 | import time
2 | import matplotlib.pyplot as plt
3 | import cv2
4 | import numpy as np
5 | import rasterio
6 | import os
7 | os.chdir("/Users/jameschen/Dropbox/photo_grid")
8 | import grid as gd
9 | os.chdir("/Users/jameschen/Dropbox/James Chen/GRID/Manuscript/Remote Sensing/")
10 | os.chdir("First Revision/demo/")
11 |
12 | # load the 1st demo file
13 | img = gd.loadImg("demo_1.tif")
14 |
15 |
16 | # define output function
17 | def out_diff_size(imgIn, pts, path, size):
18 | img = gd.cropImg(imgIn, pts, img_W=size, img_H=size).astype(rasterio.uint8)
19 | bands = img.shape[2]
20 | with rasterio.open(path, 'w', driver="GTiff",
21 | height=img.shape[0], width=img.shape[1],
22 | count=bands, dtype=rasterio.uint8) as dst:
23 | for i in range(bands):
24 | dst.write(img[:, :, i], i+1)
25 |
26 |
27 | # crop AOI for demo
28 | pts = [[2879.464480874317, 5707.814207650273],
29 | [5758.928961748634, 5861.158469945355],
30 | [5571.508196721311, 8945.081967213115],
31 | [2709.0819672131147, 8808.775956284153]]
32 |
33 | # output different file size of data from the same AOI
34 | out_diff_size(img, pts, "size/size_2_0gb.tif", 18500)
35 | out_diff_size(img, pts, "size/size_1_5gb.tif", 15700)
36 | out_diff_size(img, pts, "size/size_1_0gb.tif", 13000)
37 | out_diff_size(img, pts, "size/size_0_5gb.tif", 9150)
38 | out_diff_size(img, pts, "size/size_0_1gb.tif", 4100)
39 |
40 | # output different plot number of data from the same file size 500 MB
41 | # 5*10 = 50
42 | out_diff_size(img,
43 | [[2860.333586050038, 5697.028051554207],
44 | [2777.5966641395, 6985.360121304018],
45 | [4125.02653525398, 5779.764973464746],
46 | [4065.92873388931, 7044.457922668688]],
47 | "plot/plot_50.tif", 9150)
48 |
49 | # 10*10 = 100
50 | out_diff_size(img,
51 | [[2860.333586050038, 5697.028051554207],
52 | [4136.846095526915, 5767.945413191812],
53 | [3971.3722517058377, 8297.331311599697],
54 | [2730.3184230477636, 8226.413949962092]],
55 | "plot/plot_100.tif", 9150)
56 |
57 | # 10*15 = 150
58 | out_diff_size(img,
59 | [[2860.333586050038, 5708.847611827142],
60 | [2718.4988627748294, 8226.413949962092],
61 | [4621.44806671721, 8344.609552691432],
62 | [4763.282789992419, 5815.223654283548]],
63 | "plot/plot_150.tif", 9150)
64 |
65 | # 10*20 = 200
66 | out_diff_size(img,
67 | [[2848.5140257771036, 5697.028051554207],
68 | [2718.4988627748294, 8226.413949962092],
69 | [5236.06520090978, 8380.068233510236],
70 | [5401.539044730856, 5838.862774829417]],
71 | "plot/plot_200.tif", 9150)
72 |
73 |
74 | # output benchmark results for size comparison
75 | with open("benchmark_size.csv", "w") as f:
76 | f.write("size,elapse,iter\n")
77 |
78 | dic_size = {"2_0": 2,
79 | "1_5": 1.5,
80 | "1_0": 1.0,
81 | "0_5": 0.5,
82 | "0_1": 0.1}
83 |
84 | for i in range(100):
85 | for key, val in dic_size.items():
86 | # time the loading process
87 | t_cur = time.time()
88 | grid = gd.GRID()
89 | grid.loadData("size/size_%sgb.tif" % key)
90 | elapse = round(time.time() - t_cur, 4)
91 | # export results
92 | with open("benchmark_size.csv", "a") as f:
93 | f.write("%d,%.4f,%d\n" % (val, elapse, i))
94 |
95 |
96 | # output benchmark results for plots comparison
97 | with open("benchmark_plot.csv", "w") as f:
98 | f.write("plot,ep_plots,ep_seg,iter\n")
99 |
100 | dic_plot = {"50": (50, 5, 10),
101 | "100": (100, 10, 10),
102 | "150": (150, 10, 15),
103 | "200": (200, 10, 20)}
104 |
105 | for i in range(100):
106 | for key, val in dic_plot.items():
107 | nplot, nrow, ncol = val
108 | grid = gd.GRID()
109 | grid.loadData("plot/plot_%d.tif" % nplot)
110 | w, h, d = grid.imgs.get("raw").shape
111 | grid.cropImg(pts=[[0, 0], [0, w], [h, 0], [h, w]])
112 | grid.binarizeImg(k=3, lsSelect=[0], valShad=0, valSmth=0)
113 | # locate center
114 | t_cur = time.time()
115 | grid.findPlots(nRow=nrow, nCol=ncol)
116 | ep_pt = round(time.time() - t_cur, 4)
117 | # expand boundaries
118 | t_cur = time.time()
119 | grid.cpuSeg()
120 | ep_sg = round(time.time() - t_cur, 4)
121 | # export results
122 | with open("benchmark_plot.csv", "a") as f:
123 | f.write("%d,%.4f,%.4f,%d\n" % (nplot, ep_pt, ep_sg, i))
124 |
--------------------------------------------------------------------------------
/grid/benchmark.r:
--------------------------------------------------------------------------------
1 | library(ggplot2)
2 | library(magrittr)
3 | library(data.table)
4 | library(tidyr)
5 | setwd("~/Dropbox/James Chen/Projects/GRID/Manuscript/Remote Sensing/First Revision/demo")
6 |
7 | dt_plot = fread("plot/benchmark_plot.csv") %>%
8 | gather(metrics, elapse, -plot, -iter) %>% data.table()
9 | dt_size = fread("size/benchmark_size.csv")
10 |
11 |
12 |
13 | ggplot(data=dt_plot, aes(x=plot, y=elapse, group=plot)) +
14 | geom_boxplot() +
15 | facet_grid(.~metrics) +
16 | scale_y_continuous(limits=c(1.5, 3.5))
17 |
18 | ggplot(data=dt_size, aes(x=size, y=elapse, group=size)) + geom_boxplot()
19 |
--------------------------------------------------------------------------------
/grid/demo/seg_img.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/demo/seg_img.jpg
--------------------------------------------------------------------------------
/grid/dir.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 | class Dir(Enum):
4 | NORTH = 0
5 | WEST = 1
6 | SOUTH = 2
7 | EAST = 3
8 |
--------------------------------------------------------------------------------
/grid/gimage.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gimage.pyc
--------------------------------------------------------------------------------
/grid/grid.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/grid.pyc
--------------------------------------------------------------------------------
/grid/gui/__init__.py:
--------------------------------------------------------------------------------
1 | from grid.gui.inputer import *
2 | from grid.gui.cropper import *
3 | from grid.gui.kmeaner import *
4 | from grid.gui.anchor import *
5 | from grid.gui.outputer import *
6 |
--------------------------------------------------------------------------------
/grid/gui/__pycache__/__init__.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/__init__.cpython-310.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/__init__.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/__init__.cpython-37.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/__init__.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/__init__.cpython-39.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/anchor.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/anchor.cpython-310.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/anchor.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/anchor.cpython-36.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/anchor.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/anchor.cpython-37.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/anchor.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/anchor.cpython-39.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/cropper.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/cropper.cpython-310.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/cropper.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/cropper.cpython-36.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/cropper.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/cropper.cpython-37.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/cropper.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/cropper.cpython-39.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/customQt.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/customQt.cpython-310.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/customQt.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/customQt.cpython-36.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/customQt.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/customQt.cpython-37.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/customQt.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/customQt.cpython-39.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/inputer.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/inputer.cpython-310.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/inputer.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/inputer.cpython-36.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/inputer.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/inputer.cpython-37.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/inputer.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/inputer.cpython-39.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/kmeaner.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/kmeaner.cpython-310.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/kmeaner.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/kmeaner.cpython-36.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/kmeaner.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/kmeaner.cpython-37.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/kmeaner.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/kmeaner.cpython-39.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/outputer.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/outputer.cpython-310.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/outputer.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/outputer.cpython-36.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/outputer.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/outputer.cpython-37.pyc
--------------------------------------------------------------------------------
/grid/gui/__pycache__/outputer.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/gui/__pycache__/outputer.cpython-39.pyc
--------------------------------------------------------------------------------
/grid/gui/customQt.py:
--------------------------------------------------------------------------------
1 | # basic imports
2 | import numpy as np
3 | import sys
4 |
5 | # 3-rd party imports
6 | from PyQt6.QtWidgets import *
7 | from PyQt6.QtCore import *
8 | from PyQt6.QtGui import *
9 |
10 | # self import
11 | from grid.lib import *
12 |
13 |
14 | class Widget_Img(QWidget):
15 | """
16 | Will keep imgRaw, imgVis and imgQmap
17 | """
18 |
19 | def __init__(self):
20 | super().__init__()
21 | """attr"""
22 | # self.img_raw = img
23 | # self.img_vis = img[:, :, :3].copy()
24 | self.qimg = None
25 | self.isFitWidth = None
26 | self.rgX, self.rgY = (0, 0), (0, 0)
27 | self.sizeImg = (0, 0)
28 |
29 | def make_rgb_img(self, img):
30 | self.qimg = getRGBQImg(img[:, :, :3])
31 | self.updateDim()
32 |
33 | def make_bin_img(self, img):
34 | self.qimg = getBinQImg(img)
35 | self.updateDim()
36 |
37 | def make_idx8_img(self, img, k):
38 | self.qimg = getIdx8QImg(img, k)
39 | self.updateDim()
40 |
41 | def make_gray_img(self, img):
42 | self.qimg = getGrayQImg(img)
43 | self.updateDim()
44 |
45 | def updateDim(self):
46 | self.sizeImg = self.qimg.size().scaled(self.rect().size(), Qt.KeepAspectRatio)
47 | if self.sizeImg.width() == self.width():
48 | self.isFitWidth = True
49 | marginY = int((self.height() - self.sizeImg.height()) / 2)
50 | self.rgX = (0, self.sizeImg.width())
51 | self.rgY = (marginY, marginY + self.sizeImg.height())
52 | elif self.sizeImg.height() == self.height():
53 | self.isFitWidth = False
54 | marginX = int((self.width() - self.sizeImg.width()) / 2)
55 | self.rgX = (marginX, marginX + self.sizeImg.width())
56 | self.rgY = (0, self.sizeImg.height())
57 |
58 | def isInRange(self, x, y):
59 | if (
60 | x >= self.rgX[0]
61 | and x <= self.rgX[1]
62 | and y >= self.rgY[0]
63 | and y <= self.rgY[1]
64 | ):
65 | return True
66 | else:
67 | return False
68 |
69 | def getImgRange(self):
70 | return self.rgX, self.rgY
71 |
72 | def paintImage(self, painter):
73 | painter.setRenderHint(QPainter.Antialiasing, True)
74 | self.updateDim()
75 | painter.drawPixmap(
76 | self.rgX[0],
77 | self.rgY[0],
78 | self.sizeImg.width(),
79 | self.sizeImg.height(),
80 | self.qimg,
81 | )
82 |
83 |
84 | def getRGBQImg(img):
85 | h, w = img.shape[0], img.shape[1]
86 | qImg = QImage(img.astype(np.uint8).copy(), w, h, w * 3, QImage.Format_RGB888)
87 | return QPixmap(qImg)
88 |
89 |
90 | def getBinQImg(img):
91 | h, w = img.shape[0], img.shape[1]
92 | qImg = QImage(img.astype(np.uint8).copy(), w, h, w * 1, QImage.Format_Indexed8)
93 | qImg.setColor(0, qRgb(0, 0, 0))
94 | qImg.setColor(1, qRgb(241, 225, 29))
95 | return QPixmap(qImg)
96 |
97 |
98 | def getIdx8QImg(img, k):
99 | colormap = [
100 | qRgb(228, 26, 28),
101 | qRgb(55, 126, 184),
102 | qRgb(77, 175, 74),
103 | qRgb(152, 78, 163),
104 | qRgb(255, 127, 0),
105 | qRgb(255, 255, 51),
106 | qRgb(166, 86, 40),
107 | qRgb(247, 129, 191),
108 | qRgb(153, 153, 153),
109 | ]
110 | h, w = img.shape[0], img.shape[1]
111 | qImg = QImage(img.astype(np.uint8).copy(), w, h, w * 1, QImage.Format_Indexed8)
112 | for i in range(k):
113 | qImg.setColor(i, colormap[i])
114 | return QPixmap(qImg)
115 |
116 |
117 | def getGrayQImg(img):
118 | h, w = img.shape[0], img.shape[1]
119 | qImg = QImage(img.astype(np.uint8).copy(), w, h, w * 1, QImage.Format_Grayscale8)
120 | return QPixmap(qImg)
121 |
122 |
123 | def magnifying_glass(widget, pos, area=200, zoom=4):
124 | size = int(area / zoom)
125 | pixmap = widget.grab(
126 | QRect(
127 | QPoint(pos.x() - int(size / 2), pos.y() - int(size / 2)), QSize(size, size)
128 | )
129 | )
130 | try:
131 | rate_screen = size / pixmap.width()
132 | pixmap = pixmap.scaled(int(area / rate_screen), int(area / rate_screen))
133 | painter = QPainter(pixmap)
134 | "Rect"
135 | pen = QPen()
136 | pen.setWidth(2)
137 | pen.setColor(Qt.black)
138 | painter.setPen(pen)
139 | # define rect
140 | rect = QRect(QPoint(0, 0), pixmap.size() * rate_screen)
141 | # draw rect
142 | painter.drawRect(rect)
143 | """Cursor"""
144 | pen.setWidth(2)
145 | pen.setColor(Qt.red)
146 | painter.setPen(pen)
147 | size_m = 10
148 | space = 4
149 | # define lines
150 | line1 = QLine(QPoint(size_m, 0), QPoint(space, 0))
151 | line2 = QLine(QPoint(0, size_m), QPoint(0, space))
152 | line3 = QLine(QPoint(0, -space), QPoint(0, -size_m))
153 | line4 = QLine(QPoint(-size_m, 0), QPoint(-space, 0))
154 | line1.translate(pixmap.rect().center() * rate_screen - QPoint(0, 0))
155 | line2.translate(pixmap.rect().center() * rate_screen - QPoint(0, 0))
156 | line3.translate(pixmap.rect().center() * rate_screen - QPoint(0, 0))
157 | line4.translate(pixmap.rect().center() * rate_screen - QPoint(0, 0))
158 | # draw lines
159 | painter.drawLine(line1)
160 | painter.drawLine(line2)
161 | painter.drawLine(line3)
162 | painter.drawLine(line4)
163 |
164 | # # remove central
165 | # pt_center = pixmap.rect().center() * rate_screen
166 | # x, y = pt_center.x(), pt_center.y()
167 | # painter.eraseRect(QRect(x-2, y-2, 4, 4))
168 | """finish"""
169 | painter.end()
170 | cursor = QCursor(pixmap)
171 | widget.setCursor(cursor)
172 | except Exception:
173 | """not in a valid region"""
174 |
175 |
176 | def drawCross(x, y, painter, size=2):
177 | l1_st_x, l1_st_y = x - size, y - size
178 | l1_ed_x, l1_ed_y = x + size, y + size
179 | l2_st_x, l2_st_y = x - size, y + size
180 | l2_ed_x, l2_ed_y = x + size, y - size
181 | painter.drawLine(int(l1_st_x), int(l1_st_y), int(l1_ed_x), int(l1_ed_y))
182 | painter.drawLine(int(l2_st_x), int(l2_st_y), int(l2_ed_x), int(l2_ed_y))
183 |
184 |
185 | def drawTriangle(x, y, dir, painter, range=7, peak=30):
186 | path = QPainterPath()
187 | path.moveTo(x, y)
188 | if dir == "North":
189 | path.lineTo(x - range, y + peak)
190 | path.lineTo(x + range, y + peak)
191 | elif dir == "South":
192 | path.lineTo(x - range, y - peak)
193 | path.lineTo(x + range, y - peak)
194 | elif dir == "West":
195 | path.lineTo(x + peak, y - range)
196 | path.lineTo(x + peak, y + range)
197 | elif dir == "East":
198 | path.lineTo(x - peak, y - range)
199 | path.lineTo(x - peak, y + range)
200 | path.lineTo(x, y)
201 | painter.drawPath(path)
202 |
--------------------------------------------------------------------------------
/grid/gui/inputer.py:
--------------------------------------------------------------------------------
1 | # 3rd party imports
2 | from PyQt6.QtWidgets import *
3 | from PyQt6.QtCore import *
4 | from PyQt6.QtGui import *
5 |
6 | # self imports
7 | from grid.grid import *
8 |
9 |
10 | class PnInputer(QWidget):
11 | """ """
12 |
13 | def __init__(self, grid):
14 | """ """
15 |
16 | super().__init__()
17 | self.grid = grid
18 | # user define
19 | self.gr_user = QGroupBox("User's Input (You can drag and drop files)")
20 | self.lo_user = QGridLayout()
21 | self.lb_img = QLabel()
22 | self.lb_map = QLabel()
23 | self.lb_shp = QLabel()
24 | self.fd_img = DnDLineEdit()
25 | self.fd_map = DnDLineEdit()
26 | self.fd_shp = DnDLineEdit()
27 | self.bt_img = QPushButton()
28 | self.bt_map = QPushButton()
29 | self.bt_shp = QPushButton()
30 | # demo
31 | self.gr_demo = QGroupBox("Demo")
32 | self.lo_demo = QVBoxLayout()
33 | self.lb_demo = QLabel(
34 | "Will use sample files to demo the program. Or go to User Manual "
35 | )
36 | self.lb_demo.setOpenExternalLinks(True)
37 |
38 | # self
39 | self.layout = QVBoxLayout()
40 |
41 | self.initUI()
42 |
43 | def initUI(self):
44 | """ """
45 |
46 | # USER
47 | ## GUI components
48 | self.gr_user.setCheckable(True)
49 | self.gr_user.setChecked(False)
50 | self.gr_user.clicked.connect(lambda: self.toggle(self.gr_user))
51 | self.lb_img.setText("Image (.tif, .jpg, .png):")
52 | self.lb_map.setText("Map (.csv) (OPTIONAL):")
53 | self.lb_shp.setText("Shape (.shp) (OPTIONAL):")
54 | font = self.fd_img.font()
55 | font.setPointSize(25)
56 | fm = QFontMetrics(font)
57 | self.fd_img.setFixedHeight(fm.height())
58 | self.fd_map.setFixedHeight(fm.height())
59 | self.fd_shp.setFixedHeight(fm.height())
60 | self.bt_img.setText("Browse")
61 | self.bt_img.clicked.connect(self.assign_PathImg)
62 | self.bt_map.setText("Browse")
63 | self.bt_map.clicked.connect(self.assign_PathMap)
64 | self.bt_shp.setText("Browse")
65 | self.bt_shp.clicked.connect(self.assign_PathShp)
66 | ## layout
67 | self.lo_user.addWidget(self.lb_img, 0, 0)
68 | self.lo_user.addWidget(self.fd_img, 0, 1)
69 | self.lo_user.addWidget(self.bt_img, 0, 2)
70 | self.lo_user.addWidget(self.lb_map, 1, 0)
71 | self.lo_user.addWidget(self.fd_map, 1, 1)
72 | self.lo_user.addWidget(self.bt_map, 1, 2)
73 | self.lo_user.addWidget(self.lb_shp, 2, 0)
74 | self.lo_user.addWidget(self.fd_shp, 2, 1)
75 | self.lo_user.addWidget(self.bt_shp, 2, 2)
76 | self.gr_user.setLayout(self.lo_user)
77 |
78 | # DEMO
79 | ## GUI components
80 | self.gr_demo.setCheckable(True)
81 | self.gr_demo.setChecked(True)
82 | self.gr_demo.clicked.connect(lambda: self.toggle(self.gr_demo))
83 | ## layout
84 | self.lo_demo.addWidget(self.lb_demo)
85 | self.gr_demo.setLayout(self.lo_demo)
86 |
87 | # LAYOUT
88 | self.layout.setContentsMargins(200, 50, 200, 50)
89 | self.layout.addWidget(self.gr_user)
90 | self.layout.addWidget(self.gr_demo)
91 |
92 | # FINALIZE
93 | self.setLayout(self.layout)
94 | self.show()
95 |
96 | def toggle(self, groupbox):
97 | """ """
98 |
99 | if groupbox.title() == "Demo":
100 | self.gr_user.setChecked(not self.gr_user.isChecked())
101 | elif groupbox.title() != "Demo":
102 | self.gr_demo.setChecked(not self.gr_demo.isChecked())
103 |
104 | def assign_PathImg(self):
105 | """ """
106 |
107 | fileter = "Images (*.tif *.jpg *.jpeg *.png)"
108 | path = QFileDialog().getOpenFileName(self, "", "", fileter)[0]
109 | self.fd_img.setText(path)
110 |
111 | def assign_PathMap(self):
112 | """ """
113 |
114 | fileter = "Map (*.csv *.txt)"
115 | path = QFileDialog().getOpenFileName(self, "", "", fileter)[0]
116 | self.fd_map.setText(path)
117 |
118 | def assign_PathShp(self):
119 | """ """
120 |
121 | fileter = "Shape (*.shp)"
122 | path = QFileDialog().getOpenFileName(self, "", "", fileter)[0]
123 | self.fd_shp.setText(path)
124 |
125 | def run(self):
126 | """ """
127 | if self.gr_user.isChecked():
128 | self.grid.loadData(
129 | pathImg=self.fd_img.text(),
130 | pathMap=self.fd_map.text(),
131 | pathShp=self.fd_shp.text(),
132 | )
133 | else:
134 | self.grid.loadData() # load demo files
135 |
136 |
137 | class DnDLineEdit(QLineEdit):
138 | def __init__(self):
139 | super().__init__()
140 | self.setAcceptDrops(True)
141 |
142 | def dragEnterEvent(self, event):
143 | if event.mimeData().hasUrls:
144 | event.accept()
145 | else:
146 | event.ignore()
147 |
148 | def dragMoveEvent(self, event):
149 | if event.mimeData().hasUrls:
150 | event.setDropAction(Qt.CopyAction)
151 | event.accept()
152 | else:
153 | event.ignore()
154 |
155 | def dropEvent(self, event):
156 | if event.mimeData().hasUrls:
157 | event.setDropAction(Qt.CopyAction)
158 | event.accept()
159 | text = ""
160 | for url in event.mimeData().urls():
161 | text = str(url.toLocalFile())
162 | self.setText(text)
163 | else:
164 | event.ignore()
165 |
--------------------------------------------------------------------------------
/grid/guser.py:
--------------------------------------------------------------------------------
1 | import platform
2 | import os
3 |
4 |
5 | class GUser():
6 | """
7 | """
8 | def __init__(self):
9 | """
10 | """
11 | self.platform = platform.system()
12 | self.architecture = platform.architecture()[0]
13 | self.release = platform.release()
14 | self.machine = platform.machine()
15 | self.dirHome = os.path.expanduser("~")
16 | self.dirGrid = os.path.split(__file__)[0]
17 |
18 | def print_conflict_info(self):
19 | None
20 |
21 | def printInfo(self):
22 | print("GRID User's Info")
23 | print("----------------")
24 | print("Platform: ", self.platform)
25 | print("Architecture: ", self.architecture)
26 | print("Release: ", self.release)
27 | print("Machine: ", self.machine)
28 | print("Home Dir: ", self.dirHome)
29 | print("GRID Dir: ", self.dirGrid)
30 |
31 |
32 | # print conflict message if Mac users
33 | user = GUser()
34 |
35 | if user.platform == "Darwin":
36 | print("For Mac OS users, please ignore the messages below relating to duplicated implementations. \n\
37 | It's due to the conflict of OpenCV and PyQt, but it won't affect the performance and the results.\n")
38 |
--------------------------------------------------------------------------------
/grid/guser.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/guser.pyc
--------------------------------------------------------------------------------
/grid/io.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/io.pyc
--------------------------------------------------------------------------------
/grid/res/rotate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/grid/res/rotate.png
--------------------------------------------------------------------------------
/grid/test/test_gui.py:
--------------------------------------------------------------------------------
1 | # 3rd party imports
2 | from PyQt6.QtWidgets import *
3 | from PyQt6.QtCore import *
4 | from PyQt6.QtGui import *
5 | import sys
6 | import qdarkstyle
7 | import os
8 |
9 | app = QApplication(sys.argv)
10 | app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
11 |
12 | msgBox = QMessageBox()
13 | msgBox.setIcon(QMessageBox.Icon.Information)
14 | msgBox.setText("Finished!")
15 | msgBox.setInformativeText("Save and start another job?")
16 | msgBox.setStandardButtons(
17 | QMessageBox.StandardButton.Yes|
18 | QMessageBox.StandardButton.No|
19 | QMessageBox.StandardButton.Discard)
20 |
21 | msgBox.button(QMessageBox.StandardButton.Yes).setText("Save and stay in current work")
22 | msgBox.button(QMessageBox.StandardButton.No).setText("Save and start new job")
23 | msgBox.button(QMessageBox.StandardButton.Discard).setText("Cancel")
24 | # layout = msgBox.layout()
25 | msgBox.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
26 |
27 | msgBox.show()
28 | app.exec()
29 |
30 |
31 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | numpy
2 | pandas>=0.19.2
3 | h5py
4 | pyshp
5 | scikit-learn
6 | scipy
7 | matplotlib
8 | image
9 | opencv-python
10 | rasterio
11 | PyQt6
12 | qdarkstyle
13 | tqdm
--------------------------------------------------------------------------------
/res/GRID_banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/res/GRID_banner.png
--------------------------------------------------------------------------------
/res/GRID_logo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/res/GRID_logo2.png
--------------------------------------------------------------------------------
/res/abstract.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poissonfish/GRID/ed6b0b44cf60f0cda986c5897c14307f30ae8803/res/abstract.png
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import setuptools
2 |
3 | with open("README.md", "r", encoding="utf-8") as fh:
4 | long_description = fh.read()
5 |
6 | setuptools.setup(
7 | name="photo_grid",
8 | version="1.3.13",
9 | description="A GUI for field segmentation",
10 | long_description=long_description,
11 | long_description_content_type="text/markdown",
12 | url="https://github.com/Poissonfish/GRID",
13 | python_requires=">=3.6",
14 | classifiers=[
15 | "Programming Language :: Python :: 3.6",
16 | "Programming Language :: Python :: 3.7",
17 | "Programming Language :: Python :: 3.8",
18 | "Programming Language :: Python :: 3.9",
19 | "Programming Language :: Python :: 3.10",
20 | "Programming Language :: Python :: 3.11",
21 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
22 | "Operating System :: MacOS :: MacOS X",
23 | "Operating System :: Microsoft :: Windows :: Windows 10",
24 | ],
25 | author="James Chen",
26 | author_email="niche@vt.edu",
27 | license="GPLv3",
28 | packages=["grid", "grid.gui"],
29 | include_package_data=True,
30 | install_requires=[
31 | "numpy",
32 | "pandas>=0.19.2",
33 | # data processing
34 | "h5py",
35 | "pyshp",
36 | # math, models
37 | "scikit-learn",
38 | "scipy",
39 | "matplotlib",
40 | # image processing
41 | "image",
42 | "opencv-python",
43 | "rasterio",
44 | # GUI
45 | "PyQt6",
46 | "qdarkstyle",
47 | # misc
48 | "tqdm",
49 | ],
50 | entry_points={"console_scripts": ["GRID=grid.__main__:main"]},
51 | )
52 |
--------------------------------------------------------------------------------