BioLib  3.6.2
A GUI-less version of Bio .NET library for editing & annotating various microscopy image formats.
Loading...
Searching...
No Matches
BioLib.ImageUtil Class Reference

Static Public Member Functions

static Image< L8 > Join8Bit (IEnumerable< Tuple< Extent, byte[]> > srcPixelTiles, Extent srcPixelExtent, Extent dstPixelExtent)
 Join by srcPixelTiles and cut by srcPixelExtent then scale to dstPixelExtent (only height an width is useful).
 
static Image< Rgb24 > JoinRGB24 (IEnumerable< Tuple< Extent, byte[]> > srcPixelTiles, Extent srcPixelExtent, Extent dstPixelExtent)
 Join by srcPixelTiles and cut by srcPixelExtent then scale to dstPixelExtent (only height an width is useful).
 
static Image< L16 > Join16 (IEnumerable< Tuple< Extent, byte[]> > srcPixelTiles, Extent srcPixelExtent, Extent dstPixelExtent)
 Join by srcPixelTiles and cut by srcPixelExtent then scale to dstPixelExtent (only height an width is useful).
 
static unsafe NetVips.Image JoinVipsRGB24 (IEnumerable< Tuple< Extent, byte[]> > srcPixelTiles, Extent srcPixelExtent, Extent dstPixelExtent)
 Join by srcPixelTiles and cut by srcPixelExtent then scale to dstPixelExtent (only height an width is useful).
 
static unsafe NetVips.Image JoinVips16 (IEnumerable< Tuple< Extent, byte[]> > srcPixelTiles, Extent srcPixelExtent, Extent dstPixelExtent)
 Join by srcPixelTiles and cut by srcPixelExtent then scale to dstPixelExtent (only height an width is useful).
 
static SixLabors.ImageSharp.Image CreateImageFromBytes (byte[] rgbBytes, int width, int height, AForge.PixelFormat px)
 

Detailed Description

Definition at line 15 of file Utilities.cs.

Member Function Documentation

◆ CreateImageFromBytes()

static SixLabors.ImageSharp.Image BioLib.ImageUtil.CreateImageFromBytes ( byte[] rgbBytes,
int width,
int height,
AForge.PixelFormat px )
static

Definition at line 364 of file Utilities.cs.

365 {
366 if (px == AForge.PixelFormat.Format24bppRgb)
367 {
368 if (rgbBytes.Length != width * height * 3)
369 {
370 throw new ArgumentException("Byte array size does not match the dimensions of the image");
371 }
372
373 // Create a new image of the specified size
374 Image<Rgb24> image = new Image<Rgb24>(width, height);
375
376 // Index for the byte array
377 int byteIndex = 0;
378
379 // Iterate over the image pixels
380 for (int y = 0; y < height; y++)
381 {
382 for (int x = 0; x < width; x++)
383 {
384 // Create a color from the next three bytes
385 Rgb24 color = new Rgb24(rgbBytes[byteIndex], rgbBytes[byteIndex + 1], rgbBytes[byteIndex + 2]);
386 byteIndex += 3;
387 // Set the pixel
388 image[x, y] = color;
389 }
390 }
391
392 return image;
393 }
394 else
395 if (px == AForge.PixelFormat.Format16bppGrayScale)
396 {
397 if (rgbBytes.Length != width * height * 2)
398 {
399 throw new ArgumentException("Byte array size does not match the dimensions of the image");
400 }
401
402 // Create a new image of the specified size
403 Image<L16> image = new Image<L16>(width, height);
404
405 // Index for the byte array
406 int byteIndex = 0;
407
408 // Iterate over the image pixels
409 for (int y = 0; y < height; y++)
410 {
411 for (int x = 0; x < width; x++)
412 {
413 // Create a color from the next three bytes
414 L16 color = new L16(BitConverter.ToUInt16(rgbBytes, byteIndex));
415 byteIndex += 2;
416 // Set the pixel
417 image[x, y] = color;
418 }
419 }
420
421 return image;
422 }
423 else
424 if (px == AForge.PixelFormat.Format8bppIndexed)
425 {
426 if (rgbBytes.Length != width * height)
427 {
428 throw new ArgumentException("Byte array size does not match the dimensions of the image");
429 }
430
431 // Create a new image of the specified size
432 Image<L8> image = new Image<L8>(width, height);
433
434 // Index for the byte array
435 int byteIndex = 0;
436
437 // Iterate over the image pixels
438 for (int y = 0; y < height; y++)
439 {
440 for (int x = 0; x < width; x++)
441 {
442 // Create a color from the next three bytes
443 L8 color = new L8(rgbBytes[byteIndex]);
444 byteIndex++;
445 // Set the pixel
446 image[x, y] = color;
447 }
448 }
449
450 return image;
451 }
452 else
453 if (px == AForge.PixelFormat.Format32bppArgb)
454 {
455 if (rgbBytes.Length != width * height * 4)
456 {
457 throw new ArgumentException("Byte array size does not match the dimensions of the image");
458 }
459
460 // Create a new image of the specified size
461 Image<Bgra32> image = new Image<Bgra32>(width, height);
462
463 // Index for the byte array
464 int byteIndex = 0;
465
466 // Iterate over the image pixels
467 for (int y = 0; y < height; y++)
468 {
469 for (int x = 0; x < width; x++)
470 {
471 // Create a color from the next three bytes
472 Bgra32 color = new Bgra32(rgbBytes[byteIndex], rgbBytes[byteIndex + 1], rgbBytes[byteIndex + 2], rgbBytes[byteIndex + 3]);
473 byteIndex += 4;
474 // Set the pixel
475 image[x, y] = color;
476 }
477 }
478
479 return image;
480 }
481 return null;
482 }

