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

Represents a Mask layer. More...

Inheritance diagram for BioLib.ROI.Mask:

Public Member Functions

bool IsSelected (int x, int y)
 
float GetValue (int x, int y)
 
void SetValue (int x, int y, float val)
 
 Mask (float[] fts, int width, int height, double physX, double physY, double x, double y, bool useFloatStorage=false, bool absolutePosition=false)
 
 Mask (byte[] fts, int width, int height, double physX, double physY, double x, double y, bool absolutePosition=false, bool preserveDimensions=false)
 
Gdk.Pixbuf GetColored (AForge.Color col, byte alpha, bool forceUpdate=false)
 
byte[] GetColoredBytes (AForge.Color col)
 
byte[] GetBytesCropped ()
 
byte[] GetBytesCropped (int imageWidth, int imageHeight, out int cropWidth, out int cropHeight, out int startX, out int startY)
 
byte[] GetBytesCropped (out int cropWidth, out int cropHeight, out int startX, out int startY)
 
byte[] GetBytes ()
 
byte[] GetBytesLegacy ()
 
byte[] GetFullImageBytes (int fullWidth, int fullHeight)
 
void Dispose ()
 

Static Public Member Functions

static byte[] int int int int startY OutputAs8BitImage (float[] fullMask, int imageWidth, int imageHeight, float threshold=0.0f)
 
static float float max GetMinAndMax (float[] floatArray)
 
static float[] int int int int startY CropFullImageMask (float[] fullMask, int imageWidth, int imageHeight, float threshold=0.0f)
 

Public Attributes

float min = 0
 

Static Public Attributes

static byte[] grayImage
 Crops a mask based on non-zero values and converts it to an 8-bit grayscale image.
 
static byte[] int cropWidth
 
static byte[] int int cropHeight
 
static byte[] int int int startX
 
static float min
 Gets the minimum and maximum values from a float array.
 
static float[] croppedMask
 Crops the smallest rectangular region containing all "white" pixels (values above a threshold) from a full image mask.
 
static float[] int cropWidth
 
static float[] int int cropHeight
 
static float[] int int int startX
 

Properties

double X [get, set]
 
double Y [get, set]
 
int Width [get, set]
 
int Height [get, set]
 
double PhysicalSizeX [get, set]
 
double PhysicalSizeY [get, set]
 
Gdk.Pixbuf Pixbuf [get]
 

Detailed Description

Represents a Mask layer.

Constructor & Destructor Documentation

◆ Mask() [1/2]

BioLib.ROI.Mask.Mask ( float[] fts,
int width,
int height,
double physX,
double physY,
double x,
double y,
bool useFloatStorage = false,
bool absolutePosition = false )
329 {
330 this.width = width;
331 this.height = height;
332 X = x; Y = y;
333 PhysicalSizeX = physX;
334 PhysicalSizeY = physY;
335 if (useFloatStorage)
336 {
337 var cropResult = CropFullImageMask(fts, width, height, 0.0f);
338 mask = cropResult.croppedMask;
339 X = cropResult.startX;
340 Y = cropResult.startY;
341 this.width = cropResult.cropWidth;
342 this.height = cropResult.cropHeight;
343 }
344 else
345 {
346 byte[] bt = ConvertFloatMaskToBytesCropped(fts, width, height, out int cropWidth, out int cropHeight, out int startX, out int startY);
347 maskBytes = bt;
348 X = absolutePosition ? (x / physX) : startX;
349 Y = absolutePosition ? (y / physY) : startY;
350 this.width = cropWidth;
351 this.height = cropHeight;
352 }
353 }
double X
Definition ROI.cs:223
double PhysicalSizeY
Definition ROI.cs:228
double PhysicalSizeX
Definition ROI.cs:227
static byte[] int cropWidth
Definition ROI.cs:498
static byte[] int int int startX
Definition ROI.cs:498
static float[] int int int int startY CropFullImageMask(float[] fullMask, int imageWidth, int imageHeight, float threshold=0.0f)
Definition ROI.cs:818
double Y
Definition ROI.cs:224
static byte[] int int cropHeight
Definition ROI.cs:498

◆ Mask() [2/2]

