BioLib  4.1.1
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 )
330 {
331 this.width = width;
332 this.height = height;
333 X = x; Y = y;
334 PhysicalSizeX = physX;
335 PhysicalSizeY = physY;
336 if (useFloatStorage)
337 {
338 var cropResult = CropFullImageMask(fts, width, height, 0.0f);
339 mask = cropResult.croppedMask;
340 X = cropResult.startX;
341 Y = cropResult.startY;
342 this.width = cropResult.cropWidth;
343 this.height = cropResult.cropHeight;
344 }
345 else
346 {
347 byte[] bt = ConvertFloatMaskToBytesCropped(fts, width, height, out int cropWidth, out int cropHeight, out int startX, out int startY);
348 maskBytes = bt;
349 X = absolutePosition ? (x / physX) : startX;
350 Y = absolutePosition ? (y / physY) : startY;
351 this.width = cropWidth;
352 this.height = cropHeight;
353 }
354 }

◆ 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 )
356 {
357 PhysicalSizeX = physX;
358 PhysicalSizeY = physY;
359 if (preserveDimensions)
360 {
361 maskBytes = fts ?? Array.Empty<byte>();
362 this.width = width;
363 this.height = height;
364 this.X = x / physX;
365 this.Y = y / physY;
366 }
367 else
368 {
369 maskBytes = CropByteMask(fts, width, height, out int cropWidth, out int cropHeight, out int startX, out int startY);
370 this.width = cropWidth;
371 this.height = cropHeight;
372 if (absolutePosition)
373 {
374 this.X = x / physX;
375 this.Y = y / physY;
376 }
377 else
378 {
379 this.X = (x / physX) + startX;
380 this.Y = (y / physY) + startY;
381 }
382 }
383 }

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

◆ Dispose()

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

◆ GetBytes()

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

◆ GetBytesCropped() [1/3]

byte[] BioLib.ROI.Mask.GetBytesCropped ( )
553 {
554 return GetBytesCropped(out _, out _, out _, out _);
555 }

◆ GetBytesCropped() [2/3]

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

◆ GetBytesCropped() [3/3]

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

◆ GetBytesLegacy()

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

◆ GetColored()

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

◆ GetColoredBytes()

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

◆ GetFullImageBytes()

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

◆ GetMinAndMax()

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

◆ GetValue()

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

◆ IsSelected()

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

◆ OutputAs8BitImage()

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

◆ SetValue()

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

Member Data Documentation

◆ 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.

◆ 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

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.

Property Documentation

◆ Height

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

◆ PhysicalSizeX

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

◆ PhysicalSizeY

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

◆ Pixbuf

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

◆ Width

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

◆ X

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

◆ Y

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

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