Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
135 commits
Select commit Hold shift + click to select a range
48cfc0b
Initial commit
BrysonGray Mar 13, 2023
cd10c86
add all files
BrysonGray Mar 13, 2023
c489d89
Update README.md
BrysonGray Mar 13, 2023
9886d64
started neuron tracking project and reorganized
BrysonGray Feb 1, 2024
b918b81
Add draw_line_segment and update data setup to use it to make density…
BrysonGray Feb 12, 2024
8ade337
use binary ground truth
BrysonGray Feb 13, 2024
512b5a5
cleanup
BrysonGray Feb 13, 2024
b181422
Working version using a mask and no friction or smoothing regularizers.
BrysonGray Feb 14, 2024
d26956e
include last steps in state (in progress)
BrysonGray Feb 14, 2024
3ab6daa
working version with last step input
BrysonGray Feb 16, 2024
102fa54
Don't convert to world coordinates. Draw segments without blurring. I…
BrysonGray Feb 19, 2024
d12fe3d
data visualization
BrysonGray Feb 19, 2024
dbf8dc7
Normalize image channels independently. Fixed bug by setting endpoint…
BrysonGray Feb 19, 2024
f172c70
update visualization
BrysonGray Feb 20, 2024
b22d7f0
minor fix
BrysonGray Feb 20, 2024
881234d
minor fixes
BrysonGray Feb 20, 2024
fd64964
new tests
BrysonGray Feb 20, 2024
4af6c8a
test visualization and miscellaneous fixes
BrysonGray Feb 21, 2024
bf1b5fa
Modify network architecture to input last direction into convolution …
BrysonGray Feb 27, 2024
194c78f
Fixed interpolation in crop function and made mask wider.
BrysonGray Feb 29, 2024
a2eaa8d
fix crop interpolation, increase mask width, save global errors
BrysonGray Feb 29, 2024
cb9dc16
Fix global metric calculation. Omit view interpolation.
BrysonGray Mar 5, 2024
ce71a35
fix to inference method
BrysonGray Mar 7, 2024
39a2e6d
Merge pull request #1 from BrysonGray/track_with_branching
BrysonGray Mar 7, 2024
26b55c4
merge with track_with_branching
BrysonGray Mar 7, 2024
2408619
Updates to allow branching
BrysonGray Apr 9, 2024
ee6e698
save working code to test reward functions.
BrysonGray May 20, 2024
b30e9ab
working example without branching
BrysonGray May 21, 2024
d448a00
include branch length in estimated path data
BrysonGray Jun 4, 2024
f1a0f56
soft actor critic in progress
BrysonGray Jul 3, 2024
13581ed
First pass complete SAC algorithm. Still has an issue with policy los…
BrysonGray Aug 24, 2024
354d391
Fix: fix to policy loss blowup problem.
BrysonGray Sep 3, 2024
0855535
"Formatting"
BrysonGray Sep 9, 2024
e128e0b
working example with flat 3D phantoms (stopping but no branching)
BrysonGray Sep 20, 2024
7481739
EDIT: phantoms output binary neuron mask rather than tracking boundar…
BrysonGray Sep 23, 2024
c7979c1
Refactor
BrysonGray Sep 23, 2024
01cc48f
Major updates to data loading, branch classifier, and tracking enviro…
BrysonGray Dec 12, 2024
07ec303
merge with track_with_branching
BrysonGray Dec 12, 2024
e1b6f10
updated branch classifier
BrysonGray Jan 11, 2025
4702998
Add new simulation data functionality
BrysonGray Jan 21, 2025
41c752a
Add artifacts to simulated data
BrysonGray Jan 23, 2025
e25f991
Refactor: add data directory
BrysonGray Jan 23, 2025
ed42665
Minor fixes to data simulation modules
BrysonGray Jan 30, 2025
7ad39cd
Merge branch 'main' of https://github.com/BrysonGray/tractography
BrysonGray Jan 30, 2025
26bf8ae
Refactoring
BrysonGray Feb 5, 2025
34d6e48
Restructure
BrysonGray Feb 6, 2025
5a0d8e7
Add docstrings and module descriptions
BrysonGray Feb 6, 2025
a4c05d4
Remove pretrained model weights
BrysonGray Feb 6, 2025
72d008d
minor fix to notebook example
BrysonGray Feb 6, 2025
82692fb
Update README.md
BrysonGray Feb 7, 2025
b9a6858
Update README.md
BrysonGray Feb 7, 2025
a618aba
Add: sphinx-quickstart outputs
BrysonGray Feb 7, 2025
3ca5f5e
Merge branch 'main' of https://github.com/BrysonGray/tractography
BrysonGray Feb 7, 2025
acc9aaa
Merge branch 'main' of https://github.com/BrysonGray/tractography
BrysonGray Feb 7, 2025
0516b7b
Fix to branch_classifier.ipynb and add documentation
BrysonGray Feb 8, 2025
b89d3e1
Added documentation source files
BrysonGray Feb 11, 2025
27b0716
Update requirements file
BrysonGray Feb 11, 2025
1043c6d
Add examples page to docs
BrysonGray Feb 11, 2025
1fe141a
restructure docs
BrysonGray Feb 12, 2025
7c7f641
Add workflow
BrysonGray Feb 12, 2025
fd466bb
Update requirements.txt
BrysonGray Feb 12, 2025
d6606c6
Fix: documentation workflow
BrysonGray Feb 12, 2025
1f42529
Update requirements
BrysonGray Feb 12, 2025
c957c93
Update requirements.txt
BrysonGray Feb 12, 2025
790aac0
Remove notebooks from source
BrysonGray Feb 12, 2025
8dd9ac3
Add example notebooks to source
BrysonGray Feb 12, 2025
4c9d279
Add install pandoc to documentation.yml
BrysonGray Feb 12, 2025
ecf8365
Move notebooks to their own folder and create symlinks to source dire…
BrysonGray Feb 19, 2025
c495033
Move notebooks to their own folder and create symlinks to source dire…
BrysonGray Feb 19, 2025
0c138b9
Merge pull request #4 from BrysonGray/develop
BrysonGray Feb 19, 2025
2d0267e
Merge pull request #4 from BrysonGray/develop
BrysonGray Feb 19, 2025
602ebe1
Add: random swc point rotations at swc load, paths to swc function, a…
BrysonGray Feb 20, 2025
764e0b0
Add: random swc point rotations at swc load, paths to swc function, a…
BrysonGray Feb 20, 2025
1ac6cc2
Refactor swc and parse_swc_list functions for improved readability an…
BrysonGray Feb 27, 2025
7c02db1
Refactor swc and parse_swc_list functions for improved readability an…
BrysonGray Feb 27, 2025
07886ee
editing branch_classifier for bigneuron data
BrysonGray Feb 28, 2025
e873ca4
editing branch_classifier for bigneuron data
BrysonGray Feb 28, 2025
fc684a4
Add spherical branch extraction, 2D ResNet, and fix parse_swc function
BrysonGray Mar 13, 2025
5240250
Add spherical branch extraction, 2D ResNet, and fix parse_swc function
BrysonGray Mar 13, 2025
7e876ca
Add collect spherical patch dataset function.
BrysonGray Mar 14, 2025
34032a6
Add collect spherical patch dataset function.
BrysonGray Mar 14, 2025
0c12379
Modify branch dataset collection for modularity.
BrysonGray Mar 18, 2025
30a2969
Modify branch dataset collection for modularity.
BrysonGray Mar 18, 2025
cc23b84
Debugging collect branch classifier data.
BrysonGray Mar 19, 2025
23d2a84
Debugging collect branch classifier data.
BrysonGray Mar 19, 2025
5ae8835
Fixes to data filtering for collection.
BrysonGray Mar 20, 2025
63f8a3a
Fixes to data filtering for collection.
BrysonGray Mar 20, 2025
757bdd3
Add fast spherical sampling using precomputed weights.
BrysonGray Mar 22, 2025
f65af81
Add fast spherical sampling using precomputed weights.
BrysonGray Mar 22, 2025
0c7916a
Change save_spherical_patches output file type from pytorch (.pt) to …
BrysonGray Mar 24, 2025
03abeea
Change save_spherical_patches output file type from pytorch (.pt) to …
BrysonGray Mar 24, 2025
25d02c7
Filter branch classifier data for small branches.
BrysonGray Mar 25, 2025
79d4a13
Filter branch classifier data for small branches.
BrysonGray Mar 25, 2025
f0798c6
Filtering branch size
BrysonGray Mar 26, 2025
cfd4a29
Filtering branch size
BrysonGray Mar 26, 2025
ae9de90
Update configurations and improve data processing for neuron simulati…
BrysonGray Apr 3, 2025
c7564d5
Update configurations and improve data processing for neuron simulati…
BrysonGray Apr 3, 2025
d9ad940
Add configuration files for SAC inference and training with artifacts
BrysonGray Apr 5, 2025
f9ed5e7
Add configuration files for SAC inference and training with artifacts
BrysonGray Apr 5, 2025
e2fd5b9
Refactor line segment length calculation and patch radius determinati…
BrysonGray Apr 6, 2025
c3959a9
Refactor line segment length calculation and patch radius determinati…
BrysonGray Apr 6, 2025
0d6c18b
Refactor manual_step function in tracking_interface.py to improve plo…
BrysonGray May 29, 2025
6ec9c16
Refactor manual_step function in tracking_interface.py to improve plo…
BrysonGray May 29, 2025
d1a71cc
Enhance manual step functionality and update data saving format
BrysonGray Jun 3, 2025
fc17636
Enhance manual step functionality and update data saving format
BrysonGray Jun 3, 2025
6a73a08
Refactor code structure for improved readability and maintainability
BrysonGray Jun 3, 2025
54b7d89
Refactor code structure for improved readability and maintainability
BrysonGray Jun 3, 2025
a0a4734
Merge branch 'develop' of https://github.com/BrysonGray/neurotrack in…
BrysonGray Jun 3, 2025
77af6db
Merge branch 'develop' of https://github.com/BrysonGray/neurotrack in…
BrysonGray Jun 3, 2025
6568349
Refactor SAC implementation for improved performance and flexibility …
BrysonGray Jun 6, 2025
c3ea578
Refactor SAC implementation for improved performance and flexibility …
BrysonGray Jun 6, 2025
f938cc2
Refactor branch_classifier and sac modules
BrysonGray Jun 25, 2025
109c477
Refactor branch_classifier and sac modules
BrysonGray Jun 25, 2025
f79f30c
Edit jupyter notebooks for public sharing.
BrysonGray Jun 26, 2025
3203b3b
Edit jupyter notebooks for public sharing.
BrysonGray Jun 26, 2025
d9b93d3
remove nonpublic files from cache
BrysonGray Jun 26, 2025
cf26baa
remove nonpublic files from cache
BrysonGray Jun 26, 2025
c323a4f
delete sac_inference_simulated.json
BrysonGray Jun 26, 2025
4b88ed4
delete sac_inference_simulated.json
BrysonGray Jun 26, 2025
185513f
Merge pull request #5 from BrysonGray/develop
BrysonGray Jun 26, 2025
283dd8e
Update README.md
BrysonGray Jun 27, 2025
d3d2c97
Update README.md
BrysonGray Jun 27, 2025
e71f53c
Update documentation.yml
BrysonGray Jun 27, 2025
42a9b9d
Change evaluation of best trial during tracking inference from neuron…
BrysonGray Jul 9, 2025
0c5edef
Add generation of swc_lists with random segment widths, and drawing n…
BrysonGray Jul 10, 2025
95988c1
- Update models and environment to handle grayscale and uint8 images.
BrysonGray Aug 22, 2025
f83d1bb
Fix bug with save_paths option in sac.inference().
BrysonGray Aug 22, 2025
e68d70a
Cleanup outdated code comments.
BrysonGray Aug 22, 2025
9d34f7c
Enhance SAC training and inference functionality
BrysonGray Aug 29, 2025
a25cfdc
Add stochastic option to inference function for action selection
BrysonGray Aug 29, 2025
5ed536e
Enhance image display and improve alpha loss calculation
BrysonGray Sep 5, 2025
c57ca9c
Added new data generation and online image sampling methods based on …
BrysonGray Nov 5, 2025
4b4adab
Merge new data generation methods and other minor updates from branch…
BrysonGray Mar 23, 2026
c701c96
Update .gitignore to include additional file types for exclusion
BrysonGray Mar 23, 2026
e434735
Resolve conflicts by preferring local changes
BrysonGray Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ jobs:

