hypertool 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hypertool-0.3.1/.gitignore +54 -0
- hypertool-0.3.1/INSTALL.md +130 -0
- hypertool-0.3.1/LICENSE.txt +7 -0
- hypertool-0.3.1/MANIFEST.in +6 -0
- hypertool-0.3.1/PKG-INFO +272 -0
- hypertool-0.3.1/README.md +241 -0
- hypertool-0.3.1/conda_env.yml +12 -0
- hypertool-0.3.1/hypertool/__init__.py +18 -0
- hypertool-0.3.1/hypertool/_version.py +24 -0
- hypertool-0.3.1/hypertool/cli.py +1371 -0
- hypertool-0.3.1/hypertool.egg-info/PKG-INFO +272 -0
- hypertool-0.3.1/hypertool.egg-info/SOURCES.txt +17 -0
- hypertool-0.3.1/hypertool.egg-info/dependency_links.txt +1 -0
- hypertool-0.3.1/hypertool.egg-info/entry_points.txt +2 -0
- hypertool-0.3.1/hypertool.egg-info/requires.txt +8 -0
- hypertool-0.3.1/hypertool.egg-info/top_level.txt +1 -0
- hypertool-0.3.1/pyproject.toml +47 -0
- hypertool-0.3.1/requirements.txt +14 -0
- hypertool-0.3.1/setup.cfg +4 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
deploy.sh
|
|
2
|
+
hypertool/_version.py
|
|
3
|
+
|
|
4
|
+
# Python
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*$py.class
|
|
8
|
+
*.so
|
|
9
|
+
.Python
|
|
10
|
+
build/
|
|
11
|
+
develop-eggs/
|
|
12
|
+
dist/
|
|
13
|
+
downloads/
|
|
14
|
+
eggs/
|
|
15
|
+
.eggs/
|
|
16
|
+
lib/
|
|
17
|
+
lib64/
|
|
18
|
+
parts/
|
|
19
|
+
sdist/
|
|
20
|
+
var/
|
|
21
|
+
wheels/
|
|
22
|
+
pip-wheel-metadata/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# Environments
|
|
30
|
+
.env
|
|
31
|
+
.venv
|
|
32
|
+
env/
|
|
33
|
+
venv/
|
|
34
|
+
ENV/
|
|
35
|
+
env.bak/
|
|
36
|
+
venv.bak/
|
|
37
|
+
|
|
38
|
+
# IDEs
|
|
39
|
+
.vscode/
|
|
40
|
+
.idea/
|
|
41
|
+
*.swp
|
|
42
|
+
*.swo
|
|
43
|
+
*~
|
|
44
|
+
|
|
45
|
+
# OS
|
|
46
|
+
.DS_Store
|
|
47
|
+
Thumbs.db
|
|
48
|
+
|
|
49
|
+
# Napari
|
|
50
|
+
.napari/
|
|
51
|
+
|
|
52
|
+
# Test files
|
|
53
|
+
roi_reference.png
|
|
54
|
+
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Installation Guide
|
|
2
|
+
|
|
3
|
+
## For Development
|
|
4
|
+
|
|
5
|
+
If you're working on hypertool itself:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Clone the repository
|
|
9
|
+
git clone https://github.com/your-username/hypertool.git
|
|
10
|
+
cd hypertool
|
|
11
|
+
|
|
12
|
+
# Install in editable mode (changes reflect immediately)
|
|
13
|
+
pip install -e .
|
|
14
|
+
|
|
15
|
+
# Or with conda environment
|
|
16
|
+
conda env create -f conda_env.yml
|
|
17
|
+
conda activate napari
|
|
18
|
+
pip install -e .
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## For Production/Pipeline Use
|
|
22
|
+
|
|
23
|
+
### Option 1: Install from Git (Private Repository)
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# With SSH
|
|
27
|
+
pip install git+ssh://git@github.com:Dannyzimmer/hypertool.git
|
|
28
|
+
|
|
29
|
+
# With HTTPS + token
|
|
30
|
+
pip install git+https://{GITHUB_TOKEN}@github.com/Dannyzimmer/hypertool.git
|
|
31
|
+
|
|
32
|
+
# Specific version
|
|
33
|
+
pip install git+https://github.com/Dannyzimmer/hypertool.git@v0.1.0
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Option 2: Install from Local Path
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# From local directory
|
|
40
|
+
pip install /path/to/hypertool
|
|
41
|
+
|
|
42
|
+
# In editable mode (for development)
|
|
43
|
+
pip install -e /path/to/hypertool
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Option 3: Add to requirements.txt
|
|
47
|
+
|
|
48
|
+
In your pipeline's `requirements.txt`:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
# From Git
|
|
52
|
+
git+https://github.com/Dannyzimmer/hypertool.git@v0.1.0
|
|
53
|
+
|
|
54
|
+
# From local path (development)
|
|
55
|
+
-e /path/to/hypertool
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Verify Installation
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Check command is available
|
|
62
|
+
hypertool --help
|
|
63
|
+
|
|
64
|
+
# Check version
|
|
65
|
+
python -c "from hypertool import __version__; print(__version__)"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Usage in Python Code
|
|
69
|
+
|
|
70
|
+
### As CLI command
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import subprocess
|
|
74
|
+
|
|
75
|
+
result = subprocess.run([
|
|
76
|
+
'hypertool', 'crop',
|
|
77
|
+
'image.hdr', 'masks.npy',
|
|
78
|
+
'-o', './output'
|
|
79
|
+
], check=True)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### As imported functions
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from hypertool.cli import (
|
|
86
|
+
crop_from_pixel_mask,
|
|
87
|
+
load_pixel_mask,
|
|
88
|
+
save_pixel_mask
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Use functions directly
|
|
92
|
+
mask = load_pixel_mask('masks.npy')
|
|
93
|
+
# ... process ...
|
|
94
|
+
save_pixel_mask(mask, 'output.npy', 'npy')
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## CI/CD Integration
|
|
98
|
+
|
|
99
|
+
### GitHub Actions
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
- name: Install hypertool
|
|
103
|
+
env:
|
|
104
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
105
|
+
run: |
|
|
106
|
+
pip install git+https://${GITHUB_TOKEN}@github.com/your-username/hypertool.git@v2.1.0
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### GitLab CI
|
|
110
|
+
|
|
111
|
+
```yaml
|
|
112
|
+
before_script:
|
|
113
|
+
- pip install git+https://oauth2:${CI_JOB_TOKEN}@gitlab.com/your-username/hypertool.git@v2.1.0
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Uninstall
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
pip uninstall hypertool
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Troubleshooting
|
|
123
|
+
|
|
124
|
+
### Missing dependencies
|
|
125
|
+
|
|
126
|
+
If you get import errors, ensure all dependencies are installed:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pip install -r requirements.txt
|
|
130
|
+
```
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2026 Daniel Pérez Rodríguez
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
hypertool-0.3.1/PKG-INFO
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hypertool
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Command-line tool for hyperspectral image processing
|
|
5
|
+
Author: Daniel Pérez Rodríguez
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/dannyzimm/hypertool
|
|
8
|
+
Project-URL: Repository, https://github.com/dannyzimm/hypertool
|
|
9
|
+
Keywords: hyperspectral,imaging,segmentation,classification,napari
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE.txt
|
|
22
|
+
Requires-Dist: spectral>=0.23.1
|
|
23
|
+
Requires-Dist: napari[all]>=0.4.18
|
|
24
|
+
Requires-Dist: numpy>=1.24.0
|
|
25
|
+
Requires-Dist: pandas>=2.0.0
|
|
26
|
+
Requires-Dist: click>=8.1.0
|
|
27
|
+
Requires-Dist: scikit-image>=0.21.0
|
|
28
|
+
Requires-Dist: matplotlib>=3.10.8
|
|
29
|
+
Requires-Dist: tifffile>=2023.0.0
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# Hypertool
|
|
33
|
+
|
|
34
|
+
A command-line tool for visualization and processing of hyperspectral images in ENVI format (HDR/RAW).
|
|
35
|
+
|
|
36
|
+
## Features
|
|
37
|
+
|
|
38
|
+
- Interactive visualization of hyperspectral images using napari
|
|
39
|
+
- RGB composite generation with automatic or custom band selection
|
|
40
|
+
- Multi-band layer visualization
|
|
41
|
+
- **Classification workflow**: ROI-based masking and cropping
|
|
42
|
+
- **Segmentation workflow**: Pixel-level annotation and paired image+mask cropping
|
|
43
|
+
- Support for ENVI, NumPy, and TIFF formats
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
### Quick Install (Development)
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install -e .
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### From Git (Production/Pipeline)
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Latest version
|
|
57
|
+
pip install git+https://github.com/your-username/hypertool.git
|
|
58
|
+
|
|
59
|
+
# Specific version
|
|
60
|
+
pip install git+https://github.com/your-username/hypertool.git@v2.1.0
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
For detailed installation instructions (private repositories, CI/CD, etc.), see [INSTALL.md](INSTALL.md).
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
### View Command
|
|
68
|
+
|
|
69
|
+
Visualize hyperspectral images in napari with different display modes.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# RGB mode with default bands from HDR metadata
|
|
73
|
+
python hypertool.py view image.hdr
|
|
74
|
+
|
|
75
|
+
# RGB mode with custom bands (0-based indices)
|
|
76
|
+
python hypertool.py view image.hdr --bands "50,100,150"
|
|
77
|
+
|
|
78
|
+
# View all bands as separate layers
|
|
79
|
+
python hypertool.py view image.hdr --mode all
|
|
80
|
+
|
|
81
|
+
# View a specific range of bands
|
|
82
|
+
python hypertool.py view image.hdr --mode range --start 50 --end 100
|
|
83
|
+
|
|
84
|
+
# Disable automatic normalization
|
|
85
|
+
python hypertool.py view image.hdr --no-normalize
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Workflows
|
|
89
|
+
|
|
90
|
+
### Classification Workflow (ROI-based)
|
|
91
|
+
|
|
92
|
+
For image classification tasks where each crop gets a single label.
|
|
93
|
+
|
|
94
|
+
#### 1. ROI-Mask Command
|
|
95
|
+
|
|
96
|
+
Create standardized ROI masks using geometric shapes.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Create 6 circular masks (manual save)
|
|
100
|
+
python hypertool.py roi-mask image.hdr --shape circle --size 35 --num 6
|
|
101
|
+
|
|
102
|
+
# Create with auto-save on close
|
|
103
|
+
python hypertool.py roi-mask image.hdr --shape circle --size 35 --num 6 -o rois.csv
|
|
104
|
+
|
|
105
|
+
# Other shapes
|
|
106
|
+
python hypertool.py roi-mask image.hdr --shape square --size 30 --num 5 -o rois.csv
|
|
107
|
+
python hypertool.py roi-mask image.hdr --shape triangle --size 20 --num 3 -o rois.csv
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Parameters:**
|
|
111
|
+
- `--shape`: Shape type (square, circle, triangle)
|
|
112
|
+
- `--size`: Size on 1-100 scale (automatically converted to pixels)
|
|
113
|
+
- `--num`: Number of shapes to create (distributed in grid layout)
|
|
114
|
+
- `--output/-o`: Optional auto-save path (saves on napari close)
|
|
115
|
+
|
|
116
|
+
**Steps:**
|
|
117
|
+
1. Adjust mask positions in napari
|
|
118
|
+
2. **Option A:** Close napari (auto-saves if -o specified)
|
|
119
|
+
**Option B:** Export manually via File > Save Selected Layer(s)
|
|
120
|
+
3. Create a `labels.csv` mapping each ROI index to its class
|
|
121
|
+
|
|
122
|
+
#### 2. Crop Command (ROI mode)
|
|
123
|
+
|
|
124
|
+
Extract ROI crops from CSV.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Crop using ROIs (bounding box only)
|
|
128
|
+
python hypertool.py crop image.hdr rois.csv ./output
|
|
129
|
+
|
|
130
|
+
# Apply shape mask (pixels outside shape = 0)
|
|
131
|
+
python hypertool.py crop image.hdr rois.csv ./output --apply-mask
|
|
132
|
+
|
|
133
|
+
# Custom prefix and NumPy format
|
|
134
|
+
python hypertool.py crop image.hdr rois.csv ./output --prefix sample --format numpy
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Segmentation Workflow (Pixel-level)
|
|
138
|
+
|
|
139
|
+
For semantic segmentation tasks where each pixel gets a label.
|
|
140
|
+
|
|
141
|
+
#### Option A: Geometric Shapes (Recommended for uniform regions)
|
|
142
|
+
|
|
143
|
+
For regions with consistent geometric shapes (e.g., petri dishes, samples in trays).
|
|
144
|
+
|
|
145
|
+
**Step 1: Create ROI shapes**
|
|
146
|
+
```bash
|
|
147
|
+
python hypertool.py roi-mask image.hdr --shape circle --size 35 --num 6 -o rois.csv
|
|
148
|
+
```
|
|
149
|
+
- Move circles to position in napari
|
|
150
|
+
- Close napari (auto-saves to rois.csv)
|
|
151
|
+
|
|
152
|
+
**Step 2: Convert ROIs to pixel mask**
|
|
153
|
+
```bash
|
|
154
|
+
python hypertool.py roi-to-pixel-mask image.hdr rois.csv \
|
|
155
|
+
--classes "tipo_A,tipo_B" -o masks.npy --save-metadata
|
|
156
|
+
```
|
|
157
|
+
- A reference image opens showing numbered ROIs
|
|
158
|
+
- Enter ROI numbers for each class interactively
|
|
159
|
+
- Background is automatically assigned to everything else
|
|
160
|
+
- `--save-metadata` creates `masks.json` with class mapping
|
|
161
|
+
|
|
162
|
+
**Step 3: Crop image+mask pairs**
|
|
163
|
+
```bash
|
|
164
|
+
python hypertool.py crop image.hdr masks.npy -o ./output
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Result:**
|
|
168
|
+
```
|
|
169
|
+
output/
|
|
170
|
+
├── images/ # Hyperspectral crops
|
|
171
|
+
│ ├── crop_0.npy
|
|
172
|
+
│ └── ...
|
|
173
|
+
└── masks/ # Segmentation masks (0=bg, 1=tipo_A, 2=tipo_B)
|
|
174
|
+
├── crop_0.npy
|
|
175
|
+
└── ...
|
|
176
|
+
|
|
177
|
+
masks.json # Class mapping metadata
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Example interactive session:**
|
|
181
|
+
```
|
|
182
|
+
ROI reference displayed...
|
|
183
|
+
|
|
184
|
+
tipo_A (label=1) ROI numbers (comma-separated): 0,1,2
|
|
185
|
+
✓ tipo_A → ROIs: [0, 1, 2]
|
|
186
|
+
|
|
187
|
+
tipo_B (label=2) ROI numbers (comma-separated): 3,4,5
|
|
188
|
+
✓ tipo_B → ROIs: [3, 4, 5]
|
|
189
|
+
|
|
190
|
+
Proceed with mask generation? [Y/n]: y
|
|
191
|
+
✓ Pixel mask saved to: masks.npy
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### Option B: Free Annotation (For irregular shapes)
|
|
195
|
+
|
|
196
|
+
For complex or irregular regions that can't be represented by geometric shapes.
|
|
197
|
+
|
|
198
|
+
**Step 1: Create pixel masks manually**
|
|
199
|
+
```bash
|
|
200
|
+
python hypertool.py pixel-mask image.hdr --classes "background,healthy,diseased"
|
|
201
|
+
```
|
|
202
|
+
- Opens napari with empty Labels layer
|
|
203
|
+
- Use paint/fill tools to annotate regions
|
|
204
|
+
- Save via File > Save Selected Layer(s) or use `--output`
|
|
205
|
+
|
|
206
|
+
**Step 2: Crop image+mask pairs**
|
|
207
|
+
```bash
|
|
208
|
+
python hypertool.py crop image.hdr masks.npy ./output
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Output structure:**
|
|
212
|
+
```
|
|
213
|
+
output/
|
|
214
|
+
├── images/
|
|
215
|
+
│ ├── crop_0.npy
|
|
216
|
+
│ ├── crop_1.npy
|
|
217
|
+
│ └── ...
|
|
218
|
+
└── masks/
|
|
219
|
+
├── crop_0.npy
|
|
220
|
+
├── crop_1.npy
|
|
221
|
+
└── ...
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Command Summary
|
|
225
|
+
|
|
226
|
+
| Command | Purpose | Workflow |
|
|
227
|
+
|---------|---------|----------|
|
|
228
|
+
| `view` | Visualize hyperspectral images | Both |
|
|
229
|
+
| `roi-mask` | Create geometric ROI shapes | Classification / Segmentation |
|
|
230
|
+
| `roi-to-pixel-mask` | Convert ROI shapes to pixel masks | Segmentation |
|
|
231
|
+
| `pixel-mask` | Free-hand pixel annotation | Segmentation |
|
|
232
|
+
| `crop` | Extract crops (auto-detects mode) | Both |
|
|
233
|
+
|
|
234
|
+
## Crop Command Auto-Detection
|
|
235
|
+
|
|
236
|
+
The `crop` command automatically detects the workflow:
|
|
237
|
+
|
|
238
|
+
- **CSV input** → Classification workflow (ROI-based)
|
|
239
|
+
- Creates: Individual cropped images
|
|
240
|
+
|
|
241
|
+
- **NPY/TIF input** → Segmentation workflow (pixel-mask)
|
|
242
|
+
- Creates: Paired image + mask crops in separate directories
|
|
243
|
+
|
|
244
|
+
## CSV Format (Classification Workflow)
|
|
245
|
+
|
|
246
|
+
The ROI CSV file exported from napari must contain:
|
|
247
|
+
- `index`: ROI identifier
|
|
248
|
+
- `shape-type`: Type of shape (rectangle, ellipse, polygon)
|
|
249
|
+
- `vertex-index`: Vertex number within the shape
|
|
250
|
+
- `axis-0`: Y coordinate
|
|
251
|
+
- `axis-1`: X coordinate
|
|
252
|
+
|
|
253
|
+
## Requirements
|
|
254
|
+
|
|
255
|
+
- Python 3.8+
|
|
256
|
+
- spectral
|
|
257
|
+
- napari
|
|
258
|
+
- numpy
|
|
259
|
+
- pandas
|
|
260
|
+
- click
|
|
261
|
+
- scikit-image
|
|
262
|
+
- tifffile (optional, for TIF export)
|
|
263
|
+
- PyQt5
|
|
264
|
+
- matplotlib
|
|
265
|
+
|
|
266
|
+
## Notes
|
|
267
|
+
|
|
268
|
+
- Band indices are 0-based in the CLI
|
|
269
|
+
- The tool automatically detects BIL/BSQ/BIP interleave formats
|
|
270
|
+
- Percentile normalization (2nd-98th) is applied by default for visualization
|
|
271
|
+
- Segmentation masks use integer labels: 0=background, 1=class1, 2=class2, etc.
|
|
272
|
+
- For segmentation, connected regions are automatically detected and cropped
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# Hypertool
|
|
2
|
+
|
|
3
|
+
A command-line tool for visualization and processing of hyperspectral images in ENVI format (HDR/RAW).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Interactive visualization of hyperspectral images using napari
|
|
8
|
+
- RGB composite generation with automatic or custom band selection
|
|
9
|
+
- Multi-band layer visualization
|
|
10
|
+
- **Classification workflow**: ROI-based masking and cropping
|
|
11
|
+
- **Segmentation workflow**: Pixel-level annotation and paired image+mask cropping
|
|
12
|
+
- Support for ENVI, NumPy, and TIFF formats
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### Quick Install (Development)
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install -e .
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### From Git (Production/Pipeline)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Latest version
|
|
26
|
+
pip install git+https://github.com/your-username/hypertool.git
|
|
27
|
+
|
|
28
|
+
# Specific version
|
|
29
|
+
pip install git+https://github.com/your-username/hypertool.git@v2.1.0
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
For detailed installation instructions (private repositories, CI/CD, etc.), see [INSTALL.md](INSTALL.md).
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
### View Command
|
|
37
|
+
|
|
38
|
+
Visualize hyperspectral images in napari with different display modes.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# RGB mode with default bands from HDR metadata
|
|
42
|
+
python hypertool.py view image.hdr
|
|
43
|
+
|
|
44
|
+
# RGB mode with custom bands (0-based indices)
|
|
45
|
+
python hypertool.py view image.hdr --bands "50,100,150"
|
|
46
|
+
|
|
47
|
+
# View all bands as separate layers
|
|
48
|
+
python hypertool.py view image.hdr --mode all
|
|
49
|
+
|
|
50
|
+
# View a specific range of bands
|
|
51
|
+
python hypertool.py view image.hdr --mode range --start 50 --end 100
|
|
52
|
+
|
|
53
|
+
# Disable automatic normalization
|
|
54
|
+
python hypertool.py view image.hdr --no-normalize
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Workflows
|
|
58
|
+
|
|
59
|
+
### Classification Workflow (ROI-based)
|
|
60
|
+
|
|
61
|
+
For image classification tasks where each crop gets a single label.
|
|
62
|
+
|
|
63
|
+
#### 1. ROI-Mask Command
|
|
64
|
+
|
|
65
|
+
Create standardized ROI masks using geometric shapes.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Create 6 circular masks (manual save)
|
|
69
|
+
python hypertool.py roi-mask image.hdr --shape circle --size 35 --num 6
|
|
70
|
+
|
|
71
|
+
# Create with auto-save on close
|
|
72
|
+
python hypertool.py roi-mask image.hdr --shape circle --size 35 --num 6 -o rois.csv
|
|
73
|
+
|
|
74
|
+
# Other shapes
|
|
75
|
+
python hypertool.py roi-mask image.hdr --shape square --size 30 --num 5 -o rois.csv
|
|
76
|
+
python hypertool.py roi-mask image.hdr --shape triangle --size 20 --num 3 -o rois.csv
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Parameters:**
|
|
80
|
+
- `--shape`: Shape type (square, circle, triangle)
|
|
81
|
+
- `--size`: Size on 1-100 scale (automatically converted to pixels)
|
|
82
|
+
- `--num`: Number of shapes to create (distributed in grid layout)
|
|
83
|
+
- `--output/-o`: Optional auto-save path (saves on napari close)
|
|
84
|
+
|
|
85
|
+
**Steps:**
|
|
86
|
+
1. Adjust mask positions in napari
|
|
87
|
+
2. **Option A:** Close napari (auto-saves if -o specified)
|
|
88
|
+
**Option B:** Export manually via File > Save Selected Layer(s)
|
|
89
|
+
3. Create a `labels.csv` mapping each ROI index to its class
|
|
90
|
+
|
|
91
|
+
#### 2. Crop Command (ROI mode)
|
|
92
|
+
|
|
93
|
+
Extract ROI crops from CSV.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Crop using ROIs (bounding box only)
|
|
97
|
+
python hypertool.py crop image.hdr rois.csv ./output
|
|
98
|
+
|
|
99
|
+
# Apply shape mask (pixels outside shape = 0)
|
|
100
|
+
python hypertool.py crop image.hdr rois.csv ./output --apply-mask
|
|
101
|
+
|
|
102
|
+
# Custom prefix and NumPy format
|
|
103
|
+
python hypertool.py crop image.hdr rois.csv ./output --prefix sample --format numpy
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Segmentation Workflow (Pixel-level)
|
|
107
|
+
|
|
108
|
+
For semantic segmentation tasks where each pixel gets a label.
|
|
109
|
+
|
|
110
|
+
#### Option A: Geometric Shapes (Recommended for uniform regions)
|
|
111
|
+
|
|
112
|
+
For regions with consistent geometric shapes (e.g., petri dishes, samples in trays).
|
|
113
|
+
|
|
114
|
+
**Step 1: Create ROI shapes**
|
|
115
|
+
```bash
|
|
116
|
+
python hypertool.py roi-mask image.hdr --shape circle --size 35 --num 6 -o rois.csv
|
|
117
|
+
```
|
|
118
|
+
- Move circles to position in napari
|
|
119
|
+
- Close napari (auto-saves to rois.csv)
|
|
120
|
+
|
|
121
|
+
**Step 2: Convert ROIs to pixel mask**
|
|
122
|
+
```bash
|
|
123
|
+
python hypertool.py roi-to-pixel-mask image.hdr rois.csv \
|
|
124
|
+
--classes "tipo_A,tipo_B" -o masks.npy --save-metadata
|
|
125
|
+
```
|
|
126
|
+
- A reference image opens showing numbered ROIs
|
|
127
|
+
- Enter ROI numbers for each class interactively
|
|
128
|
+
- Background is automatically assigned to everything else
|
|
129
|
+
- `--save-metadata` creates `masks.json` with class mapping
|
|
130
|
+
|
|
131
|
+
**Step 3: Crop image+mask pairs**
|
|
132
|
+
```bash
|
|
133
|
+
python hypertool.py crop image.hdr masks.npy -o ./output
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Result:**
|
|
137
|
+
```
|
|
138
|
+
output/
|
|
139
|
+
├── images/ # Hyperspectral crops
|
|
140
|
+
│ ├── crop_0.npy
|
|
141
|
+
│ └── ...
|
|
142
|
+
└── masks/ # Segmentation masks (0=bg, 1=tipo_A, 2=tipo_B)
|
|
143
|
+
├── crop_0.npy
|
|
144
|
+
└── ...
|
|
145
|
+
|
|
146
|
+
masks.json # Class mapping metadata
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Example interactive session:**
|
|
150
|
+
```
|
|
151
|
+
ROI reference displayed...
|
|
152
|
+
|
|
153
|
+
tipo_A (label=1) ROI numbers (comma-separated): 0,1,2
|
|
154
|
+
✓ tipo_A → ROIs: [0, 1, 2]
|
|
155
|
+
|
|
156
|
+
tipo_B (label=2) ROI numbers (comma-separated): 3,4,5
|
|
157
|
+
✓ tipo_B → ROIs: [3, 4, 5]
|
|
158
|
+
|
|
159
|
+
Proceed with mask generation? [Y/n]: y
|
|
160
|
+
✓ Pixel mask saved to: masks.npy
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
#### Option B: Free Annotation (For irregular shapes)
|
|
164
|
+
|
|
165
|
+
For complex or irregular regions that can't be represented by geometric shapes.
|
|
166
|
+
|
|
167
|
+
**Step 1: Create pixel masks manually**
|
|
168
|
+
```bash
|
|
169
|
+
python hypertool.py pixel-mask image.hdr --classes "background,healthy,diseased"
|
|
170
|
+
```
|
|
171
|
+
- Opens napari with empty Labels layer
|
|
172
|
+
- Use paint/fill tools to annotate regions
|
|
173
|
+
- Save via File > Save Selected Layer(s) or use `--output`
|
|
174
|
+
|
|
175
|
+
**Step 2: Crop image+mask pairs**
|
|
176
|
+
```bash
|
|
177
|
+
python hypertool.py crop image.hdr masks.npy ./output
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Output structure:**
|
|
181
|
+
```
|
|
182
|
+
output/
|
|
183
|
+
├── images/
|
|
184
|
+
│ ├── crop_0.npy
|
|
185
|
+
│ ├── crop_1.npy
|
|
186
|
+
│ └── ...
|
|
187
|
+
└── masks/
|
|
188
|
+
├── crop_0.npy
|
|
189
|
+
├── crop_1.npy
|
|
190
|
+
└── ...
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Command Summary
|
|
194
|
+
|
|
195
|
+
| Command | Purpose | Workflow |
|
|
196
|
+
|---------|---------|----------|
|
|
197
|
+
| `view` | Visualize hyperspectral images | Both |
|
|
198
|
+
| `roi-mask` | Create geometric ROI shapes | Classification / Segmentation |
|
|
199
|
+
| `roi-to-pixel-mask` | Convert ROI shapes to pixel masks | Segmentation |
|
|
200
|
+
| `pixel-mask` | Free-hand pixel annotation | Segmentation |
|
|
201
|
+
| `crop` | Extract crops (auto-detects mode) | Both |
|
|
202
|
+
|
|
203
|
+
## Crop Command Auto-Detection
|
|
204
|
+
|
|
205
|
+
The `crop` command automatically detects the workflow:
|
|
206
|
+
|
|
207
|
+
- **CSV input** → Classification workflow (ROI-based)
|
|
208
|
+
- Creates: Individual cropped images
|
|
209
|
+
|
|
210
|
+
- **NPY/TIF input** → Segmentation workflow (pixel-mask)
|
|
211
|
+
- Creates: Paired image + mask crops in separate directories
|
|
212
|
+
|
|
213
|
+
## CSV Format (Classification Workflow)
|
|
214
|
+
|
|
215
|
+
The ROI CSV file exported from napari must contain:
|
|
216
|
+
- `index`: ROI identifier
|
|
217
|
+
- `shape-type`: Type of shape (rectangle, ellipse, polygon)
|
|
218
|
+
- `vertex-index`: Vertex number within the shape
|
|
219
|
+
- `axis-0`: Y coordinate
|
|
220
|
+
- `axis-1`: X coordinate
|
|
221
|
+
|
|
222
|
+
## Requirements
|
|
223
|
+
|
|
224
|
+
- Python 3.8+
|
|
225
|
+
- spectral
|
|
226
|
+
- napari
|
|
227
|
+
- numpy
|
|
228
|
+
- pandas
|
|
229
|
+
- click
|
|
230
|
+
- scikit-image
|
|
231
|
+
- tifffile (optional, for TIF export)
|
|
232
|
+
- PyQt5
|
|
233
|
+
- matplotlib
|
|
234
|
+
|
|
235
|
+
## Notes
|
|
236
|
+
|
|
237
|
+
- Band indices are 0-based in the CLI
|
|
238
|
+
- The tool automatically detects BIL/BSQ/BIP interleave formats
|
|
239
|
+
- Percentile normalization (2nd-98th) is applied by default for visualization
|
|
240
|
+
- Segmentation masks use integer labels: 0=background, 1=class1, 2=class2, etc.
|
|
241
|
+
- For segmentation, connected regions are automatically detected and cropped
|