1
+ #@ ImageJ ij
2
+
3
+ '''
4
+ Note that this script requires a Python environment that includes StarDist and Cellpose
5
+ StarDist currently only supports NumPy 1.x, which necessitates using TensorFlow 2.15 or earlier
6
+ TensorFlow 2.15 itself requires python 3.11 or earlier
7
+
8
+ You can rebuild your Python environment by using:
9
+ Edit > Options > Python…
10
+
11
+ The following configuration was used to develop this script:
12
+
13
+ --Conda dependencies--
14
+ python=3.11
15
+ numpy=1.26.4
16
+
17
+ --Pip dependencies--
18
+ tensorflow==2.15
19
+ cellpose==4.0.6
20
+ stardist==0.9.0
21
+ csbdeep==0.8.0
22
+ '''
23
+
24
+ import sys
25
+ import imagej .convert as convert
26
+ import numpy as np
27
+ import matplotlib .pyplot as plt
28
+ from cellpose import models
29
+ from csbdeep .utils import normalize
30
+ from stardist .models import StarDist2D
31
+ import scyjava as sj
32
+
33
+ def filter_index_image (narr :np .ndarray , min_size :int , max_size :int ):
34
+ """
35
+ Filter an index image's labels with a pixel size range.
36
+ """
37
+ unique = np .unique (narr )
38
+ for label in unique :
39
+ if label == 0 :
40
+ # skip the background
41
+ continue
42
+
43
+ # create a crop for each label
44
+ bbox = get_bounding_box (np .where (narr == label ))
45
+ bbox_crop = narr [bbox [0 ]:bbox [2 ] + 1 , bbox [1 ]:bbox [3 ] + 1 ].copy ()
46
+ bbox_crop [bbox_crop != label ] = 0
47
+
48
+ # get the number of pixels in label
49
+ bbox_crop = bbox_crop .astype (bool )
50
+ label_size = np .sum (bbox_crop )
51
+
52
+ if not min_size <= label_size <= max_size :
53
+ narr [narr == label ] = 0
54
+
55
+ return narr
56
+
57
+ def get_bounding_box (indices : np .ndarray ):
58
+ """
59
+ Get the bounding box coordinates from a the label indices.
60
+ """
61
+ # get min and max bounds of indices array
62
+ min_row = np .min (indices [0 ])
63
+ min_col = np .min (indices [1 ])
64
+ max_row = np .max (indices [0 ])
65
+ max_col = np .max (indices [1 ])
66
+
67
+ return (min_row , min_col , max_row , max_col )
68
+
69
+ # open image data and convert to Python from Java
70
+ #TODO does this connection need to be closed?
71
+ data = ij .io ().open ('https://media.imagej.net/pyimagej/3d/hela_a3g.tif' )
72
+ xdata = ij .py .from_java (data )
73
+
74
+ # show the first channel
75
+ ij .ui ().show ("nucleus" , ij .py .to_java (xdata [:, :, 0 ]))
76
+
77
+ # show the second channel
78
+ ij .ui ().show ("cytoplasm" , ij .py .to_java (xdata [:, :, 1 ] * 125 ))
79
+
80
+ # run StarDist on nuclei channel
81
+ model = StarDist2D .from_pretrained ('2D_versatile_fluo' )
82
+ nuc_labels , _ = model .predict_instances (normalize (xdata [:, :, 0 ]))
83
+
84
+ # run Cellpose on cytoplasm (grayscale)
85
+ model = models .CellposeModel (gpu = False , model_type = 'cyto' )
86
+ ch = [0 , 0 ]
87
+ cyto_labels = model .eval (xdata [:, :, 1 ].data , channels = ch , diameter = 72.1 )
88
+
89
+ # show the stardist results
90
+ ij .ui ().show ("StarDist results" , ij .py .to_java (nuc_labels ))
91
+ ij .IJ .run ("mpl-viridis" , "" );
92
+
93
+ # show the second channel
94
+ ij .ui ().show ("Cellpose results" , ij .py .to_java (cyto_labels [0 ]))
95
+ ij .IJ .run ("mpl-viridis" , "" );
96
+
97
+ # filter the stardist results and display
98
+ filter_index_image (nuc_labels , 500 , 10000 )
99
+ ij .ui ().show ("StarDist filtered" , ij .py .to_java (nuc_labels ))
100
+ ij .IJ .run ("mpl-viridis" , "" );
101
+
102
+ # ensure ROI Manager exists
103
+ rm = ij .RoiManager .getInstance ()
104
+ if rm is None :
105
+ ij .IJ .run ("ROI Manager..." )
106
+ rm = ij .RoiManager .getInstance ()
107
+
108
+ # Reset the ROI manager
109
+ rm .reset ()
110
+
111
+ # convert to ImgLib2 ROI in a ROITree
112
+ nuc_roi_tree = convert .index_img_to_roi_tree (ij , nuc_labels )
113
+ cyto_roi_tree = convert .index_img_to_roi_tree (ij , cyto_labels [0 ])
114
+
115
+ # print the contents of the ROITree (nuclear ROIs)
116
+ len (nuc_roi_tree .children ())
117
+ for i in range (len (nuc_roi_tree .children ())):
118
+ print (nuc_roi_tree .children ().get (i ).data ())
119
+
120
+ # display the input data, select channel 2 and enhance the contrast
121
+ data_title = "hela_a3g.tif"
122
+ ij .ui ().show (data_title , data )
123
+ imp = ij .WindowManager .getImage (data_title )
124
+ imp .setC (2 )
125
+ ij .IJ .run (imp , "Enhance Contrast" , "saturated=0.35" )
126
+
127
+ # convert a single ImgLib2 roi to a legacy ImageJ ROI with the ConvertService.
128
+ imglib_polygon_roi = nuc_roi_tree .children ().get (0 ).data ()
129
+ ij_polygon_roi = ij .convert ().convert (imglib_polygon_roi , sj .jimport ('ij.gui.PolygonRoi' ))
130
+ print (type (ij_polygon_roi ))
131
+
132
+ # convert index images to ImageJ ROI in RoiManager
133
+ #TODO any way to color the selections? We can use Colors... but it appears to be global and the last one run wins
134
+ #ij.IJ.run(imp, "Colors...", "foreground=blue background=black selection=red");
135
+ convert .index_img_to_roi_manager (ij , nuc_labels )
136
+ convert .index_img_to_roi_manager (ij , cyto_labels [0 ])
137
+
138
+ #TODO this pops an unnecessary display at the end but if I don't make it the last line the ROIs don't show
139
+ rm .moveRoisToOverlay (imp )
140
+ rm .runCommand (imp , "Show All" )
0 commit comments