BioLib.ROI.Mask.Mask ( byte[] fts,
int width,
int height,
double physX,
double physY,
double x,
double y,
bool absolutePosition = false,
bool preserveDimensions = false )
355 {
356 PhysicalSizeX = physX;
357 PhysicalSizeY = physY;
358 if (preserveDimensions)
359 {
360 maskBytes = fts ?? Array.Empty<byte>();
361 this.width = width;
362 this.height = height;
363 this.X = x / physX;
364 this.Y = y / physY;
365 }
366 else
367 {
368 maskBytes = CropByteMask(fts, width, height, out int cropWidth, out int cropHeight, out int startX, out int startY);
369 this.width = cropWidth;
370 this.height = cropHeight;
371 if (absolutePosition)
372 {
373 this.X = x / physX;
374 this.Y = y / physY;
375 }
376 else
377 {
378 this.X = (x / physX) + startX;
379 this.Y = (y / physY) + startY;
380 }
381 }
382 }

Member Function Documentation

◆ CropFullImageMask()

static float[] int int int int startY BioLib.ROI.Mask.CropFullImageMask ( float[] fullMask,
int imageWidth,
int imageHeight,
float threshold = 0::0f )
static
820 {
821 if (fullMask == null || fullMask.Length != imageWidth * imageHeight)
822 throw new ArgumentException("Invalid mask dimensions or null mask.");
823
824 // Initialize bounding box values
825 int minX = imageWidth, minY = imageHeight, maxX = -1, maxY = -1;
826
827 // Find the bounding box of "white" pixels
828 for (int y = 0; y < imageHeight; y++)
829 {
830 for (int x = 0; x < imageWidth; x++)
831 {
832 int index = y * imageWidth + x;
833 if (fullMask[index] > threshold) // Pixel exceeds threshold, considered "white"
834 {
835 minX = Math.Min(minX, x);
836 minY = Math.Min(minY, y);
837 maxX = Math.Max(maxX, x);
838 maxY = Math.Max(maxY, y);
839 }
840 }
841 }
842
843 // Handle cases where no white pixels are found
844 if (minX > maxX || minY > maxY)
845 return (Array.Empty<float>(), 0, 0, 0, 0); // Return an empty mask
846
847 // Calculate the cropped region dimensions
848 int cropWidth = maxX - minX + 1;
849 int cropHeight = maxY - minY + 1;
850
851 // Extract the cropped region
852 float[] croppedMask = new float[cropWidth * cropHeight];
853 for (int y = 0; y < cropHeight; y++)
854 {
855 for (int x = 0; x < cropWidth; x++)
856 {
857 int sourceIndex = (minY + y) * imageWidth + (minX + x);
858 int targetIndex = y * cropWidth + x;
859
860 croppedMask[targetIndex] = fullMask[sourceIndex];
861 }
862 }
863
864 return (croppedMask, cropWidth, cropHeight, minX, minY);
865 }
static float[] croppedMask
Crops the smallest rectangular region containing all "white" pixels (values above a threshold) from a...
Definition ROI.cs:818

◆ Dispose()

void BioLib.ROI.Mask.Dispose ( )
868 {
869 if (pixbuf != null)
870 pixbuf.Dispose();
871 if (colored != null)
872 colored.Dispose();
873 mask = null;
874 maskBytes = null;
875 }

◆ GetBytes()

byte[] BioLib.ROI.Mask.GetBytes ( )
648 {
649 if (maskBytes != null)
650 return (byte[])maskBytes.Clone();
651
652 if (mask == null)
653 return Array.Empty<byte>();
654
655 return ConvertFloatMaskToBytes(mask);
656 }

◆ GetBytesCropped() [1/3]

byte[] BioLib.ROI.Mask.GetBytesCropped ( )
552 {
553 return GetBytesCropped(out _, out _, out _, out _);
554 }
byte[] GetBytesCropped()
Definition ROI.cs:551

◆ GetBytesCropped() [2/3]

byte[] BioLib.ROI.Mask.GetBytesCropped ( int imageWidth,
int imageHeight,
out int cropWidth,
out int cropHeight,
out int startX,
out int startY )
557 {
558 if (maskBytes != null)
559 {
560 // If this mask buffer still represents a full-size image mask,
561 // crop it down before serializing so the payload stays compact
562 // and the ROI position is preserved by the saved metadata.
563 if (imageWidth > 0 && imageHeight > 0 && maskBytes.Length == imageWidth * imageHeight && width == imageWidth && height == imageHeight)
564 return CropByteMask(maskBytes, imageWidth, imageHeight, out cropWidth, out cropHeight, out startX, out startY);
565
566 cropWidth = this.Width;
567 cropHeight = this.Height;
568 startX = 0;
569 startY = 0;
570 return (byte[])maskBytes.Clone();
571 }
572
573 return GetBytesCropped(out cropWidth, out cropHeight, out startX, out startY);
574 }
int Width
Definition ROI.cs:225
int Height
Definition ROI.cs:226

