From 7ef6f0a4b2e4869facf70f42d694c010d5038922 Mon Sep 17 00:00:00 2001
From: polarbean <harry.carey95@gmail.com>
Date: Wed, 21 Aug 2024 17:02:35 +0200
Subject: [PATCH] add support for brainglobe atlases

---
 PyNutil/main.py                           | 60 ++++++++++++++---------
 messing_around_files/brainglobe.py        | 22 +++++++++
 test/test1.json                           |  3 +-
 test/test10_PyNutil_web.json              |  2 +-
 test/test2.json                           |  3 +-
 test/test3.json                           |  3 +-
 test/test4_2017.json                      |  3 +-
 test/test5_NOP_s037.json                  |  3 +-
 test/test6_artifical.json                 |  2 +-
 test/test7_PyNutil.json                   |  2 +-
 test/test8_PyNutil_bigcaudoputamen.json   |  2 +-
 workflows/calculate_objects_per_region.py |  4 ++
 testOOP.py => workflows/testOOP.py        | 10 ++--
 13 files changed, 77 insertions(+), 42 deletions(-)
 create mode 100644 messing_around_files/brainglobe.py
 rename testOOP.py => workflows/testOOP.py (57%)

diff --git a/PyNutil/main.py b/PyNutil/main.py
index a64249a..57194a4 100644
--- a/PyNutil/main.py
+++ b/PyNutil/main.py
@@ -5,6 +5,8 @@ from .counting_and_load import label_points, pixel_count_per_region
 import json
 import pandas as pd
 from datetime import datetime
+import numpy as np
+import brainglobe_atlasapi
 import os
 
 
@@ -19,8 +21,8 @@ class PyNutil:
         The path to the alignment JSON file.
     colour : int
         The colour of the segmentation data to extract.
-    volume_path : str
-        The name of the atlas volume to use.
+    atlas_name : str
+        The name of the atlas volume to use. Uses BrainGlobe API name
     settings_file : str, optional
         The path to a JSON file containing the above parameters.
 
@@ -76,7 +78,8 @@ class PyNutil:
         segmentation_folder=None,
         alignment_json=None,
         colour=None,
-        volume_path=None,
+        atlas_name=None,
+        atlas_resolution_micron=None,
         settings_file=None,
     ) -> None:
         self.config, self.metadata_path = metadata_loader.load_config()
@@ -87,28 +90,29 @@ class PyNutil:
                 segmentation_folder = settings["segmentation_folder"]
                 alignment_json = settings["alignment_json"]
                 colour = settings["colour"]
-                volume_path = settings["volume_path"]
+                atlas_name = settings["atlas_name"]
             except KeyError as exc:
                 raise KeyError(
-                    "settings file must contain segmentation_folder, alignment_json, colour, and volume_path"
+                    "settings file must contain segmentation_folder, alignment_json, colour, and atlas_name"
                 ) from exc
         # check if any values are None
-        if None in [segmentation_folder, alignment_json, colour, volume_path]:
+        if None in [segmentation_folder, alignment_json, colour, atlas_name]:
             raise ValueError(
                 "segmentation_folder, alignment_json, colour, and volume_path must all be specified and not be None"
             )
-        if volume_path not in self.config["annotation_volumes"]:
-            raise ValueError(
-                f"Atlas {volume_path} not found in config file, valid atlases are: \n{' , '.join(list(self.config['annotation_volumes'].keys()))}"
-            )
+        # if atlas_name not in self.config["annotation_volumes"]:
+        #     raise ValueError(
+        #         f"Atlas {atlas_name} not found in config file, valid atlases are: \n{' , '.join(list(self.config['annotation_volumes'].keys()))}"
+        #     )
 
         self.segmentation_folder = segmentation_folder
         self.alignment_json = alignment_json
         self.colour = colour
-        self.atlas = volume_path
-        self.atlas_volume, self.atlas_labels = self.load_atlas_data()
+        self.atlas_name = atlas_name
+        self.atlas_volume, self.atlas_labels = self.load_atlas_data(atlas_name=atlas_name)
+        ###This is just because of the migration to BrainGlobe
 
-    def load_atlas_data(self):
+    def load_atlas_data(self, atlas_name):
         """Loads the atlas volume and labels from disk.
 
         Returns
@@ -119,16 +123,26 @@ class PyNutil:
         """
         # load the metadata json as well as the path to stored data files
         # this could potentially be moved into init
-        atlas_root_path = self.config["annotation_volume_directory"]
-        current_atlas_path = self.config["annotation_volumes"][self.atlas]["volume"]
         print("loading atlas volume")
