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";
35 public float[] mImgEmbedding;
36 public bool isMicro =
false;
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")
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;
66 if (
SAM.theSingleton ==
null)
73 if (points_per_side != 0)
75 this.point_grids = build_all_layer_point_grids(
78 crop_n_points_downscale_factor);
88 List<double[,]> build_all_layer_point_grids(
int n_per_side,
int n_layers,
int scale_per_layer)
90 List<double[,]> points_by_layer =
new List<double[,]>();
91 for (
int i = 0; i <= n_layers; i++)
93 int n_points = (int)(n_per_side / Math.Pow(scale_per_layer, i));
94 points_by_layer.Add(BuildPointGrid(n_points));
96 return points_by_layer;
99 double[,] BuildPointGrid(
int n_per_side)
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))
106 double[,] points =
new double[n_per_side * n_per_side, 2];
108 for (
int i = 0; i < n_per_side; i++)
110 for (
int j = 0; j < n_per_side; j++)
112 int index = i * n_per_side + j;
113 points[index, 0] = points_one_side[i];
114 points[index, 1] = points_one_side[j];
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)
132 int short_side = Math.Min(im_h, im_w);
134 crop_boxes.Add(
new List<int> { 0, 0, im_w, im_h });
137 for (
int i_layer = 0; i_layer < n_layers; i_layer++)
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));
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);
145 List<int> crop_box_x0 =
new List<int>();
146 List<int> crop_box_y0 =
new List<int>();
148 for (
int i = 0; i < n_crops_per_side; i++)
150 crop_box_x0.Add((crop_w - overlap) * i);
151 crop_box_y0.Add((crop_h - overlap) * i);
154 foreach (
int x0
in crop_box_x0)
156 foreach (
int y0
in crop_box_y0)
158 List<int> box =
new List<int>
162 Math.Min(x0 + crop_w, im_w),
163 Math.Min(y0 + crop_h, im_h)
167 layer_idxs.Add(i_layer + 1);
173 int crop_len(
int orig_len,
int n_crops,
int overlap)
175 return (
int)(Math.Ceiling((
double)(overlap * (n_crops - 1) + orig_len) / n_crops));
177 IEnumerable<List<object>> BatchIterator(
int batch_size, params
object[] args)
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++)
183 List<object> batch =
new List<object>();
184 foreach (
object arg
in args)
186 Array arr = (Array)arg;
187 int start = b * batch_size;
188 int end = (b + 1) * batch_size;
189 if (end > arr.Length)
192 Array slice = Array.CreateInstance(arr.GetType().GetElementType(), end - start);
193 Array.Copy(arr, start, slice, 0, end - start);
200 public MaskData Generate(BioImage im,
int buffer)
203 mImgEmbedding = ((List<float[]>)im.Tag)[buffer];
204 if (points_per_side != 0)
206 this.point_grids = build_all_layer_point_grids(
209 crop_n_points_downscale_factor);
211 MaskData masks = this._generate_masks(this.mImage);
214 MaskData _generate_masks(BioImage img)
217 List<List<int>> crop_boxes =
new List<List<int>>();
218 List<int> layer_idxs =
new List<int>();
220 this.generateCropBoxes(img.SizeX, img.SizeY,
this.crop_n_layers,
this.crop_overlap_ratio, ref crop_boxes, ref layer_idxs);
222 for (
int i = 0; i < crop_boxes.Count; i++)
224 MaskData mask = this._process_crop(crop_boxes[i], layer_idxs[i]);
231 MaskData _process_crop(List<int> crop_box,
int crop_layer_idx)
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];
239 for (
int i = 0; i < gps.GetLength(0); i++)
245 points_for_image[i] = ptn;
247 object[] args = { points_for_image };
248 foreach (var v
in BatchIterator(this.points_per_batch, args))
250 MaskData mask = this._process_batch(v.ToList(), r.Width, r.Height, crop_box,
this.mImage.SizeX,
this.mImage.SizeY);
256 MaskData _process_batch(List<object> points,
int cropimgwid,
int cropimghei,List<int>cropbox,
257 int orgimgwid,
int orgimghei)
260 List<float[]> masks =
new List<float[]>();
261 foreach (var v
in points)
264 for (
int i=0;i<pts.Length;i++)
268 md = this.mSAM.
Decode(
new List<Promotion>() { pts[i] }, this.mImgEmbedding, cropimgwid, cropimghei);
271 this.microSAM = (
MicroSAM)this.mSAM;
272 md = this.microSAM.
Decode(
new List<Promotion>() { pts[i] }, this.mImgEmbedding, cropimgwid, cropimghei);
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);
281 batch.mBox = batch.batched_mask_to_box().ToList();