◆ GetBytesCropped() [3/3]

byte[] BioLib.ROI.Mask.GetBytesCropped ( out int cropWidth,
out int cropHeight,
out int startX,
out int startY )
577 {
578 if (maskBytes != null)
579 {
580 cropWidth = this.Width;
581 cropHeight = this.Height;
582 startX = 0;
583 startY = 0;
584 return (byte[])maskBytes.Clone();
585 }
586
587 if (mask == null)
588 {
589 cropWidth = width;
590 cropHeight = height;
591 startX = (int)Math.Round(X);
592 startY = (int)Math.Round(Y);
593 return Array.Empty<byte>();
594 }
595
596 // Crop the mask using a threshold of 0
597 var floatCropResult = CropFullImageMask(mask, this.Width, this.Height, 0.0f);
598 float[] croppedMask = floatCropResult.croppedMask;
599
600 cropWidth = floatCropResult.cropWidth;
601 cropHeight = floatCropResult.cropHeight;
602 startX = floatCropResult.startX;
603 startY = floatCropResult.startY;
604
605 // Handle empty mask case
606 if (croppedMask == null || croppedMask.Length == 0)
607 return Array.Empty<byte>();
608
609 // Get the minimum and maximum values of the mask for normalization
610 var (min, max) = GetMinAndMax(croppedMask);
611 min = 0;
612 // Prepare the byte array for the normalized output
613 byte[] bytes = new byte[cropWidth * cropHeight];
614
615 // If the crop is a binary mask (all positive values identical),
616 // preserve the mask instead of collapsing it to an empty output.
617 if (Math.Abs(max - min) < float.Epsilon)
618 {
619 for (int y = 0; y < cropHeight; y++)
620 {
621 for (int x = 0; x < cropWidth; x++)
622 {
623 int index = y * cropWidth + x;
624 if (croppedMask[index] > 0)
625 bytes[index] = 255;
626 }
627 }
628 return bytes;
629 }
630
631 // Normalize float values and convert to byte
632 for (int y = 0; y < cropHeight; y++)
633 {
634 for (int x = 0; x < cropWidth; x++)
635 {
636 int index = y * cropWidth + x; // 1D index for the mask
637 if (croppedMask[index] > 0)
638 {
639 // Normalize the value: (value - min) / (max - min) * 255
640 float normalized = (croppedMask[index] - min) / (max - min);
641 bytes[index] = (byte)(normalized * 255);
642 }
643 }
644 }
645 return bytes;
646 }
float min
Definition ROI.cs:218
static float float max GetMinAndMax(float[] floatArray)
Definition ROI.cs:529

◆ GetBytesLegacy()

byte[] BioLib.ROI.Mask.GetBytesLegacy ( )
734 {
735 byte[] rgbaBytes = new byte[width * height];
736 for (int y = 0; y < Height; y++)
737 {
738 for (int x = 0; x < Width; x++)
739 {
740 int index = y * Width + x; // 1D index for the mask
741 // Set RGBA channels
742 rgbaBytes[index] = (byte)GetMaskValue(index);
743 }
744 }
745 return rgbaBytes;
746 }

◆ GetColored()

Gdk.Pixbuf BioLib.ROI.Mask.GetColored ( AForge.Color col,
byte alpha,
bool forceUpdate = false )
452 {
453 if (updateColored || forceUpdate)
454 {
455 UpdateColored(col, alpha);
456 return colored;
457 }
458 else
459 return colored;
460 }

◆ GetColoredBytes()

byte[] BioLib.ROI.Mask.GetColoredBytes ( AForge.Color col)
463 {
464 byte[] pixelData = new byte[width * height];
465 byte[] values = GetBytes();
466 for (int y = 0; y < height; y++)
467 {
468 for (int x = 0; x < width; x++)
469 {
470 int ind = y * width + x;
471
472 if (ind < values.Length)
473 {
474 float value = values[ind];
475 if (value > 0)
476 {
477 pixelData[ind] = values[ind];
478 }
479 }
480 }
481 }
482 return pixelData;
483 }
byte[] GetBytes()
Definition ROI.cs:647

