diff --git a/BioGTK.csproj b/BioGTK.csproj index 1d6082e..3ff41ca 100644 --- a/BioGTK.csproj +++ b/BioGTK.csproj @@ -22,7 +22,7 @@ AnyCPU;x64;ARM64 True x64 - Updated Bioformats to 6.13.0. + GUI bug fixes. ErikRepo @@ -53,6 +53,7 @@ + @@ -70,6 +71,8 @@ + + @@ -224,6 +227,7 @@ + @@ -253,6 +257,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -272,10 +277,4 @@ - - - PreserveNewest - - - diff --git a/Glade/Plot.glade b/Glade/Plot.glade new file mode 100644 index 0000000..99e27bc --- /dev/null +++ b/Glade/Plot.glade @@ -0,0 +1,14 @@ + + + + + + False + + + True + False + + + + diff --git a/Glade/TabsView.glade b/Glade/TabsView.glade index 08a92b1..e50096d 100644 --- a/Glade/TabsView.glade +++ b/Glade/TabsView.glade @@ -357,6 +357,14 @@ False + + + Find Focus + True + False + False + + diff --git a/Glade/TabsView.glade~ b/Glade/TabsView.glade~ index 0f44da6..4348144 100644 --- a/Glade/TabsView.glade~ +++ b/Glade/TabsView.glade~ @@ -357,6 +357,14 @@ False + + + Find Focus + True + False + False + + @@ -455,7 +463,7 @@ - + True False Script Recorder diff --git a/Source/Bio.cs b/Source/Bio.cs index bb50c85..fd12714 100644 --- a/Source/Bio.cs +++ b/Source/Bio.cs @@ -6937,6 +6937,75 @@ public static void AutoThresholdThread(BioImage b) Thread th = new Thread(AutoThreshold); th.Start(); } + /// The function finds the focus of a given BioImage at a specific channel and time by + /// calculating the focus quality of each Z-plane and returning the coordinate with the highest + /// focus quality. + /// + /// @param BioImage A BioImage object that contains the image data. + /// @param Channel The channel of the BioImage to analyze. A BioImage can have multiple + /// channels, each representing a different fluorescent label or imaging modality. + /// @param Time The time point at which the focus is being calculated. + /// + /// @return an integer value which represents the coordinate of the image with the highest focus + /// quality in a given channel and time. + public static int FindFocus(BioImage im, int Channel, int Time) + { + + long mf = 0; + int fr = 0; + List dt = new List(); + ZCT c = new ZCT(0, 0, 0); + for (int i = 0; i < im.SizeZ; i++) + { + long f = CalculateFocusQuality(im.Buffers[im.Coords[i, Channel, Time]]); + dt.Add(f); + if (f > mf) + { + mf = f; + fr = im.Coords[i, Channel, Time]; + } + } + Plot pl = Plot.Create(dt.ToArray(), "Focus"); + pl.Show(); + return fr; + } + /// The function calculates the focus quality of a given bitmap image. + /// + /// @param Bitmap A class representing a bitmap image, which contains information about the + /// image's size, pixel data, and color channels. + /// + /// @return The method is returning a long value which represents the calculated focus quality + /// of the input Bitmap image. + static long CalculateFocusQuality(Bitmap b) + { + if (b.RGBChannelsCount == 1) + { + long sum = 0; + long sumOfSquaresR = 0; + for (int y = 0; y < b.SizeY; y++) + for (int x = 0; x < b.SizeX; x++) + { + ColorS pixel = b.GetPixel(x, y); + sum += pixel.R; + sumOfSquaresR += pixel.R * pixel.R; + } + return sumOfSquaresR * b.SizeX * b.SizeY - sum * sum; + } + else + { + long sum = 0; + long sumOfSquares = 0; + for (int y = 0; y < b.SizeY; y++) + for (int x = 0; x < b.SizeX; x++) + { + ColorS pixel = b.GetPixel(x, y); + int p = (pixel.R + pixel.G + pixel.B) / 3; + sum += p; + sumOfSquares += p * p; + } + return sumOfSquares * b.SizeX * b.SizeY - sum * sum; + } + } /// It disposes of all the buffers and channels in the image, removes the image from the Images /// list, and then forces the garbage collector to run public void Dispose() diff --git a/Source/Plot.cs b/Source/Plot.cs new file mode 100644 index 0000000..57ad2b9 --- /dev/null +++ b/Source/Plot.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using AForge; +using Gdk; +using GLib; +using Gtk; +using org.checkerframework.checker.units.qual; +using ScottPlot; +using System.Threading; + +namespace BioGTK +{ + public class Plot : Gtk.Window + { + public ScottPlot.Plot plot; + string file; + string name; + Bitmap bitmap; + List data = new List(); + static Dictionary plots = new Dictionary(); + public static Dictionary Plots + { + get { return plots; } + } + public List Data + { + get { return data; } + set { data = value; UpdateImage(); } + } + public Bitmap Image + { + get { return bitmap; } + set { bitmap = value; } + } + public void UpdateImage() + { + plot = new ScottPlot.Plot(AllocatedWidth, AllocatedHeight); + foreach (double[] val in data) + { + plot.AddBar(val); + } + file = plot.SaveFig(name + ".png"); + this.Title = name; + pixbuf = new Pixbuf(file); + } + + #region Properties + Pixbuf pixbuf; + private Builder _builder; +#pragma warning disable 649 + [Builder.Object] + private Gtk.DrawingArea image; + [Builder.Object] + private Gtk.Label label; +#pragma warning restore 649 + #endregion + + #region Constructors / Destructors + + /// It creates a new instance of the Plot class. + /// + /// @return A new instance of the Plot class. + public static Plot Create(double[] vals, string name) + { + Builder builder = new Builder(null, "BioGTK.Glade.Plot.glade", null); + return new Plot(builder, builder.GetObject("plot").Handle, vals, name); + } + + + /* It's the constructor of the class. */ + protected Plot(Builder builder, IntPtr handle, double[] vals, string name) : base(handle) + { + _builder = builder; + builder.Autoconnect(this); + this.Title = name; + image.Drawn += Image_Drawn; + image.SizeAllocated += Image_SizeAllocated; + this.DeleteEvent += About_DeleteEvent; + data.Add(vals); + this.name = name; + selected = this; + if(plots.ContainsKey(name)) + plots[name] = this; + else + plots.Add(name,this); + } + System.Threading.Thread th; + static Plot selected; + public static Plot SelectedPlot + { + get { return selected; } + } + static void ShowPlot() + { + selected.Show(); + selected.Present(); + } + + private void Image_SizeAllocated(object o, SizeAllocatedArgs args) + { + UpdateImage(); + } + + private void About_DeleteEvent(object o, DeleteEventArgs args) + { + args.RetVal = true; + plots.Remove(name); + Hide(); + } + + private void Image_Drawn(object o, DrawnArgs e) + { + Pixbuf pf = pixbuf.ScaleSimple(image.AllocatedWidth, image.AllocatedHeight, InterpType.Bilinear); + Gdk.CairoHelper.SetSourcePixbuf(e.Cr, pf, 0, 0); + e.Cr.Paint(); + e.Cr.Stroke(); + } + + #endregion + + } +} diff --git a/Source/Scripting.cs b/Source/Scripting.cs index f388e6c..b531e38 100644 --- a/Source/Scripting.cs +++ b/Source/Scripting.cs @@ -644,6 +644,7 @@ public void Stop() return; //We stop this script SelectedItem.Stop(); + RefreshItems(); } /// It runs the program. /// @@ -752,6 +753,7 @@ private void Save() scripts.Add(scriptLabel.Text,new Script(filechooser.Filename, view.Buffer.Text)); } RefreshItems(); + filechooser.Destroy(); } /// It stops the timer and resets the timer to 0 diff --git a/Source/TabsView.cs b/Source/TabsView.cs index b2647c9..acc750b 100644 --- a/Source/TabsView.cs +++ b/Source/TabsView.cs @@ -90,7 +90,8 @@ public static ImageView SelectedViewer private MenuItem rotateFlipMenu; [Builder.Object] private MenuItem stackToolMenu; - + [Builder.Object] + private MenuItem focusMenu; [Builder.Object] private MenuItem to8BitMenu; @@ -217,6 +218,7 @@ protected void SetupHandlers() switchRedBlueMenu.ButtonPressEvent += switchRedBlueMenuClick; stackToolMenu.ButtonPressEvent += stackToolMenuClick; + focusMenu.ButtonPressEvent += FocusMenu_ButtonPressEvent; to8BitMenu.ButtonPressEvent += to8BitMenuClick; to16BitMenu.ButtonPressEvent += to16BitMenuClick; @@ -241,11 +243,20 @@ protected void SetupHandlers() this.WindowStateEvent += TabsView_WindowStateEvent; } - /// When the user clicks on the Script Recorder menu item, the Script Recorder window is shown - /// - /// @param o The object that the event is being called on. - /// @param ButtonPressEventArgs - /// https://developer.gnome.org/gtk3/stable/GtkButton.html#GtkButton-clicked + private void FocusMenu_ButtonPressEvent(object o, ButtonPressEventArgs args) + { + if (ImageView.SelectedImage == null) return; + ZCT co = SelectedViewer.GetCoordinate(); + int f = BioImage.FindFocus(ImageView.SelectedImage, co.C, co.T); + ZCT z = ImageView.SelectedImage.Buffers[f].Coordinate; + SelectedViewer.SetCoordinate(z.Z, z.C, z.T); + } + + /// When the user clicks on the Script Recorder menu item, the Script Recorder window is shown + /// + /// @param o The object that the event is being called on. + /// @param ButtonPressEventArgs + /// https://developer.gnome.org/gtk3/stable/GtkButton.html#GtkButton-clicked private void ScriptRecorderMenu_ButtonPressEvent(object o, ButtonPressEventArgs args) { App.recorder.Show();