Skip to content

Commit 7fc849c

Browse files
committed
4.0.0 OME type slide fix.
Support for 16 bit slides.
1 parent 3a96680 commit 7fc849c

File tree

6 files changed

+435
-41
lines changed

6 files changed

+435
-41
lines changed

BioImager.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
<PackageTags>Microscopy;Biology;</PackageTags>
1515
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
1616
<Description>A .NET microscopy imaging application based on Bio library. Supports various microscopes by using imported libraries &amp; GUI automation. Supported libraries include Prior® &amp; Zeiss® &amp; all devices supported by Micromanager 2.0 and python-microscope.</Description>
17-
<Version>3.9.1</Version>
17+
<Version>4.0.0</Version>
1818
<PackageProjectUrl></PackageProjectUrl>
1919
<RepositoryUrl>https://github.com/BiologyTools/BioImager</RepositoryUrl>
2020
<PackageLicenseFile></PackageLicenseFile>
2121
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
22-
<PackageReleaseNotes>Accelerated graphics fix.</PackageReleaseNotes>
22+
<PackageReleaseNotes>OME type slides fix. Support for 16 bit slides.</PackageReleaseNotes>
2323
<Platforms>AnyCPU;x86;x64</Platforms>
2424
</PropertyGroup>
2525
<ItemGroup>

Source/Bio/ISlideSource.cs

+58-20
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using SixLabors.ImageSharp;
99
using SixLabors.ImageSharp.PixelFormats;
1010
using AForge;
11+
using Image = SixLabors.ImageSharp.Image;
1112
namespace BioImager
1213
{
1314
public class LruCache<TileInformation, TValue>
@@ -62,6 +63,13 @@ public void Add(Info key, TValue value)
6263
lruList.AddLast(newNode);
6364
cacheMap[key] = newNode;
6465
}
66+
public void Dispose()
67+
{
68+
foreach (LinkedListNode<(Info key, TValue value)> item in cacheMap.Values)
69+
{
70+
lruList.Remove(item);
71+
}
72+
}
6573
}
6674
public class TileCache
6775
{
@@ -110,6 +118,10 @@ private async Task<byte[]> LoadTile(TileInformation tileId)
110118
return null;
111119
}
112120
}
121+
public void Dispose()
122+
{
123+
cache.Dispose();
124+
}
113125
}
114126

115127
public class TileInformation
@@ -160,7 +172,6 @@ public static ISlideSource Create(BioImage source, SlideImage im, bool enableCac
160172
}
161173
#endregion
162174
public double MinUnitsPerPixel { get; protected set; }
163-
public static byte[] LastSlice;
164175
public static Extent destExtent;
165176
public static Extent sourceExtent;
166177
public static double curUnitsPerPixel = 1;
@@ -194,9 +205,12 @@ public async Task<byte[]> GetSlice(SliceInfo sliceInfo)
194205
{
195206
try
196207
{
197-
NetVips.Image im = OpenSlideGTK.ImageUtil.JoinVips(tiles, srcPixelExtent, new Extent(0, 0, dstPixelWidth, dstPixelHeight));
198-
LastSlice = im.WriteToMemory();
199-
return LastSlice;
208+
NetVips.Image im = null;
209+
if (this.Image.BioImage.Resolutions[curLevel].PixelFormat == PixelFormat.Format16bppGrayScale)
210+
im = ImageUtil.JoinVips16(tiles, srcPixelExtent, new Extent(0, 0, dstPixelWidth, dstPixelHeight));
211+
else if(this.Image.BioImage.Resolutions[curLevel].PixelFormat == PixelFormat.Format24bppRgb)
212+
im = ImageUtil.JoinVipsRGB24(tiles, srcPixelExtent, new Extent(0, 0, dstPixelWidth, dstPixelHeight));
213+
return im.WriteToMemory();
200214
}
201215
catch (Exception e)
202216
{
@@ -207,16 +221,28 @@ public async Task<byte[]> GetSlice(SliceInfo sliceInfo)
207221
}
208222
try
209223
{
210-
Image<Rgb24> im = OpenSlideGTK.ImageUtil.Join(tiles, srcPixelExtent, new Extent(0, 0, dstPixelWidth, dstPixelHeight));
211-
LastSlice = GetRgb24Bytes(im);
212-
im.Dispose();
224+
Image im = null;
225+
if (this.Image.BioImage.Resolutions[curLevel].PixelFormat == PixelFormat.Format16bppGrayScale)
226+
{
227+
im = ImageUtil.Join16(tiles, srcPixelExtent, new Extent(0, 0, dstPixelWidth, dstPixelHeight));
228+
byte[] bts = Get16Bytes((Image<L16>)im);
229+
im.Dispose();
230+
return bts;
231+
}
232+
else if (this.Image.BioImage.Resolutions[curLevel].PixelFormat == PixelFormat.Format24bppRgb)
233+
{
234+
im = ImageUtil.JoinRGB24(tiles, srcPixelExtent, new Extent(0, 0, dstPixelWidth, dstPixelHeight));
235+
byte[] bts = GetRgb24Bytes((Image<Rgb24>)im);
236+
im.Dispose();
237+
return bts;
238+
}
213239
}
214240
catch (Exception er)
215241
{
216242
Console.WriteLine(er.Message);
217243
return null;
218244
}
219-
return LastSlice;
245+
return null;
220246
}
221247
public byte[] GetRgb24Bytes(Image<Rgb24> image)
222248
{
@@ -230,14 +256,34 @@ public byte[] GetRgb24Bytes(Image<Rgb24> image)
230256
for (int x = 0; x < width; x++)
231257
{
232258
Rgb24 pixel = image[x, y];
233-
rgbBytes[byteIndex++] = pixel.R;
234-
rgbBytes[byteIndex++] = pixel.G;
235259
rgbBytes[byteIndex++] = pixel.B;
260+
rgbBytes[byteIndex++] = pixel.G;
261+
rgbBytes[byteIndex++] = pixel.R;
236262
}
237263
}
238264