◆ GetFullImageBytes()

byte[] BioLib.ROI.Mask.GetFullImageBytes ( int fullWidth,
int fullHeight )
749 {
750 byte[] cropped = GetBytes();
751 if (cropped == null || cropped.Length == 0 || fullWidth <= 0 || fullHeight <= 0)
752 return Array.Empty<byte>();
753
754 int cropWidth = Width;
755 int cropHeight = Height;
756 if (cropWidth <= 0 || cropHeight <= 0)
757 return Array.Empty<byte>();
758
759 if (cropped.Length == (long)fullWidth * fullHeight &&
760 (int)Math.Round(X) == 0 &&
761 (int)Math.Round(Y) == 0 &&
762 cropWidth == fullWidth &&
763 cropHeight == fullHeight)
764 {
765 return cropped;
766 }
767
768 byte[] full = new byte[fullWidth * fullHeight];
769 int offsetX = (int)Math.Round(X);
770 int offsetY = (int)Math.Round(Y);
771
772 for (int row = 0; row < cropHeight; row++)
773 {
774 int destY = offsetY + row;
775 if (destY < 0 || destY >= fullHeight)
776 continue;
777
778 int sourceIndex = row * cropWidth;
779 int destX = offsetX;
780 int copyWidth = cropWidth;
781
782 if (destX < 0)
783 {
784 sourceIndex -= destX;
785 copyWidth += destX;
786 destX = 0;
787 }
788
789 if (destX >= fullWidth || copyWidth <= 0)
790 continue;
791
792 if (destX + copyWidth > fullWidth)
793 copyWidth = fullWidth - destX;
794
795 if (sourceIndex < 0 || sourceIndex + copyWidth > cropped.Length)
796 continue;
797
798 Buffer.BlockCopy(cropped, sourceIndex, full, destY * fullWidth + destX, copyWidth);
799 }
800
801 return full;
802 }

◆ GetMinAndMax()

static float float max BioLib.ROI.Mask.GetMinAndMax ( float[] floatArray)
static
530 {
531 if (floatArray == null || floatArray.Length == 0)
532 throw new ArgumentException("Input array must not be null or empty.");
533
534 float min = floatArray[0];
535 float max = floatArray[0];
536
537 foreach (float value in floatArray)
538 {
539 if (value < min)
540 {
541 min = value;
542 }
543 if (value > max)
544 {
545 max = value;
546 }
547 }
548
549 return (min, max);
550 }

◆ GetValue()

float BioLib.ROI.Mask.GetValue ( int x,
int y )
313 {
314 int ind = y * width + x;
315 if (ind > MaskLength)
316 throw new ArgumentException("Point " + x + "," + y + " is outside the mask.");
317 return GetMaskValue(ind);
318 }

◆ IsSelected()

bool BioLib.ROI.Mask.IsSelected ( int x,
int y )
302 {
303 int ind = y * width + x;
304 if (ind >= MaskLength)
305 return false;
306 if (GetMaskValue(ind) > min)
307 {
308 return true;
309 }
310 return false;
311 }

◆ OutputAs8BitImage()

static byte[] int int int int startY BioLib.ROI.Mask.OutputAs8BitImage ( float[] fullMask,
int imageWidth,
int imageHeight,
float threshold = 0::0f )
static
500 {
501 if (fullMask == null || fullMask.Length != imageWidth * imageHeight)
502 throw new ArgumentException("Invalid mask dimensions or null mask.");
503
504 // Crop the mask using the threshold
505 var cropResult = CropFullImageMask(fullMask, imageWidth, imageHeight, threshold);
506 float[] croppedMask = cropResult.croppedMask;
507
508 // Handle empty crop
509 if (croppedMask == null || croppedMask.Length == 0)
510 return (Array.Empty<byte>(), 0, 0, 0, 0);
511
512 int cropWidth = cropResult.cropWidth;
513 int cropHeight = cropResult.cropHeight;
514
515 // Normalize and convert to 8-bit grayscale
516 byte[] grayImage = new byte[cropWidth * cropHeight];
517 for (int i = 0; i < croppedMask.Length; i++)
518 {
519 grayImage[i] = (byte)(Math.Clamp(croppedMask[i], 0.0f, 1.0f) * 255);
520 }
521
522 return (grayImage, cropWidth, cropHeight, cropResult.startX, cropResult.startY);
523 }
static byte[] grayImage
Crops a mask based on non-zero values and converts it to an 8-bit grayscale image.
Definition ROI.cs:498

