Skip to content

Commit

Permalink
2.6.0
Browse files Browse the repository at this point in the history
Whole slide overview for easier navigation.
  • Loading branch information
BiologyTools committed Mar 12, 2023
1 parent 5056ef9 commit 4b71f65
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 106 deletions.
12 changes: 7 additions & 5 deletions BioGTK.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@
<TargetFramework>net6.0</TargetFramework>
<OutputType>Library</OutputType>
<RuntimeIdentifiers>osx-x64;linux-x64;win7-x64;linux-arm64</RuntimeIdentifiers>
<AssemblyVersion>2.5.0</AssemblyVersion>
<FileVersion>2.5.0</FileVersion>
<AssemblyVersion>2.6.0</AssemblyVersion>
<FileVersion>2.6.0</FileVersion>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageId>BioGTK</PackageId>
<Title>BioGTK</Title>
<PackageProjectUrl>https://github.com/BiologyTools/BioGTK</PackageProjectUrl>
<PackageIcon>banner.jpg</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageVersion>2.5.0</PackageVersion>
<PackageVersion>2.6.0</PackageVersion>
<RepositoryUrl>https://github.com/BiologyTools/BioGTK</RepositoryUrl>
<PackageTags>Biology; GTK; ImageJ; Bio-Formats; Image-Stacks; Microscopy;</PackageTags>
<PackageLicenseExpression> GPL-3.0-only</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<Description>A .NET application &amp; library for editing &amp; annotating various microscopy image formats. Supports all bioformats supported images. Integrates with ImageJ, running ImageJ filters &amp; macro functions. Supports Windows, Linux and Mac.</Description>
<Version>2.5.0</Version>
<Version>2.6.0</Version>
<Platforms>AnyCPU;x64;ARM64</Platforms>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<PlatformTarget>x64</PlatformTarget>
Expand Down Expand Up @@ -79,7 +79,9 @@
</ItemGroup>