-        start_time = datetime.now()
-        atlas_volume = read_atlas_volume(f"{atlas_root_path}{current_atlas_path}")
-        time_taken = datetime.now() - start_time
-        print(f"atlas volume loaded in: {time_taken} ✅")
-        atlas_label_path = self.config["annotation_volumes"][self.atlas]["labels"]
-        print("loading atlas labels")
-        atlas_labels = pd.read_csv(f"{atlas_root_path}{atlas_label_path}")
+        atlas = brainglobe_atlasapi.BrainGlobeAtlas(atlas_name=atlas_name)
+        atlas_structures = {'idx':[i['id'] for i in atlas.structures_list],
+            'name':[i['name'] for i in atlas.structures_list],
+            'r':[i['rgb_triplet'][0] for i in atlas.structures_list],
+            'g':[i['rgb_triplet'][1] for i in atlas.structures_list],
+            'b':[i['rgb_triplet'][2] for i in atlas.structures_list]
+            }
+        atlas_structures['idx'].insert(0,0)
+        atlas_structures['name'].insert(0,'Clear Label')
+        atlas_structures['r'].insert(0,0)
+        atlas_structures['g'].insert(0,0)
+        atlas_structures['b'].insert(0,0)
+
+        atlas_labels = pd.DataFrame(atlas_structures)
+        if  "allen_mouse_" in atlas_name:
+            print("reorienting allen atlas into quicknii space...")
+            atlas_volume = np.transpose(atlas.annotation,[2,0,1])[:,::-1,::-1]
+        else:
+            atlas_volume = atlas.annotation
         print("atlas labels loaded ✅")
         return atlas_volume, atlas_labels
 
@@ -249,7 +263,7 @@ class PyNutil:
             all_region_df = self.atlas_labels.merge(ra, on="idx", how="left")
             current_df_new = all_region_df.merge(
                 current_df, on="idx", how="left", suffixes=(None, "_y")
-            ).drop(columns=["a", "VIS", "MSH", "name_y", "r_y", "g_y", "b_y"])
+            ).drop(columns=["name_y", "r_y", "g_y", "b_y"])
             current_df_new["area_fraction"] = (
                 current_df_new["pixel_count"] / current_df_new["region_area"]
             )