# Deploy the newly generated html pages to the GitHub Pages associated with this repo
- name: Deploy to GitHub Pages
if: github.repository == 'brysongray/neurotrack'
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/build/html
publish_dir: docs/build/html
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,16 @@ dmypy.json
# Training data and model weights
*.pt
*.csv
*.tif
*.swc

*.html
*.pdf
*.png
*.jpg
*.jpeg
*.gif
*.zip
*.out
*.json
*.ipynb
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,13 @@ No non-standard hardware is required, but this library uses pytorch which can us

Examples for usage are given in Jupyter notebooks in the notebooks folder of the github repository.

## Example neuron tracking results

Gray surface is the true neuron, red surface is the result of automated tracing.

![hippo](https://media.giphy.com/media/ZEcTAh6nwSrbRMdMDS/giphy.gif)

![hippo](https://media.giphy.com/media/7Vu79HIrW4XROOVX03/giphy.gif)

![hippo](https://media.giphy.com/media/Qlkpz2BHlb1bjyHEmo/giphy.gif)

87 changes: 78 additions & 9 deletions bin/classifier_train.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
"""

import argparse
from glob import glob
import os
from pathlib import Path
import sys
import torch

sys.path.append(str(Path(__file__).parents[1]))
from torch.utils.data import DataLoader
script_path = Path(os.path.abspath(__file__))
parent_dir = script_path.parent.parent # Go up two levels
sys.path.append(str(parent_dir))
import models
from solvers import branch_classifier

Expand All @@ -25,19 +28,24 @@ def main():
-o, --out: Path to output directory.
-l, --learning_rate: Optimizer learning rate.
-N, --epochs: Number of training epochs.
-w --weights: pretrained model weights
"""
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--source', type=str, help='Source directory containing labels as csv files and input images folder (observations).')
parser.add_argument('-o','--out', type=str, help="Path to output directory.")
parser.add_argument('-c', '--channels', type=int, default=3, help='Number of input channels in the images.')
parser.add_argument('-l', '--learning_rate', type=float, default=0.001, help='Optimizer learning rate.')
parser.add_argument('-N', '--epochs', type=int, default=15, help='Number of training epochs.')
parser.add_argument('-w', '--weights', type=str, default=None, help='pretrained model weights')

args = parser.parse_args()
source = args.source
out_dir = args.out
lr = args.learning_rate
epochs = args.epochs

weights = args.weights
channels = args.channels

source_list = os.listdir(source)
training_labels_file = [f for f in source_list if 'training_labels' in f][0]
training_labels_file = os.path.join(source, training_labels_file)
Expand All @@ -49,30 +57,91 @@ def main():
if not os.path.exists(test_labels_file):
raise FileNotFoundError("Source directory must contain a csv file with `test_labels` in the filename,\
but none was found")
img_dir = os.path.join(source, 'observations')
img_dir = [d for d in source_list if 'observations' in d][0]
img_dir = os.path.join(source, img_dir)
if not os.path.exists(img_dir):
raise FileNotFoundError("Source directory must contain a folder named `observations`,\
but none was found.")

transform = branch_classifier.transform # random permutation and flip
training_data = branch_classifier.StateData(labels_file=training_labels_file,
img_dir=img_dir,
transform=transform)
img_dir=img_dir,transform=transform)
test_data = branch_classifier.StateData(labels_file=test_labels_file,
img_dir=img_dir)

training_dataloader = branch_classifier.init_dataloader(training_data)
test_dataloader = branch_classifier.init_dataloader(test_data)
training_dataloader = branch_classifier.init_dataloader(training_data, batchsize=64)
test_dataloader = branch_classifier.init_dataloader(test_data, batchsize=64)

if not os.path.exists(out_dir):
os.makedirs(out_dir, exist_ok=True)

classifier = models.ResNet(models.ResidualBlock, [3, 4, 6, 3], num_classes=1)
# classifier = models.ResNet2D(models.ResidualBlock2D, [3, 4, 6, 3], in_channels=36, num_classes=1)
classifier = models.ResNet3D(models.ResidualBlock3D, [3, 4, 6, 3], in_channels=channels, num_classes=1)
classifier = classifier.to(device=DEVICE, dtype=dtype)

if weights is not None:
state_dict = torch.load(weights, map_location=DEVICE)
classifier.load_state_dict(state_dict)
print(f"Loaded pretrained weights from {weights}")

branch_classifier.train(training_dataloader, test_dataloader, out_dir, lr, epochs, classifier, state_dict=None)

return


# # TODO: Change to online data sampling from swc and image files
# def main():
# """
# Main function to train the branch classifier model.

# Arguments
# ---------
# -s, --swc_dir: Source directory containing the neuron trees in swc format.
# -i, --image_dir: Source directory containing the input images.
# -o, --out: Path to output directory.
# -l, --learning_rate: Optimizer learning rate.
# -N, --epochs: Number of training epochs.
# -w, --weights: pretrained model weights
# """
# parser = argparse.ArgumentParser()
# parser.add_argument('-s', '--swc_dir', type=str, help='Source directory containing the neuron trees in swc format.')
# parser.add_argument('-i', '--image_dir', type=str, help='Source directory containing the input images.')
# parser.add_argument('-o', '--out', type=str, help="Path to output directory.")
# parser.add_argument('-l', '--learning_rate', type=float, default=0.001, help='Optimizer learning rate.')
# parser.add_argument('-N', '--epochs', type=int, default=15, help='Number of training epochs.')
# parser.add_argument('-w', '--weights', type=str, default=None, help='pretrained model weights')
# args = parser.parse_args()
# swc_dir = args.swc_dir
# image_dir = args.image_dir
# out_dir = args.out
# lr = args.learning_rate
# epochs = args.epochs
# weights = args.weights
# if not os.path.exists(swc_dir):
# raise FileNotFoundError(f"Source directory {swc_dir} does not exist.")
# if not os.path.exists(image_dir):
# raise FileNotFoundError(f"Source directory {image_dir} does not exist.")
# if not os.path.exists(out_dir):
# os.makedirs(out_dir, exist_ok=True)
# if not os.path.exists(weights):
# raise FileNotFoundError(f"Pretrained weights file {weights} does not exist.")

# swc_files = [f for x in os.walk(swc_dir) for f in glob(os.path.join(x[0], "*.swc"))]
# img_files = [f for x in os.walk(image_dir) for f in glob(os.path.join(x[0], "*image.tif"))]

# classifier = models.ResNet3D(models.ResidualBlock3D, [3, 4, 6, 3], in_channels=3, num_classes=1)
# classifier = classifier.to(device=DEVICE, dtype=dtype)

# if weights is not None:
# state_dict = torch.load(weights, map_location=DEVICE)
# classifier.load_state_dict(state_dict)
# print(f"Loaded pretrained weights from {weights}")

# transform = branch_classifier.transform # random permutation and flip
# branch_classifier.train(swc_files, img_files, out_dir, lr, epochs, classifier, transform=transform)




if __name__ == "__main__":
main()
17 changes: 15 additions & 2 deletions bin/collect_branch_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
import argparse
from datetime import datetime
from glob import glob
import numpy as np
import os
from pathlib import Path
import sys

sys.path.append(str(Path(__file__).parents[1]))
from data_prep import load, collect
from data_prep import load, collect, tree

DATE = datetime.now().strftime("%m-%d-%y")

Expand Down Expand Up @@ -42,20 +43,32 @@ def main():
parser.add_argument('-o','--out', type=str, help="Path to output directory.")
parser.add_argument('-n', '--name', type=str, help='Output filename base.')
parser.add_argument('-a', '--adjust', action='store_true', default=False, help='Set to true if neuron coordinates were rescaled to draw images.')
parser.add_argument('-r', '--remove_soma', action='store_true', default=False, help='Remove edges near the soma from the swc.')
parser.add_argument('--n_samples', type=int, default=100, help='Number of samples to collect from each image file.')
args = parser.parse_args()
labels_dir = args.labels
image_dir = args.images
out_dir = args.out
name = args.name
adjust = args.adjust
remove_soma = args.remove_soma
samples_per_file = args.n_samples

# get sample points from swc files
files = [f for x in os.walk(labels_dir) for f in glob(os.path.join(x[0], '*.swc'))]
swc_lists = []
for f in files:
swc_lists.append(load.swc(f))
swc_list = load.swc(f)
swc_list = np.array(swc_list)
if adjust:
min = np.min(swc_list[:, 2:5], axis=0)
max = np.max(swc_list[:, 2:5], axis=0)
vol = np.prod(max - min)
scale = np.round((5e7 / vol)**(1/3)) # scale depends on the volume
swc_list[...,:3] = (swc_list[...,:3] - min) * scale + np.array([10.0, 10.0, 10.0])
if remove_soma:
swc_list, _ = tree.remove_soma(swc_list, max_radius=7.0)
swc_lists.append(swc_list)
fnames = [f.split('/')[-1].split('.')[0] for f in files]

sample_points = collect.swc_random_points(samples_per_file, swc_lists, fnames, adjust=adjust)
Expand Down
Loading
Loading