<ItemGroup>
<Content Include="bioformats_package.dll" />
<Content Include="bioformats_package.dll">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Content>
<Content Include="Info.plist" />
<Content Include="Resources\banner.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand Down
123 changes: 34 additions & 89 deletions Source/Bio.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5136,7 +5136,6 @@ public static BioImage OpenOME(string file, int serie, bool tab, bool addToImage
reader.setSeries(serie);
int RGBChannelCount = reader.getRGBChannelCount();
b.bitsPerPixel = reader.getBitsPerPixel();
//Sometimes getBitsPerPixel will return an incorrect value
if (b.bitsPerPixel > 16)
{
//pr.Close();
Expand Down Expand Up @@ -5729,44 +5728,6 @@ public static Bitmap GetTile(BioImage b, ZCT coord, int serie, int tilex, int ti
bool littleEndian = b.imRead.isLittleEndian();
int RGBChannelCount = b.imRead.getRGBChannelCount();
b.bitsPerPixel = b.imRead.getBitsPerPixel();
b.physicalSizeX = (96 / 2.54) / 1000;
b.physicalSizeY = (96 / 2.54) / 1000;
b.physicalSizeZ = 1;
try
{
bool hasPhysical = false;
if (b.meta.getPixelsPhysicalSizeX(b.series) != null)
{
b.physicalSizeX = b.meta.getPixelsPhysicalSizeX(b.series).value().doubleValue();
hasPhysical = true;
}
if (b.meta.getPixelsPhysicalSizeY(b.series) != null)
{
b.physicalSizeY = b.meta.getPixelsPhysicalSizeY(b.series).value().doubleValue();
}
if (b.meta.getPixelsPhysicalSizeZ(b.series) != null)
{
b.physicalSizeZ = b.meta.getPixelsPhysicalSizeZ(b.series).value().doubleValue();
}
else
{
b.physicalSizeZ = 1;
}

if (b.meta.getStageLabelX(b.series) != null)
b.stageSizeX = b.meta.getStageLabelX(b.series).value().doubleValue();
if (b.meta.getStageLabelY(b.series) != null)
b.stageSizeY = b.meta.getStageLabelY(b.series).value().doubleValue();
if (b.meta.getStageLabelZ(b.series) != null)
b.stageSizeZ = b.meta.getStageLabelZ(b.series).value().doubleValue();
else
b.stageSizeZ = 1;
}
catch (Exception e)
{
Console.WriteLine("No Stage Coordinates. PhysicalSize:(" + b.physicalSizeX + "," + b.physicalSizeY + "," + b.physicalSizeZ + ")");
}

PixelFormat PixelFormat = GetPixelFormat(RGBChannelCount, b.bitsPerPixel);
if (tilex < 0)
tilex = 0;
Expand All @@ -5786,84 +5747,68 @@ public static Bitmap GetTile(BioImage b, ZCT coord, int serie, int tilex, int ti
return null;
if (sy <= 0)
return null;
int strplane = 0;
int stride;
if (RGBChannelCount == 1)
{
if (b.bitsPerPixel > 8)
strplane = sx * 2;
stride = sx * 2;
else
strplane = sx;
stride = sx;
}
else
if (RGBChannelCount == 3)
{
if (b.bitsPerPixel > 8)
strplane = sx * 2;
stride = sx * 2 * 3;
else
strplane = sx;
stride = sx * 3;
}
else
{
strplane = sx * 4;
stride = sx * 4;
}

byte[] bytesr = b.imRead.openBytes(b.Coords[coord.Z, coord.C, coord.T], tilex, tiley, sx, sy);
bool interleaved = b.imRead.isInterleaved();
if (!interleaved)
{
byte[] rb = new byte[strplane * sy];
byte[] gb = new byte[strplane * sy];
byte[] bb = new byte[strplane * sy];
int ind = 0;
for (int y = 0; y < sy; y++)
{
for (int st = 0; st < strplane; st++)
{
rb[((strplane) * y) + st] = bytesr[((strplane) * y) + st];
ind++;
}
}
byte[] bytes = new byte[ind];
Array.Copy(bytesr, ind, bytes, 0, ind);
for (int y = 0; y < sy; y++)
int strplane;
if (b.bitsPerPixel > 8)
strplane = sx * 2;
else
strplane = sx;
int ind = strplane * sy;
byte[] bytes = new byte[stride * sy];
if (RGBChannelCount == 1)
{
int x = 0;
for (int st = 0; st < strplane; st++)
for (int y = 0; y < sy; y++)
{
int i = ((strplane) * y) + x;
gb[i] = bytes[((strplane) * y) + st];
x++;
for (int st = 0; st < strplane; st++)
{
bytes[((strplane) * y) + st] = bytesr[((strplane) * y) + st];
}
}
}
Array.Copy(bytesr, ind * 2, bytes, 0, ind);
for (int y = 0; y < sy; y++)
else
{
int x = 0;
for (int st = 0; st < strplane; st++)
int indg = strplane * sy;
int indb = ind * 2;
for (int y = 0; y < sy; y++)
{
int i = ((strplane) * y) + x;
bb[i] = bytes[((strplane) * y) + st];
x++;
int x = 0;
int str1 = stride * y;
int str2 = strplane * y;
for (int st = 0; st < strplane; st++)
{
bytes[str1 + x + 2] = bytesr[str2 + st];
bytes[str1 + x + 1] = bytesr[indg + str2 + st];
bytes[str1 + x] = bytesr[indb + str2 + st];
x += 3;
}
}
}
Bitmap[] bms = new Bitmap[3];
if (b.bitsPerPixel == 8)
{
bms[2] = new Bitmap(b.file, sx, sy, PixelFormat.Format8bppIndexed, rb, new ZCT(0, 0, 0), p, littleEndian);
bms[1] = new Bitmap(b.file, sx, sy, PixelFormat.Format8bppIndexed, gb, new ZCT(0, 0, 0), p, littleEndian);
bms[0] = new Bitmap(b.file, sx, sy, PixelFormat.Format8bppIndexed, bb, new ZCT(0, 0, 0), p, littleEndian);
return Bitmap.RGB8To24(bms);
}
else
{
bms[2] = new Bitmap(b.file, sx, sy, PixelFormat.Format16bppGrayScale, rb, new ZCT(0, 0, 0), p, littleEndian);
bms[1] = new Bitmap(b.file, sx, sy, PixelFormat.Format16bppGrayScale, gb, new ZCT(0, 0, 0), p, littleEndian);
bms[0] = new Bitmap(b.file, sx, sy, PixelFormat.Format16bppGrayScale, bb, new ZCT(0, 0, 0), p, littleEndian);
return Bitmap.RGB16To48(bms);
}
return new Bitmap(b.file, sx, sy, PixelFormat, bytes, coord, p, littleEndian);
}
Bitmap bm = new Bitmap(b.file, sx, sy, PixelFormat, bytesr, coord, p, littleEndian);
bm.Stats = Statistics.FromBytes(bm);
return bm;
}
/// This function sets the minimum and maximum values of the image to the minimum and maximum
Expand Down
86 changes: 74 additions & 12 deletions Source/ImageView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ protected ImageView(Builder builder, IntPtr handle, BioImage im) : base(handle)
viewStack.VisibleChild = viewStack.Children[1];
scrollH.HeightRequest = im.SizeY;
scrollV.WidthRequest = im.SizeX;
InitPreview();
}
SetupHandlers();
//pictureBox.WidthRequest = im.SizeX;
Expand Down Expand Up @@ -386,7 +387,49 @@ public void UpdateImage()
Pixbuf pixbuf = new Pixbuf(bm.RGBBytes, true, 8, bm.Width, bm.Height, bm.Stride);
Bitmaps.Add(pixbuf);
}

bool showOverview;
Rectangle overview;
Pixbuf overviewBitmap;
public bool ShowOverview
{
get { return showOverview; }
set
{
showOverview = value;
UpdateView();
}
}
private int GetPreviewResolution()
{
//We will find the first Resolution small enough in bytes to use as a preview image.
int i = 0;
PixelFormat format = SelectedImage.Resolutions[0].PixelFormat;
foreach (Resolution res in SelectedImage.Resolutions)
{
if (res.PixelFormat == format)
{
if (res.SizeInBytes < 1e+9 * 0.05f)
return i;
}//Also the macro && label resolutions are often in a different pixel format
else
return i - 1;
i++;
}
return 0;
}
public void InitPreview()
{
if (SelectedImage.Resolutions.Count == 1)
return;
overview = new Rectangle(0, 0, 200, 80);
int r = GetPreviewResolution();
BioImage b = BioImage.OpenOME(SelectedImage.file, r, false, false, true, 0, 0, SelectedImage.Resolutions[r].SizeX, SelectedImage.Resolutions[r].SizeY);
AForge.Imaging.Filters.ResizeBilinear re = new AForge.Imaging.Filters.ResizeBilinear(200, 80);
Bitmap bm = re.Apply((Bitmap)b.Buffers[0].ImageRGB);
overviewBitmap = new Pixbuf(bm.Bytes,true,8,bm.Width,bm.Height,bm.Stride);
b.Dispose();
showOverview = true;
}
#region Handlers

/// <summary> Sets up the handlers. </summary>
Expand Down Expand Up @@ -419,7 +462,6 @@ protected void SetupHandlers()
imageBox.ButtonPressEvent += ImageView_ButtonPressEvent;
imageBox.ButtonReleaseEvent += ImageView_ButtonReleaseEvent;
imageBox.ScrollEvent += ImageView_ScrollEvent;

imageBox.Drawn += PictureBox_Drawn;
imageBox.SizeAllocated += PictureBox_SizeAllocated;
imageBox.AddEvents((int)
Expand Down Expand Up @@ -897,19 +939,37 @@ private void PictureBox_Drawn(object o, DrawnArgs e)
if (Bitmaps[i] == null)
UpdateImages();
RectangleD r = ToViewSpace(im.Volume.Location.X, im.Volume.Location.Y, im.Volume.Width, im.Volume.Height);

e.Cr.LineWidth = 1;
if (SelectedImage.isPyramidal)
{
e.Cr.Restore(); //g.ResetTransform();
Gdk.CairoHelper.SetSourcePixbuf(e.Cr, Bitmaps[i], 0, 0);
e.Cr.Paint();
if(ShowOverview)
{
Gdk.CairoHelper.SetSourcePixbuf(e.Cr, overviewBitmap, 0, 0);
e.Cr.Paint();
e.Cr.SetSourceColor(FromColor(Color.Gray));
e.Cr.Rectangle(overview.X, overview.Y, overview.Width, overview.Height);
e.Cr.Stroke();
Resolution rs = SelectedImage.Resolutions[Resolution];
double dx = ((double)PyramidalOrigin.X / rs.SizeX) * overview.Width;
double dy = ((double)PyramidalOrigin.Y / rs.SizeY) * overview.Height;
double dw = Math.Ceiling((double)((double)imageBox.AllocatedWidth / rs.SizeX) * overview.Width);
double dh = Math.Ceiling((double)((double)imageBox.AllocatedHeight / rs.SizeY) * overview.Height);
e.Cr.SetSourceColor(FromColor(Color.Red));
e.Cr.Rectangle((int)dx, (int)dy, (int)dw, (int)dh);
e.Cr.Stroke();
}
}
else
{
Pixbuf pf = Bitmaps[i].ScaleSimple((int)r.W,(int)r.H, InterpType.Bilinear);
Gdk.CairoHelper.SetSourcePixbuf(e.Cr, pf, (int)r.X, (int)r.Y);
pf.Dispose();
e.Cr.Paint();
}
e.Cr.Paint();

foreach (ROI an in im.Annotations)
{
if (Mode == ViewMode.RGBImage)
Expand Down Expand Up @@ -1132,7 +1192,6 @@ private void PictureBox_Drawn(object o, DrawnArgs e)
}
}
rects.Clear();

}
if (Tools.currentTool.type == Tools.Tool.Type.select)
{
Expand Down Expand Up @@ -1521,16 +1580,14 @@ public int Resolution
{
if (SelectedImage.Resolutions.Count <= value || value < 0)
return;
double x = PyramidalOrigin.X * ((double)SelectedImage.Resolutions[resolution].SizeX / (double)SelectedImage.Resolutions[value].SizeX);
double y = PyramidalOrigin.Y * ((double)SelectedImage.Resolutions[resolution].SizeY / (double)SelectedImage.Resolutions[value].SizeY);
double x = ((double)PyramidalOrigin.X / (double)SelectedImage.Resolutions[resolution].SizeX) * (double)SelectedImage.Resolutions[value].SizeX;
double y = ((double)PyramidalOrigin.Y / (double)SelectedImage.Resolutions[resolution].SizeY) * (double)SelectedImage.Resolutions[value].SizeY;
scrollH.Adjustment.Upper = SelectedImage.Resolutions[value].SizeX;
scrollV.Adjustment.Upper = SelectedImage.Resolutions[value].SizeY;
PyramidalOrigin = new Point((int)x, (int)y);
SelectedImage.Resolution = value;
resolution = value;
UpdateImage();
UpdateView();

}
}
SizeF scale = new SizeF(1, 1);
Expand Down Expand Up @@ -1890,7 +1947,6 @@ private void ImageView_ButtonPressEvent(object o, ButtonPressEventArgs e)
}
UpdateView();
}

if (e.Event.Button == 1)
{
Point s = new Point(SelectedImage.SizeX, SelectedImage.SizeY);
Expand Down Expand Up @@ -1943,6 +1999,14 @@ private void ImageView_ButtonPressEvent(object o, ButtonPressEventArgs e)
}
}
}

if(SelectedImage.isPyramidal && overview.IntersectsWith(e.Event.X,e.Event.Y))
{
Resolution rs = SelectedImage.Resolutions[Resolution];
double dx = ((e.Event.X) / overview.Width) * rs.SizeX;
double dy = ((e.Event.Y) / overview.Height) * rs.SizeY;
PyramidalOrigin = new Point((int)dx, (int)dy);
}
}
UpdateStatus();
App.tools.ToolDown(mouseDown, e);
Expand Down Expand Up @@ -2040,8 +2104,6 @@ public double ToViewH(double d)
double y = (double)(d / PxHmicron) * Scale.Height;
return y;
}


public PointD ToScreenSpace(double x, double y)
{
double fx = ToScreenScaleW(Origin.X - x);
Expand Down

0 comments on commit 4b71f65

Please sign in to comment.