◆ Join16()

static Image< L16 > BioLib.ImageUtil.Join16 ( IEnumerable< Tuple< Extent, byte[]> > srcPixelTiles,
Extent srcPixelExtent,
Extent dstPixelExtent )
static

Join by srcPixelTiles and cut by srcPixelExtent then scale to dstPixelExtent (only height an width is useful).

Parameters
srcPixelTilestile with tile extent collection
srcPixelExtentcanvas extent
dstPixelExtentjpeg output size
Returns

Definition at line 183 of file Utilities.cs.

184 {
185 if (srcPixelTiles == null || srcPixelTiles.Count() == 0)
186 return null;
187 srcPixelExtent = srcPixelExtent.ToIntegerExtent();
188 dstPixelExtent = dstPixelExtent.ToIntegerExtent();
189 int canvasWidth = (int)srcPixelExtent.Width;
190 int canvasHeight = (int)srcPixelExtent.Height;
191 var dstWidth = (int)dstPixelExtent.Width;
192 var dstHeight = (int)dstPixelExtent.Height;
193 Image<L16> canvas = new Image<L16>(canvasWidth, canvasHeight);
194 foreach (var tile in srcPixelTiles)
195 {
196 try
197 {
198 var tileExtent = tile.Item1.ToIntegerExtent();
199 var intersect = srcPixelExtent.Intersect(tileExtent);
200 if (intersect.Width == 0 || intersect.Height == 0)
201 continue;
202 if (tile.Item2 == null)
203 continue;
204 Image<L16> tileRawData = (Image<L16>)CreateImageFromBytes(tile.Item2, (int)tileExtent.Width, (int)tileExtent.Height, AForge.PixelFormat.Format16bppGrayScale);
205 var tileOffsetPixelX = (int)Math.Ceiling(intersect.MinX - tileExtent.MinX);
206 var tileOffsetPixelY = (int)Math.Ceiling(intersect.MinY - tileExtent.MinY);
207 var canvasOffsetPixelX = (int)Math.Ceiling(intersect.MinX - srcPixelExtent.MinX);
208 var canvasOffsetPixelY = (int)Math.Ceiling(intersect.MinY - srcPixelExtent.MinY);
209 //We copy the tile region to the canvas.
210 for (int y = 0; y < intersect.Height; y++)
211 {
212 for (int x = 0; x < intersect.Width; x++)
213 {
214 int indx = canvasOffsetPixelX + x;
215 int indy = canvasOffsetPixelY + y;
216 int tindx = tileOffsetPixelX + x;
217 int tindy = tileOffsetPixelY + y;
218 canvas[indx, indy] = tileRawData[tindx, tindy];
219 }
220 }
221 tileRawData.Dispose();
222 }
223 catch (Exception e)
224 {
225 Console.WriteLine(e.ToString());
226 }
227
228 }
229 if (dstWidth != canvasWidth || dstHeight != canvasHeight)
230 {
231 try
232 {
233 canvas.Mutate(x => x.Resize(dstWidth, dstHeight));
234 return canvas;
235 }
236 catch (Exception e)
237 {
238 Console.WriteLine(e.Message);
239 }
240
241 }
242 return canvas;
243 }

◆ Join8Bit()

