BioCore  5.0.0
A Windows .NET microscopy library and application for viewing, editing, and annotating images.
Loading...
Searching...
No Matches
ChannelsTool.cs
Go to the documentation of this file.
1using AForge;
2using System.ComponentModel;
3namespace BioCore
4{
5 public partial class ChannelsTool : Form
6 {
7 private HistogramControl hist = null;
8 private bool initializing;
9 private int histogramRequestVersion;
10 private BioImage histogramLoadingImage;
11 private Task histogramLoadingTask;
12 private BioImage histogramImage;
13 private ZCT histogramCoordinate;
14 private ZCT histogramLoadingCoordinate;
15 /* A property that returns a list of channels. */
16 public List<Channel> Channels
17 {
18 get
19 {
20 return App.Channels;
21 }
22 }
23 /* A property that returns the selected channel from the channelsBox. */
24 public Channel SelectedChannel
25 {
26 get
27 {
28 if (channelsBox.SelectedIndex != -1)
29 return Channels[channelsBox.SelectedIndex];
30 else
31 return Channels[0];
32 }
33 }
34 /* A property that is used to get and set the value of the sampleBox.Value. */
35 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
36 public int SelectedSample
37 {
38 get
39 {
40 return (int)sampleBox.Value;
41 }
42 set
43 {
44 sampleBox.Value = (decimal)value;
45 }
46 }
48 public void UpdateItems()
49 {
50 int selectedIndex = channelsBox.SelectedIndex;
51 initializing = true;
52 channelsBox.Items.Clear();
53 foreach (Channel item in Channels)
54 {
55 channelsBox.Items.Add(item);
56 }
57 channelsBox.SelectedIndex = Channels.Count == 0
58 ? -1
59 : Math.Clamp(selectedIndex, 0, Channels.Count - 1);
60 initializing = false;
61 }
62 /* Creating a new instance of the ChannelsTool class. */
63 public ChannelsTool(List<Channel> Channels)
64 {
65 initializing = true;
66 InitializeComponent();
67 foreach (Channel item in Channels)
68 {
69 channelsBox.Items.Add(item);
70 }
71 MouseWheel += new System.Windows.Forms.MouseEventHandler(ChannelsTool_MouseWheel);
72
73 if (Channels.Count == 0)
74 {
75 channelsBox.Enabled = false;
76 sampleBox.Enabled = false;
77 statsPanel.Controls.Add(new Label
78 {
79 Dock = DockStyle.Fill,
80 Text = "No channel metadata is available for this image.",
81 TextAlign = ContentAlignment.MiddleCenter
82 });
83 initializing = false;
84 return;
85 }
86
87 channelsBox.SelectedIndex = 0;
88 Channel channel = Channels[0];
89 int sample = channel.range?.Length > 0 ? 0 : -1;
90 int defaultMax = channel.BitsPerPixel <= 8 ? byte.MaxValue : ushort.MaxValue;
91 int minimum = sample >= 0 ? channel.range[sample].Min : 0;
92 int maximum = sample >= 0 ? channel.range[sample].Max : defaultMax;
93 if (channel.stats?.Length > 0)
94 {
95 minimum = (int)channel.stats[0].StackMin;
96 maximum = (int)channel.stats[0].StackMax;
97 }
98 minBox.Value = Math.Clamp(minimum, (int)minBox.Minimum, (int)minBox.Maximum);
99 maxBox.Value = Math.Clamp(maximum, (int)maxBox.Minimum, (int)maxBox.Maximum);
100 hist = new HistogramControl(channel);
101 hist.GraphMax = Math.Max(1, (int)maxBox.Value);
102 maxGraphBox.Value = Math.Clamp(maxBox.Value, maxGraphBox.Minimum, maxGraphBox.Maximum);
103 statsPanel.Controls.Add(hist);
104 initializing = false;
105 Shown += async (_, _) => await EnsureHistogramAsync();
106 }
107
115 private void minBox_ValueChanged(object sender, EventArgs e)
116 {
117 if (initializing || channelsBox.SelectedIndex == -1)
118 return;
119 if (hist != null)
120 {
121 hist.UpdateChannel(Channels[channelsBox.SelectedIndex]);
122 hist.Invalidate();
123 hist.Min = (int)minBox.Value;
124 }
125 App.Channels[channelsBox.SelectedIndex].range[(int)sampleBox.Value].Max = (int)maxBox.Value;
126 App.viewer.UpdateImage();
127 App.viewer.UpdateView();
128 }
136 private void maxBox_ValueChanged(object sender, EventArgs e)
137 {
138 if (initializing || channelsBox.SelectedIndex == -1)
139 return;
140 if (hist != null)
141 {
142 hist.UpdateChannel(Channels[channelsBox.SelectedIndex]);
143 hist.Invalidate();
144 hist.Max = (int)maxBox.Value;
145 }
146 App.Channels[channelsBox.SelectedIndex].range[(int)sampleBox.Value].Min = (int)minBox.Value;
147 App.viewer.UpdateImage();
148 App.viewer.UpdateView();
149 }
157 private void channelsBox_SelectedIndexChanged(object sender, EventArgs e)
158 {
159 if (initializing || channelsBox.SelectedIndex == -1)
160 return;
161 Channel channel = Channels[channelsBox.SelectedIndex];
162 if (channel.range == null || channel.range.Length == 0)
163 return;
164 sampleBox.Value = 0;
165 sampleBox.Maximum = channel.range.Length - 1;
166 if (minBox.Maximum < Channels[channelsBox.SelectedIndex].range[(int)sampleBox.Value].Min || maxBox.Maximum < Channels[channelsBox.SelectedIndex].range[(int)sampleBox.Value].Max)
167 {
168 minBox.Value = 0;
169 maxBox.Value = ushort.MaxValue;
170 }
171 else
172 {
173 minBox.Value = Channels[channelsBox.SelectedIndex].range[(int)sampleBox.Value].Min;
174 maxBox.Value = Channels[channelsBox.SelectedIndex].range[(int)sampleBox.Value].Max;
175 }
176 if (hist != null)
177 {
178 //hist.Statistics = Channels[channelsBox.SelectedIndex].statistics;
179 hist.UpdateChannel(SelectedChannel);
180 hist.Invalidate();
181 }
182 fluorBox.Text = SelectedChannel.Fluor;
183 emisBox.Value = (decimal)SelectedChannel.Emission;
184 excBox.Value = (decimal)SelectedChannel.Excitation;
185 App.viewer.UpdateView();
186 }
187
194 private void maxUintBox_SelectedIndexChanged(object sender, EventArgs e)
195 {
196 int i = int.Parse((string)maxUintBox.SelectedItem, System.Globalization.CultureInfo.InvariantCulture);
197 if (i <= maxBox.Maximum)
198 maxBox.Value = i;
199
200 }
201
206 private void ChannelsTool_FormClosing(object sender, FormClosingEventArgs e)
207 {
208 e.Cancel = true;
209 this.Hide();
210 }
211
216 private void setMaxAllBut_Click(object sender, EventArgs e)
217 {
218 foreach (Channel c in Channels)
219 {
220 for (int i = 0; i < c.range.Length; i++)
221 {
222 c.range[i].Max = (int)maxBox.Value;
223 }
224 }
225 App.viewer.UpdateView();
226 }
227
232 private void setMinAllBut_Click(object sender, EventArgs e)
233 {
234 foreach (Channel c in Channels)
235 {
236 for (int i = 0; i < c.range.Length; i++)
237 {
238 c.range[i].Min = (int)minBox.Value;
239 }
240 }
241 App.viewer.UpdateView();
242 }
243
249 private void ChannelsTool_Activated(object sender, EventArgs e)
250 {
251 UpdateItems();
252 if (Channels.Count == 0 || channelsBox.SelectedIndex < 0 || hist == null)
253 return;
254 Channel channel = SelectedChannel;
255 if (channel.range == null || channel.range.Length == 0)
256 return;
257 initializing = true;
258 sampleBox.Maximum = channel.range.Length - 1;
259 sampleBox.Value = Math.Min(sampleBox.Value, sampleBox.Maximum);
260 minBox.Value = Math.Clamp(channel.range[(int)sampleBox.Value].Min,
261 (int)minBox.Minimum, (int)minBox.Maximum);
262 maxBox.Value = Math.Clamp(channel.range[(int)sampleBox.Value].Max,
263 (int)maxBox.Minimum, (int)maxBox.Maximum);
264 initializing = false;
265 hist.UpdateChannel(channel);
266 hist.UpdateView();
267 _ = EnsureHistogramAsync();
268
269 }
270
271 private async Task EnsureHistogramAsync()
272 {
273 BioImage image = ImageView.SelectedImage;
274 if (image == null || hist == null)
275 return;
276
277 ZCT coordinate = image.Coordinate;
278 int requestVersion = ++histogramRequestVersion;
279 if (ReferenceEquals(histogramImage, image) && SameCoordinate(histogramCoordinate, coordinate) &&
280 ZarrChannelView.HasHistogramStatistics(image))
281 {
282 hist.StatusMessage = "";
283 ApplyFrameRange();
284 hist.Invalidate();
285 return;
286 }
287
288 hist.StatusMessage = "Loading histogram…";
289 hist.Invalidate();
290 try
291 {
292 if (!ReferenceEquals(histogramLoadingImage, image) ||
293 !SameCoordinate(histogramLoadingCoordinate, coordinate) ||
294 histogramLoadingTask == null || histogramLoadingTask.IsCompleted)
295 {
296 histogramLoadingImage = image;
297 histogramLoadingCoordinate = coordinate;
298 histogramLoadingTask = ZarrChannelView.EnsureHistogramStatisticsAsync(
299 image, coordinate);
300 }
301 await histogramLoadingTask;
302 if (requestVersion != histogramRequestVersion || image != ImageView.SelectedImage)
303 return;
304 histogramImage = image;
305 histogramCoordinate = coordinate;
306 hist.StatusMessage = ZarrChannelView.HasHistogramStatistics(image)
307 ? ""
308 : "Histogram data is unavailable for this image.";
309 hist.UpdateChannel(SelectedChannel);
310 ApplyFrameRange();
311 hist.Invalidate();
312 }
313 catch (Exception ex)
314 {
315 if (requestVersion != histogramRequestVersion)
316 return;
317 hist.StatusMessage = $"Could not load histogram: {ex.Message}";
318 hist.Invalidate();
319 }
320 }
321
322 public void RefreshHistogram()
323 {
324 if (Visible)
325 _ = EnsureHistogramAsync();
326 }
327
328 private void ApplyFrameRange()
329 {
330 if (channelsBox.SelectedIndex < 0 || SelectedChannel.stats == null ||
331 SelectedChannel.stats.Length == 0)
332 return;
333
334 int sample = Math.Clamp((int)sampleBox.Value, 0, SelectedChannel.stats.Length - 1);
335 Statistics statistics = SelectedChannel.stats[sample];
336 int minimum = Math.Clamp((int)statistics.StackMin, (int)minBox.Minimum, (int)minBox.Maximum);
337 int maximum = Math.Clamp((int)statistics.StackMax, minimum, (int)maxBox.Maximum);
338 int graphMaximum = Math.Max(1, maximum);
339 int graphMinimum = Math.Min(minimum, graphMaximum);
340 int histogramBin = Math.Max(1, (graphMaximum - graphMinimum + 255) / 256);
341
342 initializing = true;
343 minBox.Value = minimum;
344 maxBox.Value = maximum;
345 minGraphBox.Value = Math.Clamp(graphMinimum,
346 (int)minGraphBox.Minimum, (int)minGraphBox.Maximum);
347 maxGraphBox.Value = Math.Clamp(graphMaximum,
348 (int)maxGraphBox.Minimum, (int)maxGraphBox.Maximum);
349 binBox.Value = Math.Clamp(histogramBin, (int)binBox.Minimum, (int)binBox.Maximum);
350 initializing = false;
351
352 hist.GraphMin = graphMinimum;
353 hist.GraphMax = graphMaximum;
354 hist.Bin = histogramBin;
355 }
356
357 private static bool SameCoordinate(ZCT left, ZCT right) =>
358 left.Z == right.Z && left.C == right.C && left.T == right.T;
359
364 private void ChannelsTool_ResizeEnd(object sender, EventArgs e)
365 {
366 hist?.UpdateView();
367 }
368
374 private void maxUintBox2_SelectedIndexChanged(object sender, EventArgs e)
375 {
376 int i = int.Parse((string)maxUintBox2.SelectedItem, System.Globalization.CultureInfo.InvariantCulture);
377 if (i <= maxGraphBox.Maximum)
378 maxGraphBox.Value = i;
379 if (i == 255)
380 {
381 maxGraphBox.Value = 255;
382 binBox.Value = 1;
383 }
384 }
385
391 private void minGraphBox_ValueChanged(object sender, EventArgs e)
392 {
393 if (hist != null)
394 {
395 hist.GraphMin = (int)minGraphBox.Value;
396 hist.Invalidate();
397 }
398 }
399
405 private void maxGraphBox_ValueChanged(object sender, EventArgs e)
406 {
407 if (hist != null)
408 {
409 hist.GraphMax = (int)maxGraphBox.Value;
410 hist.Invalidate();
411 }
412 }
418 private void binBox_ValueChanged(object sender, EventArgs e)
419 {
420 if (hist != null)
421 {
422 hist.Bin = (int)binBox.Value;
423 hist.Invalidate();
424 }
425 }
426
431 private void ChannelsTool_MouseDown(object sender, MouseEventArgs e)
432 {
433
434 }
435 private bool pressedX1 = false;
436 private bool pressedX2 = false;
445 private void ChannelsTool_MouseMove(object sender, MouseEventArgs e)
446 {
447 if (e.Button == MouseButtons.XButton1)
448 {
449 if (channelsBox.SelectedIndex < channelsBox.Items.Count - 1)
450 {
451 if (pressedX1 == false)
452 {
453 channelsBox.SelectedIndex++;
454 pressedX1 = true;
455 return;
456 }
457 }
458 }
459 pressedX1 = false;
460 if (e.Button == MouseButtons.XButton2)
461 {
462 if (channelsBox.SelectedIndex > 0)
463 {
464 if (pressedX2 == false)
465 {
466 channelsBox.SelectedIndex--;
467 pressedX2 = true;
468 return;
469 }
470 }
471 }
472 pressedX2 = false;
473 }
474
483 private void ChannelsTool_MouseWheel(object sender, MouseEventArgs e)
484 {
485 if (e.Delta == 0)
486 return;
487 int i = 100;
488 if (maxGraphBox.Value < 255)
489 i = 10;
490 if (e.Delta > 0)
491 {
492 if (maxGraphBox.Value + i < maxGraphBox.Maximum)
493 {
494 maxGraphBox.Value += i;
495 hist.Invalidate();
496 return;
497 }
498 }
499 else
500 if (maxGraphBox.Value - i > maxGraphBox.Minimum)
501 {
502 maxGraphBox.Value -= i;
503 hist.Invalidate();
504 return;
505 }
506 }
507
512 private void stackHistoBox_CheckedChanged(object sender, EventArgs e)
513 {
514 hist.StackHistogram = stackHistoBox.Checked;
515 hist.Invalidate();
516 }
517
523 private void setMinToolStripMenuItem_Click(object sender, EventArgs e)
524 {
525 minBox.Value = (int)hist.MouseValX;
526 }
527
532 private void setMaxToolStripMenuItem_Click(object sender, EventArgs e)
533 {
534 maxBox.Value = (int)hist.MouseValX;
535 }
536
542 private void applyBut_Click(object sender, EventArgs e)
543 {
544 ImageView.SelectedImage.Bake(ImageView.SelectedImage.RChannel.RangeR, ImageView.SelectedImage.GChannel.RangeG, ImageView.SelectedImage.BChannel.RangeB);
545 }
546
552 private void minToolStripMenuItem_Click(object sender, EventArgs e)
553 {
554 minBox.Value = (decimal)SelectedChannel.stats[channelsBox.SelectedIndex].StackMin;
555 }
556
562 private void maxToolStripMenuItem_Click(object sender, EventArgs e)
563 {
564 minBox.Value = (decimal)SelectedChannel.stats[channelsBox.SelectedIndex].StackMax;
565 }
566
572 private void medianToolStripMenuItem_Click(object sender, EventArgs e)
573 {
574 minBox.Value = (decimal)SelectedChannel.stats[channelsBox.SelectedIndex].StackMedian;
575 }
576
582 private void meanToolStripMenuItem_Click(object sender, EventArgs e)
583 {
584 minBox.Value = (decimal)SelectedChannel.stats[channelsBox.SelectedIndex].StackMean;
585 }
586
592 private void toolStripMenuItem1_Click(object sender, EventArgs e)
593 {
594 maxBox.Value = (decimal)SelectedChannel.stats[channelsBox.SelectedIndex].StackMin;
595 }
596
602 private void toolStripMenuItem2_Click(object sender, EventArgs e)
603 {
604 maxBox.Value = (decimal)SelectedChannel.stats[channelsBox.SelectedIndex].StackMax;
605 }
611 private void toolStripMenuItem3_Click(object sender, EventArgs e)
612 {
613 maxBox.Value = (decimal)SelectedChannel.stats[channelsBox.SelectedIndex].StackMedian;
614 }
620 private void toolStripMenuItem4_Click(object sender, EventArgs e)
621 {
622 maxBox.Value = (decimal)SelectedChannel.stats[channelsBox.SelectedIndex].StackMean;
623 }
624
629 private void updateBut_Click(object sender, EventArgs e)
630 {
631 if (ImageView.SelectedImage.bitsPerPixel > 8)
632 {
633 ImageView.SelectedImage.StackThreshold(true);
634 if (ImageView.SelectedImage.RGBChannelCount == 1)
635 {
636 maxBox.Value = (decimal)ImageView.SelectedImage.Channels[channelsBox.SelectedIndex].stats[0].StackMax;
637 minBox.Value = (decimal)ImageView.SelectedImage.Channels[channelsBox.SelectedIndex].stats[0].StackMin;
638 }
639 else
640 {
641 maxBox.Value = (decimal)ImageView.SelectedImage.Channels[channelsBox.SelectedIndex].stats[channelsBox.SelectedIndex].StackMax;
642 minBox.Value = (decimal)ImageView.SelectedImage.Channels[channelsBox.SelectedIndex].stats[channelsBox.SelectedIndex].StackMin;
643 }
644 }
645 else
646 {
647 ImageView.SelectedImage.StackThreshold(false);
648 }
649 App.viewer.UpdateImage();
650 }
651
657 private void sampleBox_ValueChanged(object sender, EventArgs e)
658 {
659 if (initializing || Channels.Count == 0)
660 return;
661 if (channelsBox.SelectedIndex == -1)
662 channelsBox.SelectedIndex = 0;
663 minBox.Value = Channels[channelsBox.SelectedIndex].range[(int)sampleBox.Value].Min;
664 maxBox.Value = Channels[channelsBox.SelectedIndex].range[(int)sampleBox.Value].Max;
665 if (hist != null)
666 {
667 //hist.Statistics = Channels[channelsBox.SelectedIndex].statistics;
668 hist.UpdateChannel(SelectedChannel);
669 hist.Invalidate();
670 }
671 App.viewer.UpdateView();
672 }
673
679 private void excBox_ValueChanged(object sender, EventArgs e)
680 {
681 SelectedChannel.Excitation = (int)excBox.Value;
682 }
683
689 private void emisBox_ValueChanged(object sender, EventArgs e)
690 {
691 SelectedChannel.Emission = (int)emisBox.Value;
692 }
693
699 private void fluorBox_TextChanged(object sender, EventArgs e)
700 {
701 SelectedChannel.Fluor = fluorBox.Text;
702 }
703 }
704}
static List< Channel > Channels
Definition App.cs:38
ChannelsTool(List< Channel > Channels)
List< Channel > Channels
void UpdateItems()
It clears the listbox and then adds all the items in the Channels list to the listbox.