BioImager  5.0.0
A .NET microscopy imaging application based on Bio library. Supports various microscopes by using imported libraries & GUI automation. Supports XInput game controllers to move stage, take images, run ImageJ macros on images or Bio C# scripts.
Loading...
Searching...
No Matches
SlideImager.cs
Go to the documentation of this file.
1using AForge;
2using NetVips;
3using System;
4using System.Collections.Generic;
5using System.ComponentModel;
6using System.Data;
7using System.Diagnostics;
8using System.Drawing;
9using System.IO.Compression;
10using System.Linq;
11using System.Text;
12using System.Threading.Tasks;
13using System.Windows.Forms;
14using BioLib;
15namespace BioImager
16{
17 public partial class SlideImager : Form
18 {
19 private static Stopwatch Stopwatch = new Stopwatch();
25 public static PointD ToImageSpace(PointD p, PointD stage, double physX, double physY)
26 {
27 PointD pp = new PointD();
28 pp.X = (float)((p.X - stage.X) / physX);
29 pp.Y = (float)((p.Y - stage.Y) / physY);
30 return pp;
31 }
32 public class BaseLevel
33 {
34 public double Focus { get; set; }
35 public int Objective { get; set; }
36 public BaseLevel(double focus, int objective)
37 {
38 Focus = focus;
39 Objective = objective;
40 }
41 public override string ToString()
42 {
43 return "Focus:" + Focus + ", Objective:" + Objective;
44 }
45 }
46 public class Level
47 {
48 public List<Level> Levels = new List<Level>();
49 public Level Parent { get; set; } = null;
50 public Point3D Location { get; set; }
51 public List<BioImage> BioImages { get; set; } = new List<BioImage>();
52 public int Objective { get; set; }
53 public double Focus { get; set; }
54 public NetVips.Image VipsImage { get; set; }
55 public PixelFormat PixelFormat { get; set; }
56 public double PhysicalX { get; set; }
57 public double PhysicalY { get; set; }
58 public AForge.Bitmap Image { get; set; } = null;
59 public double Width { get; set; }
60 public double Height { get; set; }
61 public int Index { get; set; }
62 public double WidthPx { get { return Width / PhysicalX; } }
63 public double HeightPx { get { return Height / PhysicalY; } }
64 public List<Channel> Channels = new List<Channel>();
65 public Enums.ForeignTiffCompression Compression { get; set; }
66 public int CompressionLevel { get; set; }
67 public void Init(double w, double h, PixelFormat pf, int index)
68 {
70 int wi = (int)(w / r.W);
71 int hi = (int)(h / r.H);
72 double xx = 2 * index;
73 if(index==0)
74 Image = new AForge.Bitmap((int)(w / PhysicalX), (int)(h / PhysicalY), pf);
75 else
76 Image = new AForge.Bitmap((int)(w / PhysicalX / xx), (int)(h / PhysicalY / xx), pf);
77 int bands = BioImage.GetBands(pf);
78 if (Image.BitsPerPixel > 8)
79 VipsImage = NetVips.Image.NewFromMemory(Image.Data, (ulong)Image.Length, Image.Width, Image.Height, bands, Enums.BandFormat.Ushort);
80 else
81 VipsImage = NetVips.Image.NewFromMemory(Image.Data, (ulong)Image.Length, Image.Width, Image.Height, bands, Enums.BandFormat.Uchar);
82 }
83 public Level(double w, double h, PixelFormat pf, int levels, Enums.ForeignTiffCompression comp, double physX, double physY)
84 {
85 PhysicalX = physX; PhysicalY = physY;
86 Compression = comp;
87 for (int i = 0; i < levels; i++)
88 {
89 Levels.Add(new Level(w, h, pf));
90 Levels[i].Parent = this;
91 }
92 }
93 public Level(double w, double h, PixelFormat pf)
94 {
95 Width = w; Height = h; PixelFormat = pf;
96 }
97 public void SaveLevel(string file)
98 {
99 string met = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" +
100 "<OME xmlns=\"http://www.openmicroscopy.org/Schemas/OME/2016-06\" " +
101 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
102 "xsi:schemaLocation=\"http://www.openmicroscopy.org/Schemas/OME/2016-06 http://www.openmicroscopy.org/Schemas/OME/2016-06/ome.xsd\">";
103 int c = Parent.Image.RGBChannelsCount;
104 string endian = Parent.Image.LittleEndian.ToString().ToLower();
105 int ib = 0;
106 met +=
107 "<Image ID=\"Image:" + ib + "\">" +
108 "<Pixels BigEndian=\"" + endian + "\" DimensionOrder= \"XYCZT\" ID= \"Pixels:0\" Interleaved=\"true\" " +
109 "PhysicalSizeX=\"" + PhysicalX + "\" PhysicalSizeXUnit=\"µm\" PhysicalSizeY=\"" + PhysicalY + "\" PhysicalSizeYUnit=\"µm\" SignificantBits=\"" + Parent.Image.BitsPerPixel + "\" " +
110 "SizeC = \"" + c + "\" SizeT = \"" + 1 + "\" SizeX =\"" + Parent.Image.Width +
111 "\" SizeY= \"" + Parent.Image.Height + "\" SizeZ=\"" + 1;
112 if (Parent.Image.BitsPerPixel > 8) met += "\" Type= \"uint16\">";
113 else met += "\" Type= \"uint8\">";
114 int i = 0;
115 foreach (Channel ch in Channels)
116 {
117 met += "<Channel ID=\"Channel:" + ib + ":" + i + "\" SamplesPerPixel=\"1\"></Channel>";
118 i++;
119 }
120 met += "</Pixels></Image></OME>";
121 A:
122 try
123 {
124 using var mutated = Parent.VipsImage.Mutate(mutable =>
125 {
126 // Set the ImageDescription tag
127 mutable.Set(GValue.GStrType, "image-description", met);
128 mutable.Set(GValue.GIntType, "page-height", Parent.Image.Height);
129 });
130 if (Parent.Image.BitsPerPixel > 8)
131 mutated.Tiffsave(file, Compression, 1, Enums.ForeignTiffPredictor.None, true, (int)512, (int)512, true, false, 16,
132 Enums.ForeignTiffResunit.Cm, 1000 * PhysicalX, 1000 * PhysicalY, true, null, Enums.RegionShrink.Nearest,
133 CompressionLevel, true, Enums.ForeignDzDepth.Onetile, true, false, null, null, (int)Parent.Image.Height);
134 else
135 mutated.Tiffsave(file, Compression, 1, Enums.ForeignTiffPredictor.None, true, (int)512, (int)512, true, false, 8,
136 Enums.ForeignTiffResunit.Cm, 1000 * PhysicalX, 1000 * PhysicalY, true, null, Enums.RegionShrink.Nearest,
137 CompressionLevel, true, Enums.ForeignDzDepth.Onetile, true, false, null, null, (int)Parent.Image.Height);
138 }
139 catch (Exception e)
140 {
141 Console.WriteLine(e.ToString());
142 goto A;
143 }
144
145
146 }
147 public void SaveLevels(string file)
148 {
149 string met = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" +
150 "<OME xmlns=\"http://www.openmicroscopy.org/Schemas/OME/2016-06\" " +
151 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
152 "xsi:schemaLocation=\"http://www.openmicroscopy.org/Schemas/OME/2016-06 http://www.openmicroscopy.org/Schemas/OME/2016-06/ome.xsd\">";
153 int c = Image.RGBChannelsCount;
154 string endian = Image.LittleEndian.ToString().ToLower();
155 int ib = 0;
156 foreach (Level l in Levels)
157 {
158 met +=
159 "<Image ID=\"Image:" + ib + "\">" +
160 "<Pixels BigEndian=\"" + endian + "\" DimensionOrder= \"XYCZT\" ID= \"Pixels:0\" Interleaved=\"true\" " +
161 "PhysicalSizeX=\"" + PhysicalX + "\" PhysicalSizeXUnit=\"µm\" PhysicalSizeY=\"" + PhysicalY + "\" PhysicalSizeYUnit=\"µm\" SignificantBits=\"" + Image.BitsPerPixel + "\" " +
162 "SizeC = \"" + c + "\" SizeT = \"" + 1 + "\" SizeX =\"" + Image.Width +
163 "\" SizeY= \"" + Image.Height + "\" SizeZ=\"" + 1;
164 if (Image.BitsPerPixel > 8) met += "\" Type= \"uint16\">";
165 else met += "\" Type= \"uint8\">";
166 int i = 0;
167 foreach (Channel ch in l.Channels)
168 {
169 met += "<Channel ID=\"Channel:" + ib + ":" + i + "\" SamplesPerPixel=\"1\"></Channel>";
170 i++;
171 }
172 met += "</Pixels></Image>";
173 ib++;
174 }
175 met += "</OME>";
176 int li = 0;
177 foreach (Level l in Levels)
178 {
179 string fs = file.Replace(".ome.tif", "");
180 NetVips.Image im = NetVips.Image.NewFromFile(fs + "-" + li + "ome.tif");
181 using var mutated = im.Mutate(mutable =>
182 {
183 // Set the ImageDescription tag
184 mutable.Set(GValue.GStrType, "image-description", met);
185 mutable.Set(GValue.GIntType, "page-height", l.Height * l.PhysicalY);
186 });
187 if (l.Image.BitsPerPixel > 8)
188 mutated.Tiffsave(file, Compression, 1, Enums.ForeignTiffPredictor.None, true, (int)l.WidthPx, (int)l.HeightPx, true, false, 16,
189 Enums.ForeignTiffResunit.Cm, 1000 * l.PhysicalX, 1000 * l.PhysicalY, true, null, Enums.RegionShrink.Nearest,
190 CompressionLevel, true, Enums.ForeignDzDepth.One, true, false, null, null, (int)l.HeightPx);
191 else
192 mutated.Tiffsave(file, Compression, 1, Enums.ForeignTiffPredictor.None, true, (int)l.WidthPx, (int)l.HeightPx, true, false, 8,
193 Enums.ForeignTiffResunit.Cm, 1000 * l.PhysicalX, 1000 * l.PhysicalY, true, null, Enums.RegionShrink.Nearest,
194 CompressionLevel, true, Enums.ForeignDzDepth.One, true, false, null, null, (int)l.HeightPx);
195 li++;
196 }
197 }
198 public void ImageLevel(int level)
199 {
200 Level l = Levels[level];
201 if (l.Image == null)
202 Init(l.Width, l.Height, l.PixelFormat, l.Index);
203 Microscope.SetPosition(new Point3D(l.Location.X, l.Location.Y, l.Focus));
206 int w = (int)Math.Ceiling(l.Width / r.W);
207 int h = (int)Math.Ceiling(l.Height / r.H);
208 count = w * h;
209 bool leftright = false;
210 for (int y = 0; y < h; y++)
211 {
212 for (int x = 0; x < w; x++)
213 {
214 Point3D pd = Microscope.GetPosition();
215 l.ImageTile(new PointD(pd.X, pd.Y),(w * h) - ((y * w) + x));
216 SlideImager.progress = (int)((double)((y * w) + x) / (double)(w * h));
217 if (leftright)
219 else
221 }
222 Point3D p = Microscope.GetPosition();
223 l.ImageTile(new PointD(p.X, p.Y), (w * h) - ((y * w) + w));
224 leftright = !leftright;
226 }
227 }
228 private void ImageTile(PointD loc, int tiles)
229 {
230 Stopwatch.Restart();
231 A:
232 BioImage b = Microscope.TakeImage(false, false, false);
233 if (b == null)
234 goto A;
235 PhysicalX = b.PhysicalSizeX;
236 PhysicalY = b.PhysicalSizeY;
237 Channels = b.Channels;
238 PointD pd = ToImageSpace(loc, new PointD(Location.X, Location.Y), b.PhysicalSizeX, b.PhysicalSizeY);
239 int bands = BioImage.GetBands(PixelFormat);
240 NetVips.Image im;
241 if (b.bitsPerPixel > 8)
242 im = NetVips.Image.NewFromMemory(b.Buffers[0].Data, (ulong)b.Buffers[0].Length, b.Buffers[0].Width, b.Buffers[0].Height, bands, Enums.BandFormat.Ushort);
243 else
244 im = NetVips.Image.NewFromMemory(b.Buffers[0].Data, (ulong)b.Buffers[0].Length, b.Buffers[0].Width, b.Buffers[0].Height, bands, Enums.BandFormat.Uchar);
245 Parent.VipsImage = Parent.VipsImage.Insert(im, (int)pd.X, (int)pd.Y);
246 im.Dispose();
247 b.Dispose();
248 Stopwatch.Stop();
249 status = "Time Left:" + (Stopwatch.Elapsed * tiles).ToString();
250 }
251 }
252 private Level SlideLevel { get; set; } = null;
253 private List<BaseLevel> Levels { get; set; } = new List<BaseLevel>();
254 public SlideImager()
255 {
256 InitializeComponent();
258 {
259 objBox.Items.Add(o);
260 }
261 foreach (Enums.ForeignTiffCompression o in (Enums.ForeignTiffCompression[])Enum.GetValues(typeof(Enums.ForeignTiffCompression)))
262 {
263 compBox.Items.Add(o);
264 }
265 }
266
267
268 private void setToStageBut_Click(object sender, EventArgs e)
269 {
270 Point3D p = Microscope.GetPosition();
271 xBox.Value = (decimal)p.X;
272 yBox.Value = (decimal)p.Y;
273 }
274
275 private void setSizeBut_Click(object sender, EventArgs e)
276 {
277 Point3D p = Microscope.GetPosition();
278 wBox.Value = (decimal)(p.X - (double)xBox.Value);
279 hBox.Value = (decimal)(p.Y - (double)yBox.Value);
280 }
281
282 private void startBut_Click(object sender, EventArgs e)
283 {
284 if (saveFileDialog.ShowDialog() != DialogResult.OK)
285 return;
286 Microscope.Objectives.SetPosition(Levels[0].Objective);
287 BioImage b = Microscope.TakeImage(false, false, false);
288 SlideLevel = new Level((double)wBox.Value, (double)hBox.Value, b.Buffers[0].PixelFormat, Levels.Count, (Enums.ForeignTiffCompression)compBox.SelectedItem, b.PhysicalSizeX, b.PhysicalSizeY);
289 for (int i = 0; i < Levels.Count; i++)
290 {
291 SlideLevel.Levels[i].Location = b.Volume.Location;
292 SlideLevel.Levels[i].Focus = Levels[i].Focus;
293 SlideLevel.Levels[i].Objective = Levels[i].Objective;
294 }
295 SlideLevel.PixelFormat = b.Buffers[0].PixelFormat;
296 SlideLevel.PhysicalX = b.PhysicalSizeX;
297 SlideLevel.PhysicalY = b.PhysicalSizeY;
298 timer.Start();
299 RunImaging(saveFileDialog.FileName, SlideLevel, Levels);
300 }
301 static Level level = null;
302 static string ffile = null;
303 static List<BaseLevel> levels;
304 static int prog;
305 static string status = "";
306 static bool imaging = false;
307 static int count = 0;
308 private static int progress { get { return prog; } set { prog = value; } }
309 private static void Image()
310 {
311 for (int i = 0; i < levels.Count; i++)
312 {
313 string f = ffile.Replace(".ome.tif", "");
314 A:
315 try
316 {
317 level.ImageLevel(i);
318 level.Levels[i].SaveLevel(f + "-" + i + ".ome.tif");
319 }
320 catch (Exception e)
321 {
322 Console.WriteLine(e.ToString());
323 goto A;
324 }
325 }
326 imaging = false;
327 level.SaveLevels(ffile);
328 }
329 private static void RunImaging(string file, Level lev, List<BaseLevel> lvs)
330 {
331 imaging = true;
332 level = lev;
333 levels = lvs;
334 ffile = file;
335 Thread th = new Thread(Image);
336 th.Start();
337 }
338
339 private void addBut_Click(object sender, EventArgs e)
340 {
341 BaseLevel bl = new BaseLevel((double)focBox.Value, objBox.SelectedIndex);
342 Levels.Add(bl);
343 listBox.Items.Add(bl);
344 }
345
346 private void SlideImager_FormClosing(object sender, FormClosingEventArgs e)
347 {
348 e.Cancel = true;
349 this.Hide();
350 }
351
352 private void focBut_Click(object sender, EventArgs e)
353 {
354 focBox.Value = (decimal)Microscope.GetFocus();
355 }
356
357 private void listBox_SelectedIndexChanged(object sender, EventArgs e)
358 {
359 if (listBox.SelectedItem == null)
360 return;
361 BaseLevel bl = (BaseLevel)listBox.SelectedItem;
362 focBox.Value = (decimal)bl.Focus;
363 objBox.SelectedIndex = bl.Objective;
364 }
365
366 private void objBox_SelectedIndexChanged(object sender, EventArgs e)
367 {
368 if (listBox.SelectedItems.Count > 0)
369 {
370 BaseLevel bl = (BaseLevel)listBox.SelectedItem;
371 bl.Objective = objBox.SelectedIndex;
372 }
373 }
374
375 private void focBox_ValueChanged(object sender, EventArgs e)
376 {
377 if (listBox.SelectedItems.Count > 0)
378 {
379 BaseLevel bl = (BaseLevel)listBox.SelectedItem;
380 bl.Focus = (double)focBox.Value;
381 }
382 }
383
384 private void remBut_Click(object sender, EventArgs e)
385 {
386 if (listBox.SelectedItems.Count > 0)
387 listBox.Items.RemoveAt(listBox.SelectedIndex);
388 }
389
390 private void timer_Tick(object sender, EventArgs e)
391 {
392 if (!imaging)
393 timer.Stop();
394 toolStripProgressBar.Value = progress * 100;
395 toolStripStatusLabel.Text = status;
396 }
397 }
398}
AForge.RectangleD RectangleD
System.Drawing.Image Image
Definition ImageView.cs:16
AForge.PointD PointD
AForge.PixelFormat PixelFormat
BioLib.BioImage BioImage
Definition TabsView.cs:15
static Objectives Objectives
static void SetPosition(Point3D p)
static RectangleD GetObjectiveViewRectangle()
static Point3D GetPosition()
static void MoveFieldDown()
Move the field down by one unit.
static BioImage TakeImage()
static void MoveFieldRight()
Move the field right by the width of the view.
static void MoveFieldLeft()
Move the field left by the width of the viewport.
List< Objective > List
void SetPosition(int index)
BaseLevel(double focus, int objective)
Level(double w, double h, PixelFormat pf)
Level(double w, double h, PixelFormat pf, int levels, Enums.ForeignTiffCompression comp, double physX, double physY)
void Init(double w, double h, PixelFormat pf, int index)
void SaveLevels(string file)
List< BioImage > BioImages
void SaveLevel(string file)
static PointD ToImageSpace(PointD p, PointD stage, double physX, double physY)