diff --git a/messing_around_files/brainglobe.py b/messing_around_files/brainglobe.py
new file mode 100644
index 0000000..fdd39f8
--- /dev/null
+++ b/messing_around_files/brainglobe.py
@@ -0,0 +1,22 @@
+import brainglobe_atlasapi
+import pandas as pd
+import nrrd
+import matplotlib.pyplot as plt
+import numpy as np
+brainglobe_atlasapi.list_atlases.show_atlases()
+allen = brainglobe_atlasapi.BrainGlobeAtlas('allen_mouse_25um')
+
+keys = allen.structures.keys()
+
+
+
+##current structure format 
+labels = pd.read_csv(r'/home/harryc/github/PyNutil/PyNutil/metadata/annotation_volumes/allen2017_colours.csv')
+
+labels
+
+
+orig_vol = nrrd.read(r"/home/harryc/github/PyNutil/PyNutil/metadata/annotation_volumes/annotation_25_reoriented_2017.nrrd")
+
+plt.imshow(orig_vol[0][200]>0)
+
diff --git a/test/test1.json b/test/test1.json
index 0355d8c..ca83423 100644
--- a/test/test1.json
+++ b/test/test1.json
@@ -1,5 +1,4 @@
-{   "volume_path": "allen2017",
-    "label_path": "annotation_volumes/allen2017_colours.csv",
+{   "atlas_name": "allen_mouse_25um",
     "segmentation_folder": "test_data/ttA_2877_NOP_segmentations",
     "alignment_json": "test_data/ttA_2877_NOP_horizontal_final_2017.json",
     "nonlinear": true,
diff --git a/test/test10_PyNutil_web.json b/test/test10_PyNutil_web.json
index fd8a95a..397836f 100644
--- a/test/test10_PyNutil_web.json
+++ b/test/test10_PyNutil_web.json
@@ -1,5 +1,5 @@
 {
-  "volume_path": "allen2017",
+  "atlas_name": "allen_mouse_25um",
   "label_path": "PyNutil/annotation_volumes/allen2017_colours.csv",
   "segmentation_folder": "PyNutil/test_data/PyTest_web",
   "alignment_json": "PyNutil/test_data/PyNutil_test.waln",
diff --git a/test/test2.json b/test/test2.json
index 9618297..f3ba1f3 100644
--- a/test/test2.json
+++ b/test/test2.json
@@ -1,5 +1,4 @@
-{   "volume_path": "../annotation_volumes/annotation_10_reoriented_2022.nrrd",
-    "label_path": "../annotation_volumes/allen2022_colours_updated.csv",
+{   "atlas_name": "allen_mouse_25um",
     "segmentation_folder": "../test_data/oneSection15",
     "alignment_json": "../test_data/C68_nonlinear_no_markers.json",
     "nonlinear": true,
diff --git a/test/test3.json b/test/test3.json
index 1c9343f..fb6838e 100644
--- a/test/test3.json
+++ b/test/test3.json
@@ -1,5 +1,4 @@
-{   "volume_path": "allen2017",
-    "label_path": "annotation_volumes/allen2017_colours.csv",
+{   "atlas_name": "allen_mouse_25um",
     "segmentation_folder": "test_data/oneSection15",
     "alignment_json": "test_data/C68_nonlinear.json",
     "nonlinear": true,
diff --git a/test/test4_2017.json b/test/test4_2017.json
index bdb3959..4545491 100644
--- a/test/test4_2017.json
+++ b/test/test4_2017.json
@@ -1,5 +1,4 @@
-{   "volume_path": "allen2017",
-    "label_path": "annotation_volumes/allen2017_colours.csv",
+{   "atlas_name": "allen_mouse_25um",
     "segmentation_folder": "test_data/oneSection15",
     "alignment_json": "test_data/C68_nonlinear_no_markers.json",
     "nonlinear": true,
diff --git a/test/test5_NOP_s037.json b/test/test5_NOP_s037.json
index d53d90f..3155140 100644
--- a/test/test5_NOP_s037.json
+++ b/test/test5_NOP_s037.json
@@ -1,5 +1,4 @@
-{   "volume_path": "allen2017",
-    "label_path": "annotation_volumes/allen2017_colours.csv",
+{   "atlas_name": "allen_mouse_25um",
     "segmentation_folder": "test_data/ttA_2877_NOP_s037_seg",
     "alignment_json": "test_data/ttA_2877_NOP_horizontal_final_2017.json",
     "nonlinear": false,
diff --git a/test/test6_artifical.json b/test/test6_artifical.json
index c8f58ec..0de2663 100644
--- a/test/test6_artifical.json
+++ b/test/test6_artifical.json
@@ -1,4 +1,4 @@
-{   "volume_path": "../annotation_volumes/annotation_10_reoriented_2017.nrrd",
+{   "atlas_name": "allen_mouse_25um",
     "label_path": "../annotation_volumes/allen2017_colours.csv",
     "segmentation_folder": "../test_data/ttA_2877_NOP_segmentations",
     "alignment_json": "../test_data/ttA_2877_NOP_horizontal_final_2017.json",
diff --git a/test/test7_PyNutil.json b/test/test7_PyNutil.json
index 07d54af..9cbfa89 100644
--- a/test/test7_PyNutil.json
+++ b/test/test7_PyNutil.json
@@ -1,4 +1,4 @@
-{   "volume_path": "allen2017",
+{   "atlas_name": "allen_mouse_25um",
     "label_path": "annotation_volumes/allen2017_colours.csv",
     "segmentation_folder": "test_data/PyTest_seg",
     "alignment_json": "test_data/PyNutil_testdataset_Nonlin_SY.json",
diff --git a/test/test8_PyNutil_bigcaudoputamen.json b/test/test8_PyNutil_bigcaudoputamen.json
index 7c26469..089d7f9 100644
--- a/test/test8_PyNutil_bigcaudoputamen.json
+++ b/test/test8_PyNutil_bigcaudoputamen.json
@@ -1,5 +1,5 @@
 {
-  "volume_path": "allen2017",
+  "atlas_name": "allen_mouse_25um",
   "label_path": "PyNutil/annotation_volumes/allen2017_colours.csv",
   "segmentation_folder": "PyNutil/test_data/PyTest_bigcaudoputamen_seg",
   "alignment_json": "PyNutil/test_data/PyNutil_testdataset_Nonlin_SY_fixed_bigcaudoputamen.json",
diff --git a/workflows/calculate_objects_per_region.py b/workflows/calculate_objects_per_region.py
index a72a549..dcb3fbd 100644
--- a/workflows/calculate_objects_per_region.py
+++ b/workflows/calculate_objects_per_region.py
@@ -1,3 +1,7 @@
+import os
+import sys
+sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
 import cv2
 from skimage import measure
 
diff --git a/testOOP.py b/workflows/testOOP.py
similarity index 57%
rename from testOOP.py
rename to workflows/testOOP.py
index 63cb085..52b11fc 100644
--- a/testOOP.py
+++ b/workflows/testOOP.py
@@ -1,10 +1,10 @@
+import sys
+import os
+sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 from PyNutil import PyNutil
 import os
 
-os.chdir("..")
-
-
-pnt = PyNutil(settings_file=r"PyNutil/test/test10_PyNutil_web.json")
+pnt = PyNutil(settings_file=r"test/test8_PyNutil_bigcaudoputamen.json")
 
 ##use_flat can be set to True if you want to use the flat file
 ## for method select between "all", "per_pixel" and "per_object"
@@ -12,7 +12,7 @@ pnt.get_coordinates(object_cutoff=0, method="all", use_flat=False)
 
 pnt.quantify_coordinates()
 
-pnt.save_analysis("PyNutil/outputs/test10_PyNutil_web_all")
+pnt.save_analysis("../PyNutil/outputs/test9_PyNutil_bigcaudoputamen_new")
 
 # remove name, r, g, b, from pixel_
 # add to region_areas df
-- 
GitLab