Skip to content

Commit

Permalink
3.9.1 Pyramidal ZCT for OME slides.
Browse files Browse the repository at this point in the history
  • Loading branch information
BiologyTools committed Mar 6, 2024
1 parent 9206c7b commit 575f04a
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 46 deletions.
8 changes: 4 additions & 4 deletions BioCore/BioCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<Version>3.9.0</Version>
<Version>3.9.1</Version>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
Expand All @@ -23,9 +23,9 @@
<PackageId>BioCore</PackageId>
<Platforms>AnyCPU;x86;x64</Platforms>
<Description>A .NET library &amp; program for annotating, &amp; editing various microscopy imaging formats using Bioformats supported images. including whole slide, pyramidal &amp; series.</Description>
<AssemblyVersion>3.9.0</AssemblyVersion>
<FileVersion>3.9.0</FileVersion>
<PackageReleaseNotes>Viewing multiple pyramid files at the same time &amp; viewing improvements for pyramidal images.</PackageReleaseNotes>
<AssemblyVersion>3.9.1</AssemblyVersion>
<FileVersion>3.9.1</FileVersion>
<PackageReleaseNotes>Pyramidal ZCT depth support for OME type slides.</PackageReleaseNotes>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
Expand Down
6 changes: 3 additions & 3 deletions BioCore/Source/Bio.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5970,7 +5970,7 @@ public async void UpdateBuffersPyramidal()
else
{
start:
byte[] bts = await slideBase.GetSlice(new SliceInfo(PyramidalOrigin.X, PyramidalOrigin.Y, PyramidalSize.Width, PyramidalSize.Height, resolution));
byte[] bts = await slideBase.GetSlice(new SliceInfo(PyramidalOrigin.X, PyramidalOrigin.Y, PyramidalSize.Width, PyramidalSize.Height, resolution, new ZCT()));
if (bts == null)
{
if (PyramidalOrigin.X == 0 && PyramidalOrigin.Y == 0)
Expand Down Expand Up @@ -7955,7 +7955,7 @@ public static void Initialize()
/// > Initialize the OME-XML library
private static void InitOME()
{
factory = new ServiceFactory();
factory = new ServiceFactory();
service = (OMEXMLService)factory.getInstance(typeof(OMEXMLService));
reader = new ImageReader();
writer = new ImageWriter();
Expand Down Expand Up @@ -10321,7 +10321,7 @@ public static BioImage OpenOME(string file, int serie, bool tab, bool addToImage
Images.AddImage(b, tab);
return b;
}
public ImageReader imRead = new ImageReader();
public ImageReader imRead = null;
byte[] bts;
int ssx, ssy;
public static int FindFocus(BioImage im, int Channel, int Time)
Expand Down
81 changes: 56 additions & 25 deletions BioCore/Source/Bio/ISlideSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
using System.Threading.Tasks;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using BioCore;
using AForge;
namespace BioCore
{
public class LruCache<TKey, TValue>
Expand Down Expand Up @@ -57,31 +57,31 @@ public void Add(TKey key, TValue value)
}
public class TileCache
{
private LruCache<TileIndex, byte[]> cache;
private LruCache<TileInfo, byte[]> cache;
private int capacity;
ISlideSource source = null;
public TileCache(ISlideSource source, int capacity = 10000)
SlideSourceBase source = null;
public TileCache(SlideSourceBase source, int capacity = 10000)
{
this.source = source;
this.capacity = capacity;
this.cache = new LruCache<TileIndex, byte[]>(capacity);
this.cache = new LruCache<TileInfo, byte[]>(capacity);
}

public async Task<byte[]> GetTile(TileInfo info)
{
byte[] data = cache.Get(info.Index);
byte[] data = cache.Get(info);
if (data != null)
{
return data;
}
byte[] tile = await LoadTile(info);
AddTile(info.Index, tile);
AddTile(info, tile);
return tile;
}

private void AddTile(TileIndex tileId, byte[] tile)
private void AddTile(TileInfo tileId, byte[] tile)
{
cache.Add(tileId, tile);
cache.Add(tileId, tile);
}

private async Task<byte[]> LoadTile(TileInfo tileId)
Expand All @@ -93,10 +93,17 @@ private async Task<byte[]> LoadTile(TileInfo tileId)
catch (Exception e)
{
return null;
}
}
}
}

public class TileInfo
{
public TileIndex Index { get; set; }
public Extent Extent { get; set; }
public ZCT Coordinate { get; set; }
}

public abstract class SlideSourceBase : ISlideSource, IDisposable
{
#region Static
Expand All @@ -117,7 +124,7 @@ public static void Resister(string extensionUpper, Func<string, bool, ISlideSour

public static ISlideSource Create(BioImage source, SlideImage im, bool enableCache = true)
{

var ext = Path.GetExtension(source.file).ToUpper();
try
{
Expand All @@ -127,12 +134,12 @@ public static ISlideSource Create(BioImage source, SlideImage im, bool enableCac
if (!string.IsNullOrEmpty(SlideBase.DetectVendor(source.file)))
{
SlideBase b = new SlideBase(source, im, enableCache);

}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return null;
}
Expand All @@ -152,11 +159,15 @@ public async Task<byte[]> GetSlice(SliceInfo sliceInfo)
var curUnitsPerPixel = Schema.Resolutions[curLevel].UnitsPerPixel;
var tileInfos = Schema.GetTileInfos(sliceInfo.Extent, curLevel);
List<Tuple<Extent, byte[]>> tiles = new List<Tuple<Extent, byte[]>>();
foreach (TileInfo t in tileInfos)
foreach (BruTile.TileInfo t in tileInfos)
{
byte[] c = await cache.GetTile(t);
if(c!=null)
tiles.Add(Tuple.Create(t.Extent.WorldToPixelInvertedY(curUnitsPerPixel), c));
TileInfo tf = new TileInfo();
tf.Extent = t.Extent;
tf.Coordinate = App.viewer.GetCoordinate();
tf.Index = t.Index;
byte[] c = await cache.GetTile(tf);
if (c != null)
tiles.Add(Tuple.Create(t.Extent.WorldToPixelInvertedY(curUnitsPerPixel), c));
}
var srcPixelExtent = sliceInfo.Extent.WorldToPixelInvertedY(curUnitsPerPixel);
var dstPixelExtent = sliceInfo.Extent.WorldToPixelInvertedY(sliceInfo.Resolution);
Expand Down Expand Up @@ -264,10 +275,26 @@ public async Task<byte[]> GetTileAsync(TileInfo tileInfo)
var curLevelOffsetYPixel = -tileInfo.Extent.MaxY / Schema.Resolutions[tileInfo.Index.Level].UnitsPerPixel;
var curTileWidth = (int)(tileInfo.Extent.MaxX > Schema.Extent.Width ? tileWidth - (tileInfo.Extent.MaxX - Schema.Extent.Width) / r : tileWidth);
var curTileHeight = (int)(-tileInfo.Extent.MinY > Schema.Extent.Height ? tileHeight - (-tileInfo.Extent.MinY - Schema.Extent.Height) / r : tileHeight);
var bgraData = await Image.ReadRegionAsync(tileInfo.Index.Level, (long)curLevelOffsetXPixel, (long)curLevelOffsetYPixel, curTileWidth, curTileHeight);
var bgraData = await Image.ReadRegionAsync(tileInfo.Index.Level, (long)curLevelOffsetXPixel, (long)curLevelOffsetYPixel, curTileWidth, curTileHeight, tileInfo.Coordinate);
//We check to see if the data is valid.
if (bgraData == null)
if (bgraData.Length != curTileWidth * curTileHeight * 4)
return null;
byte[] bm = ConvertRgbaToRgb(bgraData);
return bm;
}
public async Task<byte[]> GetTileAsync(BruTile.TileInfo tileInfo)
{
if (tileInfo == null)
return null;
var r = Schema.Resolutions[tileInfo.Index.Level].UnitsPerPixel;
var tileWidth = Schema.Resolutions[tileInfo.Index.Level].TileWidth;
var tileHeight = Schema.Resolutions[tileInfo.Index.Level].TileHeight;
var curLevelOffsetXPixel = tileInfo.Extent.MinX / Schema.Resolutions[tileInfo.Index.Level].UnitsPerPixel;
var curLevelOffsetYPixel = -tileInfo.Extent.MaxY / Schema.Resolutions[tileInfo.Index.Level].UnitsPerPixel;
var curTileWidth = (int)(tileInfo.Extent.MaxX > Schema.Extent.Width ? tileWidth - (tileInfo.Extent.MaxX - Schema.Extent.Width) / r : tileWidth);
var curTileHeight = (int)(-tileInfo.Extent.MinY > Schema.Extent.Height ? tileHeight - (-tileInfo.Extent.MinY - Schema.Extent.Height) / r : tileHeight);
var bgraData = await Image.ReadRegionAsync(tileInfo.Index.Level, (long)curLevelOffsetXPixel, (long)curLevelOffsetYPixel, curTileWidth, curTileHeight, new ZCT());
//We check to see if the data is valid.
if (bgraData.Length != curTileWidth * curTileHeight * 4)
return null;
byte[] bm = ConvertRgbaToRgb(bgraData);
Expand Down Expand Up @@ -352,9 +379,9 @@ public SliceInfo() { }
/// <param name="widthPixel">pixel width</param>
/// <param name="heightPixel">pixel height</param>
/// <param name="unitsPerPixel">um/pixel</param>
public SliceInfo(double xPixel, double yPixel, double widthPixel, double heightPixel, double unitsPerPixel)
public SliceInfo(double xPixel, double yPixel, double widthPixel, double heightPixel, double unitsPerPixel, ZCT coord)
{
Extent = new Extent(xPixel, yPixel, xPixel + widthPixel,yPixel + heightPixel).PixelToWorldInvertedY(unitsPerPixel);
Extent = new Extent(xPixel, yPixel, xPixel + widthPixel, yPixel + heightPixel).PixelToWorldInvertedY(unitsPerPixel);
Resolution = unitsPerPixel;
}

Expand All @@ -366,6 +393,10 @@ public double Resolution
get;
set;
} = 1;
/// <summary>
/// ZCT Coordinate
/// </summary>
public ZCT Coordinate { get; set; }

/// <summary>
/// World extent.
Expand Down Expand Up @@ -417,9 +448,9 @@ public enum SampleMode
/// </summary>
NearestUp,
/// <summary>
/// Nearest dwon.
/// Nearest down.
/// </summary>
NearestDwon,
NearestDown,
/// <summary>
/// Top.
/// </summary>
Expand Down
22 changes: 10 additions & 12 deletions BioCore/Source/Bio/SlideImage.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using OpenSlideGTK;
using AForge;
using BioCore;
using OpenSlideGTK;
using OpenSlideGTK.Interop;
using org.checkerframework.common.returnsreceiver.qual;
using System;
using System.Collections.Generic;
using System.IO;
Expand Down Expand Up @@ -236,16 +237,13 @@ public unsafe byte[] ReadRegion(int level, long x, long y, long width, long heig
/// <param name="height">The height of the region. Must be non-negative.</param>
/// <param name="data">The BGRA pixel data of this region.</param>
/// <returns></returns>
public unsafe bool TryReadRegion(int level, long x, long y, long width, long height, out byte[] data)
public unsafe bool TryReadRegion(int level, long x, long y, long width, long height, out byte[] data, ZCT zct)
{
BufferInfo bm = BioImage.GetTile(BioImage, App.viewer.GetCoordinate(), level, (int)x, (int)y, (int)width, (int)height);
if (bm!=null)
{
data = bm.RGBBytes;
data = BioImage.GetTile(BioImage, zct, level, (int)x, (int)y, (int)width, (int)height).RGBBytes;
if (data == null)
return false;
else
return true;
}
data = null;
return false;
}

///<summary>
Expand Down Expand Up @@ -296,12 +294,12 @@ public void Dispose()
GC.SuppressFinalize(this);
}

public async Task<byte[]> ReadRegionAsync(int level, long curLevelOffsetXPixel, long curLevelOffsetYPixel, int curTileWidth, int curTileHeight)
public async Task<byte[]> ReadRegionAsync(int level, long curLevelOffsetXPixel, long curLevelOffsetYPixel, int curTileWidth, int curTileHeight, ZCT coord)
{
try
{
byte[] bts;
TryReadRegion(level, curLevelOffsetXPixel, curLevelOffsetYPixel, curTileWidth, curTileHeight,out bts);
TryReadRegion(level, curLevelOffsetXPixel, curLevelOffsetYPixel, curTileWidth, curTileHeight,out bts,coord);
return bts;
}
catch (Exception e)
Expand Down
2 changes: 1 addition & 1 deletion BioCore/Source/Bio/SlideTileLayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public SlideTileLayer(
int minExtraTiles = -1,
int maxExtraTiles = -1,
Func<TileInfo, Task<IFeature>> fetchTileAsFeature = null)
: base(source, minTiles, maxTiles, dataFetchStrategy, renderFetchStrategy, minExtraTiles, maxExtraTiles, fetchTileAsFeature)
: base(source, minTiles, maxTiles, dataFetchStrategy, renderFetchStrategy, minExtraTiles, maxExtraTiles, (Func<BruTile.TileInfo, Task<IFeature>>)fetchTileAsFeature)
{
Name = "TileLayer";
_slideSource = source;
Expand Down
2 changes: 1 addition & 1 deletion BioCore/Source/ImageView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ private void InitPreview()
}
else
{
bts = _slideBase.GetSlice(new SliceInfo(PyramidalOrigin.X, PyramidalOrigin.Y, SelectedImage.PyramidalSize.Width, SelectedImage.PyramidalSize.Height, SelectedImage.GetUnitPerPixel(Level))).Result;
bts = _slideBase.GetSlice(new SliceInfo(PyramidalOrigin.X, PyramidalOrigin.Y, SelectedImage.PyramidalSize.Width, SelectedImage.PyramidalSize.Height, SelectedImage.GetUnitPerPixel(Level), GetCoordinate())).Result;
bf = new BufferInfo((int)Math.Round(SlideBase.destExtent.Width), (int)Math.Round(SlideBase.destExtent.Height), PixelFormat.Format24bppRgb, bts, new ZCT(), "");
}
bm = re.Apply((Bitmap)bf.ImageRGB);
Expand Down

0 comments on commit 575f04a

Please sign in to comment.