BioGTK  6.7.0
A .NET library & program for annotating, editing various microscopy imaging formats using Bioformats supported images. Including whole slide, pyramidal, and series.
Loading...
Searching...
No Matches
AutoSAM.cs
1using AForge;
2using BioGTK;
3using Microsoft.ML.OnnxRuntime;
4using Microsoft.ML.OnnxRuntime.Tensors;
5using System;
6using System.Collections.Generic;
7using System.IO;
8using System.Linq;
9using System.Text;
10using System.Threading;
11using System.Threading.Tasks;
12using System.Windows;
13
14namespace BioGTK
15{
16
17 class AutoSAM
18 {
19 public int points_per_side = 4;
20 int points_per_batch = 64;
21 public float pred_iou_thresh = 0.88f;
22 public float stability_score_thresh = 0.95f;
23 float stability_score_offset = 1.0f;
24 float box_nms_thresh = 0.7f;
25 int crop_n_layers = 0;
26 float crop_nms_thresh = 0.7f;
27 float crop_overlap_ratio = (float)512 / 1500;
28 int crop_n_points_downscale_factor = 1;
29 List<double[,]> point_grids = null;
30 int min_mask_region_area = 0;
31 string output_mode = "binary_mask";
32 BioImage mImage;
33 public SAM mSAM;
34 public MicroSAM microSAM;
35 public float[] mImgEmbedding;
36 public bool isMicro = false;
37
38 public AutoSAM(int points_per_side = 4,
39 int points_per_batch = 64,
40 float pred_iou_thresh = 0.5f,
41 float stability_score_thresh = 0.5f,
42 float stability_score_offset = 1.0f,
43 float box_nms_thresh = 0.7f,
44 int crop_n_layers = 0,
45 float crop_nms_thresh = 0.7f,
46 float crop_overlap_ratio = (float)512 / 1500,
47 int crop_n_points_downscale_factor = 1,
48 List<double[,]> point_grids = null,
49 int min_mask_region_area = 0,
50 string output_mode = "binary_mask")
51 {
52 this.points_per_side = points_per_side;
53 this.points_per_batch = points_per_batch;
54 this.pred_iou_thresh = pred_iou_thresh;
55 this.stability_score_thresh = stability_score_thresh;
56 this.stability_score_offset = stability_score_offset;
57 this.box_nms_thresh = box_nms_thresh;
58 this.crop_n_layers = crop_n_layers;
59 this.crop_nms_thresh = crop_nms_thresh;
60 this.crop_overlap_ratio = crop_overlap_ratio;
61 this.crop_n_points_downscale_factor = crop_n_points_downscale_factor;
62 this.point_grids = point_grids;
63 this.min_mask_region_area = min_mask_region_area;
64 this.output_mode = output_mode;
65
66 if (SAM.theSingleton == null)
67 {
68 mSAM = MicroSAM.Instance();
69 this.isMicro = true;
70 }
71 else
72 mSAM = SAM.Instance();
73 if (points_per_side != 0)
74 {
75 this.point_grids = build_all_layer_point_grids(
76 points_per_side,
77 crop_n_layers,
78 crop_n_points_downscale_factor);
79 }
80 }
88 List<double[,]> build_all_layer_point_grids(int n_per_side, int n_layers, int scale_per_layer)
89 {
90 List<double[,]> points_by_layer = new List<double[,]>();
91 for (int i = 0; i <= n_layers; i++)
92 {
93 int n_points = (int)(n_per_side / Math.Pow(scale_per_layer, i));
94 points_by_layer.Add(BuildPointGrid(n_points));
95 }
96 return points_by_layer;
97 }
98
99 double[,] BuildPointGrid(int n_per_side)
100 {
101 double offset = 1.0 / (2 * n_per_side);
102 double[] points_one_side = Enumerable.Range(0, n_per_side)
103 .Select(i => offset + i * (1.0 - 2 * offset) / (n_per_side - 1))
104 .ToArray();
105
106 double[,] points = new double[n_per_side * n_per_side, 2];
107
108 for (int i = 0; i < n_per_side; i++)
109 {
110 for (int j = 0; j < n_per_side; j++)
111 {
112 int index = i * n_per_side + j;
113 points[index, 0] = points_one_side[i];
114 points[index, 1] = points_one_side[j];
115 }
116 }
117
118 return points;
119 }
120
121
126 void generateCropBoxes(int orgWid, int orgHei, int n_layers, float overlap_ratio,
127 ref List<List<int>> crop_boxes, ref List<int> layer_idxs)
128 {
129 int im_h = orgHei;
130 int im_w = orgWid;
131
132 int short_side = Math.Min(im_h, im_w);
133 //Original image
134 crop_boxes.Add(new List<int> { 0, 0, im_w, im_h });
135 layer_idxs.Add(0);
136
137 for (int i_layer = 0; i_layer < n_layers; i_layer++)
138 {
139 int n_crops_per_side = (int)Math.Pow(2, i_layer + 1);
140 int overlap = (int)(overlap_ratio * short_side * (2 / n_crops_per_side));
141
142 int crop_w = crop_len(im_w, n_crops_per_side, overlap);
143 int crop_h = crop_len(im_h, n_crops_per_side, overlap);
144
145 List<int> crop_box_x0 = new List<int>();
146 List<int> crop_box_y0 = new List<int>();
147
148 for (int i = 0; i < n_crops_per_side; i++)
149 {
150 crop_box_x0.Add((crop_w - overlap) * i);
151 crop_box_y0.Add((crop_h - overlap) * i);
152 }
153
154 foreach (int x0 in crop_box_x0)
155 {
156 foreach (int y0 in crop_box_y0)
157 {
158 List<int> box = new List<int>
159 {
160 x0,
161 y0,
162 Math.Min(x0 + crop_w, im_w),
163 Math.Min(y0 + crop_h, im_h)
164 };
165
166 crop_boxes.Add(box);
167 layer_idxs.Add(i_layer + 1);
168 }
169 }
170
171 }
172 }
173 int crop_len(int orig_len, int n_crops, int overlap)
174 {
175 return (int)(Math.Ceiling((double)(overlap * (n_crops - 1) + orig_len) / n_crops));
176 }
177 IEnumerable<List<object>> BatchIterator(int batch_size, params object[] args)
178 {
179
180 int n_batches = ((Array)args[0]).Length / batch_size + (((Array)args[0]).Length % batch_size != 0 ? 1 : 0);
181 for (int b = 0; b < n_batches; b++)
182 {
183 List<object> batch = new List<object>();
184 foreach (object arg in args)
185 {
186 Array arr = (Array)arg;
187 int start = b * batch_size;
188 int end = (b + 1) * batch_size;
189 if (end > arr.Length)
190 end = arr.Length;
191
192 Array slice = Array.CreateInstance(arr.GetType().GetElementType(), end - start);
193 Array.Copy(arr, start, slice, 0, end - start);
194 batch.Add(slice);
195 }
196
197 yield return batch;
198 }
199 }
200 public MaskData Generate(BioImage im, int buffer)
201 {
202 this.mImage = im;
203 mImgEmbedding = ((List<float[]>)im.Tag)[buffer];
204 if (points_per_side != 0)
205 {
206 this.point_grids = build_all_layer_point_grids(
207 points_per_side,
208 crop_n_layers,
209 crop_n_points_downscale_factor);
210 }
211 MaskData masks = this._generate_masks(this.mImage);
212 return masks;
213 }
214 MaskData _generate_masks(BioImage img)
215 {
216 MaskData masks = new MaskData();
217 List<List<int>> crop_boxes = new List<List<int>>();
218 List<int> layer_idxs = new List<int>();
219
220 this.generateCropBoxes(img.SizeX, img.SizeY, this.crop_n_layers, this.crop_overlap_ratio, ref crop_boxes, ref layer_idxs);
221
222 for (int i = 0; i < crop_boxes.Count; i++)
223 {
224 MaskData mask = this._process_crop(crop_boxes[i], layer_idxs[i]);
225 masks.Cat(mask);
226 }
227
228 return masks;
229 }
230
231 MaskData _process_crop(List<int> crop_box, int crop_layer_idx)
232 {
233 MaskData masks = new MaskData();
234 int x0 = crop_box[0], y0 = crop_box[1], x1 = crop_box[2], y1 = crop_box[3];
235 Rectangle r = new Rectangle(x0, y0, x1, y1);
236 double[,] gps = this.point_grids[crop_layer_idx];
237 PointPromotion[] points_for_image = new PointPromotion[gps.GetLength(0)];
238 Transforms ts = new Transforms(1024);
239 for (int i = 0; i < gps.GetLength(0); i++)
240 {
241 Promotion promt = new PointPromotion(ForeGround.foreground);
242 (promt as PointPromotion).X = (int)(gps[i, 0] * r.Width);
243 (promt as PointPromotion).Y = (int)(gps[i, 1] * r.Height);
244 PointPromotion ptn = ts.ApplyCoords((promt as PointPromotion), r.Width, r.Height);
245 points_for_image[i] = ptn;
246 }
247 object[] args = { points_for_image };
248 foreach (var v in BatchIterator(this.points_per_batch, args))
249 {
250 MaskData mask = this._process_batch(v.ToList(), r.Width, r.Height, crop_box, this.mImage.SizeX, this.mImage.SizeY);
251 masks.Cat(mask);
252 }
253 return masks;
254 }
255
256 MaskData _process_batch(List<object> points,int cropimgwid,int cropimghei,List<int>cropbox,
257 int orgimgwid, int orgimghei)
258 {
259 MaskData batch = new MaskData();
260 List<float[]> masks = new List<float[]>();
261 foreach (var v in points)
262 {
263 PointPromotion[] pts = v as PointPromotion[];
264 for (int i=0;i<pts.Length;i++)
265 {
266 MaskData md = null;
267 if (MicroSAM.theSingleton == null)
268 md = this.mSAM.Decode(new List<Promotion>() { pts[i] }, this.mImgEmbedding, cropimgwid, cropimghei);
269 else
270 {
271 this.microSAM = (MicroSAM)this.mSAM;
272 md = this.microSAM.Decode(new List<Promotion>() { pts[i] }, this.mImgEmbedding, cropimgwid, cropimghei);
273 }
274 md.mStability = md.CalculateStabilityScore(this.mSAM.mask_threshold, this.stability_score_offset).ToList();
275 md.Filter(this.pred_iou_thresh, this.stability_score_thresh);
276 batch.Cat(md);
277 }
278
279 }
280
281 batch.mBox = batch.batched_mask_to_box().ToList();
282 return batch;
283 }
284
285 }
286}
A structure for storing masks and their related data in batched format. Implements basic filtering an...
Definition MaskData.cs:14
new float[] Decode(BioImage b, List< Promotion > promotions, int orgWid, int orgHei)
Definition MicroSAM.cs:152
static new MicroSAM Instance()
Definition MicroSAM.cs:36
float[] Decode(BioImage b, List< Promotion > promotions, int orgWid, int orgHei)
Definition SAM.cs:153
static SAM Instance()
Definition SAM.cs:33
PointPromotion ApplyCoords(PointPromotion org_point, int orgw, int orgh)
Definition ML.cs:17