static Image< L8 > BioLib.ImageUtil.Join8Bit ( IEnumerable< Tuple< Extent, byte[]> > srcPixelTiles,
Extent srcPixelExtent,
Extent dstPixelExtent )
static

Join by srcPixelTiles and cut by srcPixelExtent then scale to dstPixelExtent (only height an width is useful).

Parameters
srcPixelTilestile with tile extent collection
srcPixelExtentcanvas extent
dstPixelExtentjpeg output size
Returns

Definition at line 24 of file Utilities.cs.

25 {
26 if (srcPixelTiles == null || !srcPixelTiles.Any())
27 return null;
28
29 // Convert extents to integer extents
30 srcPixelExtent = srcPixelExtent.ToIntegerExtent();
31 dstPixelExtent = dstPixelExtent.ToIntegerExtent();
32
33 int canvasWidth = (int)srcPixelExtent.Width;
34 int canvasHeight = (int)srcPixelExtent.Height;
35 int dstWidth = (int)dstPixelExtent.Width;
36 int dstHeight = (int)dstPixelExtent.Height;
37
38 // Create the canvas image
39 var canvas = new Image<L8>(canvasWidth, canvasHeight);
40
41 foreach (var tile in srcPixelTiles)
42 {
43 try
44 {
45 if (tile?.Item2 == null) // Skip null tiles
46 continue;
47
48 var tileExtent = tile.Item1.ToIntegerExtent();
49 var intersect = srcPixelExtent.Intersect(tileExtent);
50
51 // Skip tiles that do not intersect with the source extent
52 if (intersect.Width == 0 || intersect.Height == 0)
53 continue;
54
55 // Create an image from the tile data
56 using Image<L8> tileRawData = (Image<L8>)CreateImageFromBytes(
57 tile.Item2,
58 (int)tileExtent.Width,
59 (int)tileExtent.Height,
60 AForge.PixelFormat.Format8bppIndexed
61 );
62
63 // Compute offsets
64 int tileOffsetX = (int)(intersect.MinX - tileExtent.MinX);
65 int tileOffsetY = (int)(intersect.MinY - tileExtent.MinY);
66 int canvasOffsetX = (int)(intersect.MinX - srcPixelExtent.MinX);
67 int canvasOffsetY = (int)(intersect.MinY - srcPixelExtent.MinY);
68
69 // Copy intersected region from tile to canvas
70 for (int y = 0; y < intersect.Height; y++)
71 {
72 for (int x = 0; x < intersect.Width; x++)
73 {
74 int canvasX = canvasOffsetX + x;
75 int canvasY = canvasOffsetY + y;
76 int tileX = tileOffsetX + x;
77 int tileY = tileOffsetY + y;
78
79 // Use the older approach to manipulate pixel data
80 canvas[canvasX, canvasY] = tileRawData[tileX, tileY];
81 }
82 }
83 }
84 catch (Exception ex)
85 {
86 Console.WriteLine($"Error processing tile: {ex.Message}\n{ex.StackTrace}");
87 }
88 }
89
90 // Resize if necessary
91 if (dstWidth != canvasWidth || dstHeight != canvasHeight)
92 {
93 try
94 {
95 canvas.Mutate(x => x.Resize(dstWidth, dstHeight));
96 }
97 catch (Exception ex)
98 {
99 Console.WriteLine($"Error resizing canvas: {ex.Message}\n{ex.StackTrace}");
100 return null;
101 }
102 }
103
104 return canvas; // Return the canvas image
105 }

◆ JoinRGB24()

static Image< Rgb24 > BioLib.ImageUtil.JoinRGB24 ( IEnumerable< Tuple< Extent, byte[]> > srcPixelTiles,
Extent srcPixelExtent,
Extent dstPixelExtent )
static

Join by srcPixelTiles and cut by srcPixelExtent then scale to dstPixelExtent (only height an width is useful).

Parameters
srcPixelTilestile with tile extent collection
srcPixelExtentcanvas extent
dstPixelExtentjpeg output size
Returns

Definition at line 114 of file Utilities.cs.