239265
return rgbBytes;
240266
}
267+
public byte[] Get16Bytes(Image<L16> image)
268+
{
269+
int width = image.Width;
270+
int height = image.Height;
271+
byte[] bytes = new byte[width * height * 2];
272+
273+
int byteIndex = 0;
274+
for (int y = 0; y < height; y++)
275+
{
276+
for (int x = 0; x < width; x++)
277+
{
278+
L16 pixel = image[x, y];
279+
byte[] bts = BitConverter.GetBytes(pixel.PackedValue);
280+
bytes[byteIndex++] = bts[0];
281+
bytes[byteIndex++] = bts[1];
282+
}
283+
}
284+
285+
return bytes;
286+
}
241287

242288
public SlideImage Image { get; set; }
243289

@@ -291,11 +337,7 @@ public async Task<byte[]> GetTileAsync(TileInformation tileInfo)
291337
var curTileWidth = (int)(tileInfo.Extent.MaxX > Schema.Extent.Width ? tileWidth - (tileInfo.Extent.MaxX - Schema.Extent.Width) / r : tileWidth);
292338
var curTileHeight = (int)(-tileInfo.Extent.MinY > Schema.Extent.Height ? tileHeight - (-tileInfo.Extent.MinY - Schema.Extent.Height) / r : tileHeight);
293339
var bgraData = await Image.ReadRegionAsync(tileInfo.Index.Level, (long)curLevelOffsetXPixel, (long)curLevelOffsetYPixel, curTileWidth, curTileHeight,tileInfo.Coordinate);
294-
//We check to see if the data is valid.
295-
if (bgraData.Length != curTileWidth * curTileHeight * 4)
296-
return null;
297-
byte[] bm = ConvertRgbaToRgb(bgraData);
298-
return bm;
340+
return bgraData;
299341
}
300342
public async Task<byte[]> GetTileAsync(BruTile.TileInfo tileInfo)
301343
{
@@ -309,11 +351,7 @@ public async Task<byte[]> GetTileAsync(BruTile.TileInfo tileInfo)
309351
var curTileWidth = (int)(tileInfo.Extent.MaxX > Schema.Extent.Width ? tileWidth - (tileInfo.Extent.MaxX - Schema.Extent.Width) / r : tileWidth);
310352
var curTileHeight = (int)(-tileInfo.Extent.MinY > Schema.Extent.Height ? tileHeight - (-tileInfo.Extent.MinY - Schema.Extent.Height) / r : tileHeight);
311353
var bgraData = await Image.ReadRegionAsync(tileInfo.Index.Level, (long)curLevelOffsetXPixel, (long)curLevelOffsetYPixel, curTileWidth, curTileHeight, new ZCT());
312-
//We check to see if the data is valid.
313-
if (bgraData.Length != curTileWidth * curTileHeight * 4)
314-
return null;
315-
byte[] bm = ConvertRgbaToRgb(bgraData);
316-
return bm;
354+
return bgraData;
317355
}
318356
public static byte[] ConvertRgbaToRgb(byte[] rgbaArray)
319357
{

Source/Bio/SlideBase.cs

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
using SixLabors.ImageSharp;
88
using SixLabors.ImageSharp.Processing;
99
using SixLabors.ImageSharp.PixelFormats;
10-
using AForge;
1110

1211
namespace BioImager
1312
{

Source/Bio/SlideImage.cs

+7-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using AForge;
22
using OpenSlideGTK;
33
using OpenSlideGTK.Interop;
4-
using org.checkerframework.common.returnsreceiver.qual;
54
using System;
65
using System.Collections.Generic;
76
using System.IO;
@@ -224,7 +223,7 @@ public int GetBestLevelForDownsample(double downsample)
224223
/// <exception cref="OpenSlideException"/>
225224
public unsafe byte[] ReadRegion(int level, long x, long y, long width, long height)
226225
{
227-
return BioImage.GetTile(BioImage, App.viewer.GetCoordinate(), level, (int)x, (int)y, (int)width, (int)height).RGBBytes;
226+
return BioImage.GetTile(BioImage, App.viewer.GetCoordinate(), level, (int)x, (int)y, (int)width, (int)height).Bytes;
228227
}
229228

230229
/// <summary>
@@ -237,22 +236,13 @@ public unsafe byte[] ReadRegion(int level, long x, long y, long width, long heig
237236
/// <param name="height">The height of the region. Must be non-negative.</param>
238237
/// <param name="data">The BGRA pixel data of this region.</param>
239238
/// <returns></returns>
240-
public unsafe bool TryReadRegion(int level, long x, long y, long width, long height, ZCT coord, out byte[] data)
239+
public unsafe bool TryReadRegion(int level, long x, long y, long width, long height, out byte[] data, ZCT zct)
241240
{
242-
try
243-
{
244-
data = BioImage.GetTile(BioImage, coord, level, (int)x, (int)y, (int)width, (int)height).RGBBytes;
245-
if (data == null)
246-
return false;
247-
else
248-
return true;
249-
}
250-
catch (Exception e)
251-
{
252-
data = null;
241+
data = BioImage.GetTile(BioImage, zct, level, (int)x, (int)y, (int)width, (int)height).Bytes;
242+
if (data == null)
253243
return false;
254-
}
255-
244+
else
245+
return true;
256246
}
257247

258248
///<summary>
@@ -308,7 +298,7 @@ public async Task<byte[]> ReadRegionAsync(int level, long curLevelOffsetXPixel,
308298
try
309299
{
310300
byte[] bts;
311-
TryReadRegion(level, curLevelOffsetXPixel, curLevelOffsetYPixel, curTileWidth, curTileHeight, coord,out bts);
301+
TryReadRegion(level, curLevelOffsetXPixel, curLevelOffsetYPixel, curTileWidth, curTileHeight,out bts,coord);
312302
return bts;
313303
}
314304
catch (Exception e)

Source/Bio/SlideTileLayer.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public SlideTileLayer(
3030
int minExtraTiles = -1,
3131
int maxExtraTiles = -1,
3232
Func<TileInfo, Task<IFeature>> fetchTileAsFeature = null)
33-
: base(source, minTiles, maxTiles, dataFetchStrategy, renderFetchStrategy, minExtraTiles, maxExtraTiles, fetchTileAsFeature)
33+
: base(source, minTiles, maxTiles, dataFetchStrategy, renderFetchStrategy, minExtraTiles, maxExtraTiles, (Func<BruTile.TileInfo, Task<IFeature>>)fetchTileAsFeature)
3434
{
3535
Name = "TileLayer";
3636
_slideSource = source;

0 commit comments

Comments
 (0)