◆ SetValue()

void BioLib.ROI.Mask.SetValue ( int x,
int y,
float val )
320 {
321 int ind = y * width + x;
322 if (ind > MaskLength)
323 throw new ArgumentException("Point " + x + "," + y + " is outside the mask.");
324 SetMaskValue(ind, val);
325 updatePixbuf = true;
326 updateColored = true;
327 }

Member Data Documentation

◆ cropHeight [1/2]

byte [] int int BioLib.ROI.Mask.cropHeight
static

◆ cropHeight [2/2]

float [] int int BioLib.ROI.Mask.cropHeight
static

◆ croppedMask

float [] BioLib.ROI.Mask.croppedMask
static

Crops the smallest rectangular region containing all "white" pixels (values above a threshold) from a full image mask.

Parameters
fullMaskThe input float array representing the entire image mask.
imageWidthThe width of the full image.
imageHeightThe height of the full image.
thresholdThe threshold to consider a pixel as "white".
Returns
A tuple containing:
  • Cropped float array mask.
  • Crop width.
  • Crop height.
  • Starting X and Y coordinates of the crop in the original image.

◆ cropWidth [1/2]

byte [] int BioLib.ROI.Mask.cropWidth
static

◆ cropWidth [2/2]

float [] int BioLib.ROI.Mask.cropWidth
static

◆ grayImage

byte [] BioLib.ROI.Mask.grayImage
static

Crops a mask based on non-zero values and converts it to an 8-bit grayscale image.

Parameters
fullMaskThe input float array representing the full image mask.
imageWidthThe width of the full image.
imageHeightThe height of the full image.
thresholdThe threshold to consider a pixel as part of the crop.
Returns
A tuple containing:
  • 8-bit grayscale byte array.
  • Width and height of the cropped region.
  • Starting X and Y coordinates of the crop in the original image.

◆ min [1/2]

float BioLib.ROI.Mask.min = 0

◆ min [2/2]

float BioLib.ROI.Mask.min
static

Gets the minimum and maximum values from a float array.

Parameters
floatArrayThe input float array.
Returns
A tuple containing the minimum and maximum values.

◆ startX [1/2]

byte [] int int int BioLib.ROI.Mask.startX
static

◆ startX [2/2]

float [] int int int BioLib.ROI.Mask.startX
static

Property Documentation

◆ Height

int BioLib.ROI.Mask.Height
getset
226{ get { return height; } set { height = value; } }

◆ PhysicalSizeX

double BioLib.ROI.Mask.PhysicalSizeX
getset
227{ get; set; }

◆ PhysicalSizeY

double BioLib.ROI.Mask.PhysicalSizeY
getset
228{ get; set; }

◆ Pixbuf

Gdk.Pixbuf BioLib.ROI.Mask.Pixbuf
get
384 {
385 get
386 {
387 if (updatePixbuf)
388 {
389 if (pixbuf != null)
390 pixbuf.Dispose();
391 byte[] pixelData = new byte[width * height * 4];
392 byte[] values = GetBytes();
393 for (int y = 0; y < height; y++)
394 {
395 for (int x = 0; x < width; x++)
396 {
397 int ind = y * width + x;
398 if (ind < values.Length && values[ind] > 0)
399 {
400 pixelData[4 * ind] = values[ind];// Blue
401 pixelData[4 * ind + 1] = values[ind];// Green
402 pixelData[4 * ind + 2] = values[ind];// Red
403 pixelData[4 * ind + 3] = 125;// Alpha
404 }
405 else
406 pixelData[4 * ind + 3] = 0;
407 }
408 }
409 pixbuf = new Gdk.Pixbuf(pixelData, true, 8, width, height, width * 4);
410 updatePixbuf = false;
411 return pixbuf;
412 }
413 else
414 return pixbuf;
415 }
416 }

◆ Width

int BioLib.ROI.Mask.Width
getset
225{ get { return width; } set { width = value; } }

◆ X

double BioLib.ROI.Mask.X
getset
223{ get; set; }

◆ Y

double BioLib.ROI.Mask.Y
getset
224{ get; set; }

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