115 {
116 if (srcPixelTiles == null || srcPixelTiles.Count() == 0)
117 return null;
118 srcPixelExtent = srcPixelExtent.ToIntegerExtent();
119 dstPixelExtent = dstPixelExtent.ToIntegerExtent();
120 int canvasWidth = (int)srcPixelExtent.Width;
121 int canvasHeight = (int)srcPixelExtent.Height;
122 var dstWidth = (int)dstPixelExtent.Width;
123 var dstHeight = (int)dstPixelExtent.Height;
124 Image<Rgb24> canvas = new Image<Rgb24>(canvasWidth, canvasHeight);
125 foreach (var tile in srcPixelTiles)
126 {
127 try
128 {
129 var tileExtent = tile.Item1.ToIntegerExtent();
130 var intersect = srcPixelExtent.Intersect(tileExtent);
131 if (intersect.Width == 0 || intersect.Height == 0)
132 continue;
133 if(tile.Item2 == null)
134 continue;
135 Image<Rgb24> tileRawData = (Image<Rgb24>)CreateImageFromBytes(tile.Item2, (int)tileExtent.Width, (int)tileExtent.Height,AForge.PixelFormat.Format24bppRgb);
136 var tileOffsetPixelX = (int)Math.Ceiling(intersect.MinX - tileExtent.MinX);
137 var tileOffsetPixelY = (int)Math.Ceiling(intersect.MinY - tileExtent.MinY);
138 var canvasOffsetPixelX = (int)Math.Ceiling(intersect.MinX - srcPixelExtent.MinX);
139 var canvasOffsetPixelY = (int)Math.Ceiling(intersect.MinY - srcPixelExtent.MinY);
140 //We copy the tile region to the canvas.
141 for (int y = 0; y < intersect.Height; y++)
142 {
143 for (int x = 0; x < intersect.Width; x++)
144 {
145 int indx = canvasOffsetPixelX + x;
146 int indy = canvasOffsetPixelY + y;
147 int tindx = tileOffsetPixelX + x;
148 int tindy = tileOffsetPixelY + y;
149 canvas[indx, indy] = tileRawData[tindx, tindy];
150 }
151 }
152 tileRawData.Dispose();
153 }
154 catch (Exception e)
155 {
156 Console.WriteLine(e.ToString());
157 }
158
159 }
160 if (dstWidth != canvasWidth || dstHeight != canvasHeight)
161 {
162 try
163 {
164 canvas.Mutate(x => x.Resize(dstWidth, dstHeight));
165 return canvas;
166 }
167 catch (Exception e)
168 {
169 Console.WriteLine(e.Message);
170 }
171
172 }
173 return canvas;
174 }

◆ JoinVips16()

static unsafe NetVips.Image BioLib.ImageUtil.JoinVips16 ( IEnumerable< Tuple< Extent, byte[]> > srcPixelTiles,
Extent srcPixelExtent,
Extent dstPixelExtent )
static

Join by srcPixelTiles and cut by srcPixelExtent then scale to dstPixelExtent (only height an width is useful).

Parameters
srcPixelTilestile with tile extent collection
srcPixelExtentcanvas extent
dstPixelExtentjpeg output size
Returns

Definition at line 311 of file Utilities.cs.

312 {
313 if (srcPixelTiles == null || !srcPixelTiles.Any())
314 return null;
315
316 srcPixelExtent = srcPixelExtent.ToIntegerExtent();
317 dstPixelExtent = dstPixelExtent.ToIntegerExtent();
318 int canvasWidth = (int)srcPixelExtent.Width;
319 int canvasHeight = (int)srcPixelExtent.Height;
320
321 // Create a base canvas. Adjust as necessary, for example, using a transparent image if needed.
322 Bitmap bf = new Bitmap(canvasWidth, canvasHeight, AForge.PixelFormat.Format16bppGrayScale);
323 NetVips.Image canvas = NetVips.Image.NewFromMemory(bf.Bytes, bf.SizeX, bf.SizeX, 1, Enums.BandFormat.Ushort);
324
325 foreach (var tile in srcPixelTiles)
326 {
327 if (tile.Item2 == null)
328 continue;
329
330 fixed (byte* pTileData = tile.Item2)
331 {
332 var tileExtent = tile.Item1.ToIntegerExtent();
333 NetVips.Image tileImage = NetVips.Image.NewFromMemory((IntPtr)pTileData, (ulong)tile.Item2.Length, (int)tileExtent.Width, (int)tileExtent.Height, 1, Enums.BandFormat.Ushort);
334
335 // Calculate positions and sizes for cropping and inserting
336 var intersect = srcPixelExtent.Intersect(tileExtent);
337 if (intersect.Width == 0 || intersect.Height == 0)
338 continue;
339
340 int tileOffsetPixelX = (int)Math.Ceiling(intersect.MinX - tileExtent.MinX);
341 int tileOffsetPixelY = (int)Math.Ceiling(intersect.MinY - tileExtent.MinY);
342 int canvasOffsetPixelX = (int)Math.Ceiling(intersect.MinX - srcPixelExtent.MinX);
343 int canvasOffsetPixelY = (int)Math.Ceiling(intersect.MinY - srcPixelExtent.MinY);
344
345 using (var croppedTile = tileImage.Crop(tileOffsetPixelX, tileOffsetPixelY, (int)intersect.Width, (int)intersect.Height))
346 {
347 // Instead of inserting directly, we composite over the base canvas
348 canvas = canvas.Composite2(croppedTile, Enums.BlendMode.Over, canvasOffsetPixelX, canvasOffsetPixelY);
349 }
350 }
351 }
352
353 // Resize if the destination extent differs from the source canvas size
354 if ((int)dstPixelExtent.Width != canvasWidth || (int)dstPixelExtent.Height != canvasHeight)
355 {
356 double scaleX = (double)dstPixelExtent.Width / canvasWidth;
357 double scaleY = (double)dstPixelExtent.Height / canvasHeight;
358 canvas = canvas.Resize(scaleX, vscale: scaleY, kernel: Enums.Kernel.Nearest);
359 }
360
361 return canvas;
362 }

