Skip to content

Commit ee914fd

Browse files
authored
Merge pull request #207 from MetaCell/feature/conversion_scripts
Conversion scripts from NRRD to precomputed
2 parents 3d19d83 + ddde891 commit ee914fd

File tree

8 files changed

+1665
-0
lines changed

8 files changed

+1665
-0
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# NRRD to Neuroglancer Precomputed Workflow
2+
3+
## Overview
4+
This guide shows how to convert NRRD segmentation files to Neuroglancer precomputed format with meshes.
5+
6+
## Fixed Issues
7+
8+
### Issue #1: Meshes not showing in Neuroglancer
9+
**Root cause**: Mesh vertices were in physical coordinates (microns) instead of voxel coordinates.
10+
**Fix**: Removed `spacing` parameter from `marching_cubes()` call. Neuroglancer applies resolution scaling separately.
11+
12+
### Issue #2: Segmentation fragmentation
13+
**Clarification**: The NRRD files contain multiple anatomical structures as separate segments (this is correct).
14+
If you see unexpected fragmentation, use `merge_segments.py` to consolidate connected components.
15+
16+
## Workflow
17+
18+
### Step 1: Inspect your data (optional but recommended)
19+
```bash
20+
cd /home/ddelpiano/git/neuroglass/dataScripts/nrrd_to_precomputed
21+
python inspect_nrrd.py files/VFB_00101567.nrrd
22+
```
23+
24+
### Step 2: (Optional) Merge fragmented segments
25+
Only use this if you want to merge disconnected pieces into single segments:
26+
```bash
27+
python merge_segments.py \
28+
files/VFB_00101567.nrrd \
29+
files/VFB_00101567_merged.nrrd \
30+
--min-size 100 \
31+
--verbose
32+
```
33+
34+
### Step 3: Convert NRRD to precomputed format
35+
```bash
36+
python converter.py \
37+
--input-dir files \
38+
--output-path output \
39+
--verbose
40+
```
41+
42+
This will:
43+
- Find all `.nrrd` files in `files/` directory
44+
- Convert each to precomputed format in `output/` directory
45+
- Create a mapping file: `output/sources_to_dataset.json`
46+
47+
### Step 4: Generate meshes
48+
```bash
49+
python meshes_generator.py \
50+
--input-path output \
51+
--dust-threshold 100 \
52+
--verbose
53+
```
54+
55+
This will:
56+
- Find all precomputed datasets in `output/` directory
57+
- Generate meshes for each segment (skipping segments < 100 voxels)
58+
- Create segment properties (labels and metadata)
59+
- Generate `output/neuroglancer_state.json` for easy loading
60+
61+
### Step 5: Serve the data
62+
```bash
63+
cd output
64+
npx http-server . -p 8080 --cors
65+
```
66+
67+
### Step 6: View in Neuroglancer
68+
1. Go to https://neuroglancer-demo.appspot.com/
69+
2. Click the `{}` (JSON) button in the top-right
70+
3. Copy the contents of `output/neuroglancer_state.json`
71+
4. Paste into the JSON editor
72+
5. Click outside the editor to load
73+
74+
## Troubleshooting
75+
76+
### Meshes still not showing?
77+
1. **Check the browser console** for errors
78+
2. **Verify mesh files exist**:
79+
```bash
80+
ls -lh output/*/mesh/
81+
```
82+
3. **Check segment IDs match**:
83+
```bash
84+
python inspect_nrrd.py files/VFB_00101567.nrrd | grep "Segment IDs"
85+
```
86+
4. **Try loading a single segment manually** in Neuroglancer UI
87+
88+
### Segmentation looks wrong?
89+
- Use `inspect_nrrd.py` to see segment IDs and sizes
90+
- The NRRD files contain pre-labeled anatomical structures
91+
- If you see unexpected fragmentation, verify with the original data source
92+
93+
### Performance issues?
94+
- Reduce `--dust-threshold` to skip more small segments
95+
- Generate meshes for fewer segments initially
96+
- Check your mesh file sizes
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env python3
2+
"""Debug mesh and volume coordinate spaces"""
3+
import json
4+
import sys
5+
import os
6+
7+
if len(sys.argv) < 2:
8+
print("Usage: python check_mesh_coords.py <dataset_path>")
9+
sys.exit(1)
10+
11+
dataset_path = sys.argv[1]
12+
13+
# Read main info
14+
with open(os.path.join(dataset_path, "info"), "r") as f:
15+
info = json.load(f)
16+
17+
print("=== Dataset Info ===")
18+
print(f"Type: {info['type']}")
19+
print(f"Data type: {info['data_type']}")
20+
print(f"Volume size (XYZ): {info['scales'][0]['size']}")
21+
print(f"Resolution (XYZ): {info['scales'][0]['resolution']}")
22+
print(f"Chunk sizes: {info['scales'][0]['chunk_sizes']}")
23+
24+
# Calculate physical bounds
25+
size = info["scales"][0]["size"]
26+
resolution = info["scales"][0]["resolution"]
27+
physical_bounds = [s * r for s, r in zip(size, resolution)]
28+
print(f"Physical bounds: {physical_bounds}")
29+
30+
# Read mesh info if exists
31+
mesh_info_path = os.path.join(dataset_path, "mesh", "info")
32+
if os.path.exists(mesh_info_path):
33+
print("\n=== Mesh Info ===")
34+
with open(mesh_info_path, "r") as f:
35+
mesh_info = json.load(f)
36+
print(json.dumps(mesh_info, indent=2))
37+
38+
# Check a sample mesh file
39+
mesh_dir = os.path.join(dataset_path, "mesh")
40+
mesh_files = [
41+
f
42+
for f in os.listdir(mesh_dir)
43+
if f.endswith(".gz") or (f.isdigit() and not f.endswith(".gz"))
44+
]
45+
46+
if mesh_files:
47+
sample_mesh = mesh_files[0]
48+
print(f"\nSample mesh file: {sample_mesh}")
49+
50+
# Try to read and check coordinates
51+
try:
52+
from cloudvolume import CloudVolume
53+
from cloudvolume.mesh import Mesh
54+
55+
vol = CloudVolume(f"file://{dataset_path}", mip=0)
56+
57+
# Get segment ID from filename
58+
seg_id = int(sample_mesh.replace(".gz", "").replace(":", "_").split("_")[0])
59+
60+
try:
61+
mesh = vol.mesh.get(seg_id)
62+
if mesh and len(mesh.vertices) > 0:
63+
print(f"\nMesh {seg_id} vertices:")
64+
print(f" Min: {mesh.vertices.min(axis=0)}")
65+
print(f" Max: {mesh.vertices.max(axis=0)}")
66+
print(f" Shape: {mesh.vertices.shape}")
67+
68+
# Compare with volume bounds
69+
max_voxel = mesh.vertices.max(axis=0)
70+
print(f"\nComparison:")
71+
print(f" Volume size (voxels): {size}")
72+
print(f" Mesh max (should be <= volume size): {max_voxel}")
73+
74+
if any(max_voxel > size):
75+
print(f" ⚠ WARNING: Mesh vertices exceed volume bounds!")
76+
else:
77+
print(f" ✓ Mesh vertices within volume bounds")
78+
except Exception as e:
79+
print(f" Error loading mesh: {e}")
80+
81+
except Exception as e:
82+
print(f"Error: {e}")
83+
else:
84+
print("\n⚠ No mesh info found")

0 commit comments

Comments
 (0)