◆ JoinVipsRGB24()

static unsafe NetVips.Image BioLib.ImageUtil.JoinVipsRGB24 ( IEnumerable< Tuple< Extent, byte[]> > srcPixelTiles,
Extent srcPixelExtent,
Extent dstPixelExtent )
static

Join by srcPixelTiles and cut by srcPixelExtent then scale to dstPixelExtent (only height an width is useful).

Parameters
srcPixelTilestile with tile extent collection
srcPixelExtentcanvas extent
dstPixelExtentjpeg output size
Returns

Definition at line 252 of file Utilities.cs.

253 {
254 if (srcPixelTiles == null || !srcPixelTiles.Any())
255 return null;
256
257 srcPixelExtent = srcPixelExtent.ToIntegerExtent();
258 dstPixelExtent = dstPixelExtent.ToIntegerExtent();
259 int canvasWidth = (int)srcPixelExtent.Width;
260 int canvasHeight = (int)srcPixelExtent.Height;
261
262 // Create a base canvas. Adjust as necessary, for example, using a transparent image if needed.
263 NetVips.Image canvas = NetVips.Image.Black(canvasWidth, canvasHeight, bands: 3);
264
265 foreach (var tile in srcPixelTiles)
266 {
267 if (tile.Item2 == null)
268 continue;
269
270 fixed (byte* pTileData = tile.Item2)
271 {
272 var tileExtent = tile.Item1.ToIntegerExtent();
273 NetVips.Image tileImage = NetVips.Image.NewFromMemory((IntPtr)pTileData, (ulong)tile.Item2.Length, (int)tileExtent.Width, (int)tileExtent.Height, 3, Enums.BandFormat.Uchar);
274
275 // Calculate positions and sizes for cropping and inserting
276 var intersect = srcPixelExtent.Intersect(tileExtent);
277 if (intersect.Width == 0 || intersect.Height == 0)
278 continue;
279
280 int tileOffsetPixelX = (int)Math.Ceiling(intersect.MinX - tileExtent.MinX);
281 int tileOffsetPixelY = (int)Math.Ceiling(intersect.MinY - tileExtent.MinY);
282 int canvasOffsetPixelX = (int)Math.Ceiling(intersect.MinX - srcPixelExtent.MinX);
283 int canvasOffsetPixelY = (int)Math.Ceiling(intersect.MinY - srcPixelExtent.MinY);
284
285 using (var croppedTile = tileImage.Crop(tileOffsetPixelX, tileOffsetPixelY, (int)intersect.Width, (int)intersect.Height))
286 {
287 // Instead of inserting directly, we composite over the base canvas
288 canvas = canvas.Composite2(croppedTile, Enums.BlendMode.Over, canvasOffsetPixelX, canvasOffsetPixelY);
289 }
290 }
291 }
292
293 // Resize if the destination extent differs from the source canvas size
294 if ((int)dstPixelExtent.Width != canvasWidth || (int)dstPixelExtent.Height != canvasHeight)
295 {
296 double scaleX = (double)dstPixelExtent.Width / canvasWidth;
297 double scaleY = (double)dstPixelExtent.Height / canvasHeight;
298 canvas = canvas.Resize(scaleX, vscale: scaleY, kernel: Enums.Kernel.Nearest);
299 }
300
301 return canvas;
302 }

The documentation for this class was generated from the following file: