cellprofiler-library-nightly 5.0.0.dev328__py3-none-any.whl → 5.0.0.dev336__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cellprofiler_library/_version.py +2 -2
- cellprofiler_library/functions/image_processing.py +206 -2
- cellprofiler_library/functions/object_processing.py +99 -2
- cellprofiler_library/modules/_enhanceorsuppressfeatures.py +55 -0
- cellprofiler_library/modules/_erodeobjects.py +50 -0
- cellprofiler_library/opts/enhanceorsuppressfeatures.py +21 -0
- cellprofiler_library/opts/erodeobjects.py +15 -0
- {cellprofiler_library_nightly-5.0.0.dev328.dist-info → cellprofiler_library_nightly-5.0.0.dev336.dist-info}/METADATA +1 -1
- {cellprofiler_library_nightly-5.0.0.dev328.dist-info → cellprofiler_library_nightly-5.0.0.dev336.dist-info}/RECORD +12 -8
- {cellprofiler_library_nightly-5.0.0.dev328.dist-info → cellprofiler_library_nightly-5.0.0.dev336.dist-info}/WHEEL +0 -0
- {cellprofiler_library_nightly-5.0.0.dev328.dist-info → cellprofiler_library_nightly-5.0.0.dev336.dist-info}/licenses/LICENSE +0 -0
- {cellprofiler_library_nightly-5.0.0.dev328.dist-info → cellprofiler_library_nightly-5.0.0.dev336.dist-info}/top_level.txt +0 -0
cellprofiler_library/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '5.0.0.
|
|
32
|
-
__version_tuple__ = version_tuple = (5, 0, 0, '
|
|
31
|
+
__version__ = version = '5.0.0.dev336'
|
|
32
|
+
__version_tuple__ = version_tuple = (5, 0, 0, 'dev336')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -6,12 +6,17 @@ import centrosome.threshold
|
|
|
6
6
|
import scipy
|
|
7
7
|
import matplotlib
|
|
8
8
|
import math
|
|
9
|
-
from typing import
|
|
10
|
-
|
|
9
|
+
from numpy.typing import NDArray
|
|
10
|
+
import centrosome.filter
|
|
11
|
+
from typing import Any, Optional, Tuple, Callable, Union, List, TypeVar
|
|
12
|
+
from cellprofiler_library.types import ImageGrayscale, ImageGrayscaleMask, Image2DColor, Image2DGrayscale, ImageAny, ImageAnyMask, ObjectSegmentation, Image2D, Image2DMask, StructuringElement
|
|
11
13
|
from cellprofiler_library.opts import threshold as Threshold
|
|
14
|
+
from cellprofiler_library.opts.enhanceorsuppressfeatures import SpeckleAccuracy, NeuriteMethod
|
|
12
15
|
from cellprofiler_library.opts.crop import RemovalMethod
|
|
13
16
|
from cellprofiler_library.opts.structuring_elements import StructuringElementShape2D, StructuringElementShape3D
|
|
14
17
|
|
|
18
|
+
T = TypeVar("T", bound=ImageAny)
|
|
19
|
+
|
|
15
20
|
def rgb_to_greyscale(image):
|
|
16
21
|
if image.shape[-1] == 4:
|
|
17
22
|
output = skimage.color.rgba2rgb(image)
|
|
@@ -924,3 +929,202 @@ def erase_pixels(
|
|
|
924
929
|
else:
|
|
925
930
|
cropped_pixel_data[~crop] = 0
|
|
926
931
|
return cropped_pixel_data
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
###############################################################################
|
|
935
|
+
# EnhanceOrSuppressFeatures
|
|
936
|
+
###############################################################################
|
|
937
|
+
|
|
938
|
+
def __mask(
|
|
939
|
+
pixel_data: T,
|
|
940
|
+
mask: ImageAnyMask,
|
|
941
|
+
) -> T:
|
|
942
|
+
data = numpy.zeros_like(pixel_data)
|
|
943
|
+
data[mask] = pixel_data[mask]
|
|
944
|
+
return data
|
|
945
|
+
|
|
946
|
+
def __unmask(
|
|
947
|
+
data: T,
|
|
948
|
+
pixel_data: T,
|
|
949
|
+
mask: ImageAnyMask,
|
|
950
|
+
) -> T:
|
|
951
|
+
data[~mask] = pixel_data[~mask]
|
|
952
|
+
return data
|
|
953
|
+
|
|
954
|
+
def __structuring_element(
|
|
955
|
+
radius,
|
|
956
|
+
volumetric
|
|
957
|
+
) -> NDArray[numpy.uint8]:
|
|
958
|
+
if volumetric:
|
|
959
|
+
return skimage.morphology.ball(radius)
|
|
960
|
+
|
|
961
|
+
return skimage.morphology.disk(radius)
|
|
962
|
+
|
|
963
|
+
|
|
964
|
+
def enhance_speckles(
|
|
965
|
+
im_pixel_data: ImageGrayscale,
|
|
966
|
+
im_mask: ImageGrayscaleMask,
|
|
967
|
+
im_volumetric: bool,
|
|
968
|
+
radius: float,
|
|
969
|
+
accuracy: SpeckleAccuracy,
|
|
970
|
+
) -> ImageGrayscale:
|
|
971
|
+
data = __mask(im_pixel_data, im_mask)
|
|
972
|
+
footprint = __structuring_element(radius, im_volumetric)
|
|
973
|
+
|
|
974
|
+
if accuracy == SpeckleAccuracy.SLOW or radius <= 3:
|
|
975
|
+
result = skimage.morphology.white_tophat(data, footprint=footprint)
|
|
976
|
+
else:
|
|
977
|
+
#
|
|
978
|
+
# white_tophat = img - opening
|
|
979
|
+
# = img - dilate(erode)
|
|
980
|
+
# = img - maximum_filter(minimum_filter)
|
|
981
|
+
#
|
|
982
|
+
minimum = scipy.ndimage.filters.minimum_filter(data, footprint=footprint)
|
|
983
|
+
maximum = scipy.ndimage.filters.maximum_filter(minimum, footprint=footprint)
|
|
984
|
+
result = data - maximum
|
|
985
|
+
|
|
986
|
+
return __unmask(result, im_pixel_data, im_mask)
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
def enhance_neurites(
|
|
990
|
+
im_pixel_data: ImageGrayscale,
|
|
991
|
+
im_mask: ImageGrayscaleMask,
|
|
992
|
+
im_volumetric: bool,
|
|
993
|
+
im_spacing: Tuple[float, ...],
|
|
994
|
+
smoothing_value: float,
|
|
995
|
+
radius: float,
|
|
996
|
+
method: NeuriteMethod,
|
|
997
|
+
neurite_rescale: bool,
|
|
998
|
+
) -> ImageGrayscale:
|
|
999
|
+
data = __mask(im_pixel_data, im_mask)
|
|
1000
|
+
|
|
1001
|
+
if method == NeuriteMethod.GRADIENT:
|
|
1002
|
+
# desired effect = img + white_tophat - black_tophat
|
|
1003
|
+
footprint = __structuring_element(radius, im_volumetric)
|
|
1004
|
+
white = skimage.morphology.white_tophat(data, footprint=footprint)
|
|
1005
|
+
black = skimage.morphology.black_tophat(data, footprint=footprint)
|
|
1006
|
+
result = data + white - black
|
|
1007
|
+
result[result > 1] = 1
|
|
1008
|
+
result[result < 0] = 0
|
|
1009
|
+
else:
|
|
1010
|
+
sigma = smoothing_value
|
|
1011
|
+
smoothed = scipy.ndimage.gaussian_filter(data, numpy.divide(sigma, im_spacing))
|
|
1012
|
+
|
|
1013
|
+
if im_volumetric:
|
|
1014
|
+
result = numpy.zeros_like(smoothed)
|
|
1015
|
+
for index, plane in enumerate(smoothed):
|
|
1016
|
+
hessian = centrosome.filter.hessian(plane, return_hessian=False, return_eigenvectors=False)
|
|
1017
|
+
result[index] = (-hessian[:, :, 0] * (hessian[:, :, 0] < 0) * (sigma ** 2))
|
|
1018
|
+
else:
|
|
1019
|
+
hessian = centrosome.filter.hessian(smoothed, return_hessian=False, return_eigenvectors=False)
|
|
1020
|
+
#
|
|
1021
|
+
# The positive values are darker pixels with lighter
|
|
1022
|
+
# neighbors. The original ImageJ code scales the result
|
|
1023
|
+
# by sigma squared - I have a feeling this might be
|
|
1024
|
+
# a first-order correction for e**(-2*sigma), possibly
|
|
1025
|
+
# because the hessian is taken from one pixel away
|
|
1026
|
+
# and the gradient is less as sigma gets larger.
|
|
1027
|
+
#
|
|
1028
|
+
result = -hessian[:, :, 0] * (hessian[:, :, 0] < 0) * (sigma ** 2)
|
|
1029
|
+
|
|
1030
|
+
result = __unmask(result, im_pixel_data, im_mask)
|
|
1031
|
+
if neurite_rescale:
|
|
1032
|
+
result = skimage.exposure.rescale_intensity(result)
|
|
1033
|
+
return result
|
|
1034
|
+
|
|
1035
|
+
|
|
1036
|
+
def enhance_circles(
|
|
1037
|
+
im_pixel_data: ImageGrayscale,
|
|
1038
|
+
im_mask: ImageGrayscaleMask,
|
|
1039
|
+
im_volumetric: bool,
|
|
1040
|
+
radius: float,
|
|
1041
|
+
) -> ImageGrayscale:
|
|
1042
|
+
data = __mask(im_pixel_data, im_mask)
|
|
1043
|
+
if im_volumetric:
|
|
1044
|
+
result = numpy.zeros_like(data)
|
|
1045
|
+
for index, plane in enumerate(data):
|
|
1046
|
+
result[index] = skimage.transform.hough_circle(plane, radius)[0]
|
|
1047
|
+
else:
|
|
1048
|
+
result = skimage.transform.hough_circle(data, radius)[0]
|
|
1049
|
+
return __unmask(result, im_pixel_data, im_mask)
|
|
1050
|
+
|
|
1051
|
+
|
|
1052
|
+
def enhance_texture(
|
|
1053
|
+
im_pixel_data: ImageGrayscale,
|
|
1054
|
+
im_mask: ImageGrayscaleMask,
|
|
1055
|
+
sigma: float,
|
|
1056
|
+
) -> ImageGrayscale:
|
|
1057
|
+
mask = im_mask
|
|
1058
|
+
data = __mask(im_pixel_data, mask)
|
|
1059
|
+
gmask = skimage.filters.gaussian(mask.astype(float), sigma, mode="constant")
|
|
1060
|
+
img_mean = (skimage.filters.gaussian(data, sigma, mode="constant") / gmask)
|
|
1061
|
+
img_squared = (skimage.filters.gaussian(data ** 2, sigma, mode="constant")/ gmask)
|
|
1062
|
+
result = img_squared - img_mean ** 2
|
|
1063
|
+
return __unmask(result, im_pixel_data, mask)
|
|
1064
|
+
|
|
1065
|
+
|
|
1066
|
+
def enhance_dark_holes(
|
|
1067
|
+
im_pixel_data: ImageGrayscale,
|
|
1068
|
+
im_mask: ImageGrayscaleMask,
|
|
1069
|
+
im_volumetric: bool,
|
|
1070
|
+
dark_hole_radius_min: int,
|
|
1071
|
+
dark_hole_radius_max: int,
|
|
1072
|
+
min_radius: Optional[int] = None,
|
|
1073
|
+
max_radius: Optional[int] = None,
|
|
1074
|
+
) -> ImageGrayscale:
|
|
1075
|
+
if min_radius is None:
|
|
1076
|
+
min_radius = max(1, int(dark_hole_radius_min / 2))
|
|
1077
|
+
if max_radius is None:
|
|
1078
|
+
max_radius = int((dark_hole_radius_max + 1) / 2)
|
|
1079
|
+
|
|
1080
|
+
pixel_data = im_pixel_data
|
|
1081
|
+
mask = im_mask
|
|
1082
|
+
se = __structuring_element(1, im_volumetric)
|
|
1083
|
+
inverted_image = pixel_data.max() - pixel_data
|
|
1084
|
+
previous_reconstructed_image = inverted_image
|
|
1085
|
+
eroded_image = inverted_image
|
|
1086
|
+
smoothed_image = numpy.zeros(pixel_data.shape)
|
|
1087
|
+
|
|
1088
|
+
for i in range(max_radius + 1):
|
|
1089
|
+
eroded_image = skimage.morphology.erosion(eroded_image, se)
|
|
1090
|
+
if mask is not None:
|
|
1091
|
+
eroded_image *= mask
|
|
1092
|
+
reconstructed_image = skimage.morphology.reconstruction(eroded_image, inverted_image, "dilation", se)
|
|
1093
|
+
output_image = previous_reconstructed_image - reconstructed_image
|
|
1094
|
+
if i >= min_radius:
|
|
1095
|
+
smoothed_image = numpy.maximum(smoothed_image, output_image)
|
|
1096
|
+
previous_reconstructed_image = reconstructed_image
|
|
1097
|
+
return smoothed_image
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
def enhance_dic(
|
|
1101
|
+
im_pixel_data: ImageGrayscale,
|
|
1102
|
+
im_volumetric: bool,
|
|
1103
|
+
angle: float,
|
|
1104
|
+
decay: float,
|
|
1105
|
+
smoothing: float,
|
|
1106
|
+
) -> ImageGrayscale:
|
|
1107
|
+
pixel_data = im_pixel_data
|
|
1108
|
+
|
|
1109
|
+
if im_volumetric:
|
|
1110
|
+
result = numpy.zeros_like(pixel_data).astype(numpy.float64)
|
|
1111
|
+
for index, plane in enumerate(pixel_data):
|
|
1112
|
+
result[index] = centrosome.filter.line_integration(plane, angle, decay, smoothing)
|
|
1113
|
+
return result
|
|
1114
|
+
|
|
1115
|
+
if smoothing == 0:
|
|
1116
|
+
smoothing = float(numpy.finfo(float).eps)
|
|
1117
|
+
|
|
1118
|
+
return centrosome.filter.line_integration(pixel_data, angle, decay, smoothing)
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
def suppress(
|
|
1122
|
+
im_pixel_data: ImageGrayscale,
|
|
1123
|
+
im_mask: ImageGrayscaleMask,
|
|
1124
|
+
im_volumetric: bool,
|
|
1125
|
+
radius: float,
|
|
1126
|
+
) -> ImageGrayscale:
|
|
1127
|
+
data = __mask(im_pixel_data, im_mask)
|
|
1128
|
+
footprint = __structuring_element(radius, im_volumetric)
|
|
1129
|
+
result = skimage.morphology.opening(data, footprint)
|
|
1130
|
+
return __unmask(result, im_pixel_data, im_mask)
|
|
@@ -3,12 +3,12 @@ import centrosome.cpmorphology
|
|
|
3
3
|
import numpy
|
|
4
4
|
import scipy.ndimage
|
|
5
5
|
import skimage.morphology
|
|
6
|
+
import cellprofiler.utilities.morphology
|
|
6
7
|
import mahotas
|
|
7
8
|
import matplotlib.cm
|
|
8
9
|
from numpy.typing import NDArray
|
|
9
10
|
from typing import Optional, Literal, Tuple
|
|
10
|
-
from cellprofiler_library.types import
|
|
11
|
-
|
|
11
|
+
from cellprofiler_library.types import ImageAnyMask, ObjectLabel, ImageColor, ImageGrayscale, ImageBinary, ObjectSegmentation, StructuringElement
|
|
12
12
|
|
|
13
13
|
def shrink_to_point(labels, fill):
|
|
14
14
|
"""
|
|
@@ -532,3 +532,100 @@ def image_mode_uint16(
|
|
|
532
532
|
alpha[mask] = 1
|
|
533
533
|
return pixel_data, alpha
|
|
534
534
|
|
|
535
|
+
|
|
536
|
+
################################################################################
|
|
537
|
+
# Morphological Operations Helpers
|
|
538
|
+
################################################################################
|
|
539
|
+
|
|
540
|
+
def morphological_gradient(x_data: ObjectSegmentation, structuring_element: StructuringElement) -> ObjectSegmentation:
|
|
541
|
+
is_strel_2d = structuring_element.ndim == 2
|
|
542
|
+
|
|
543
|
+
is_img_2d = x_data.ndim == 2
|
|
544
|
+
|
|
545
|
+
if is_strel_2d and not is_img_2d:
|
|
546
|
+
y_data = numpy.zeros_like(x_data)
|
|
547
|
+
|
|
548
|
+
for index, plane in enumerate(x_data):
|
|
549
|
+
y_data[index] = scipy.ndimage.morphological_gradient(
|
|
550
|
+
plane, footprint=structuring_element
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
return y_data
|
|
554
|
+
|
|
555
|
+
if not is_strel_2d and is_img_2d:
|
|
556
|
+
raise NotImplementedError(
|
|
557
|
+
"A 3D structuring element cannot be applied to a 2D image."
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
y_data = scipy.ndimage.morphological_gradient(x_data, footprint=structuring_element)
|
|
561
|
+
|
|
562
|
+
return y_data
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
################################################################################
|
|
566
|
+
# ErodeObjects
|
|
567
|
+
################################################################################
|
|
568
|
+
|
|
569
|
+
def erode_objects_with_structuring_element(
|
|
570
|
+
labels: ObjectSegmentation,
|
|
571
|
+
structuring_element: StructuringElement,
|
|
572
|
+
preserve_midpoints: bool = True,
|
|
573
|
+
relabel_objects: bool = False
|
|
574
|
+
) -> ObjectSegmentation:
|
|
575
|
+
"""Erode objects based on the structuring element provided.
|
|
576
|
+
|
|
577
|
+
This function is similar to the "Shrink" function of ExpandOrShrinkObjects,
|
|
578
|
+
with two major distinctions:
|
|
579
|
+
1. ErodeObjects supports 3D objects
|
|
580
|
+
2. An object smaller than the structuring element will be removed entirely
|
|
581
|
+
unless preserve_midpoints is enabled.
|
|
582
|
+
|
|
583
|
+
Args:
|
|
584
|
+
labels: Input labeled objects array
|
|
585
|
+
structuring_element: Structuring element for erosion operation
|
|
586
|
+
preserve_midpoints: If True, preserve central pixels to prevent object removal
|
|
587
|
+
relabel_objects: If True, assign new label numbers to resulting objects
|
|
588
|
+
|
|
589
|
+
Returns:
|
|
590
|
+
Eroded objects array with same dimensions as input
|
|
591
|
+
"""
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
# Calculate morphological gradient to identify object boundaries
|
|
595
|
+
contours = morphological_gradient(
|
|
596
|
+
labels, structuring_element
|
|
597
|
+
)
|
|
598
|
+
|
|
599
|
+
# Erode by removing pixels at object boundaries (where contours != 0)
|
|
600
|
+
y_data = labels * (contours == 0)
|
|
601
|
+
|
|
602
|
+
# Preserve midpoints if requested to prevent object removal
|
|
603
|
+
if preserve_midpoints:
|
|
604
|
+
missing_labels = numpy.setxor1d(labels, y_data)
|
|
605
|
+
|
|
606
|
+
# Check if structuring element is disk with size 1 (special case optimization)
|
|
607
|
+
# Check based on the actual array properties since we're dealing with numpy array
|
|
608
|
+
is_simple_disk = (
|
|
609
|
+
structuring_element.ndim == 2 and
|
|
610
|
+
structuring_element.shape == (3, 3) and
|
|
611
|
+
numpy.array_equal(structuring_element, skimage.morphology.disk(1))
|
|
612
|
+
)
|
|
613
|
+
|
|
614
|
+
if is_simple_disk:
|
|
615
|
+
# For simple disk,1 case, restore missing pixels directly
|
|
616
|
+
y_data += labels * numpy.isin(labels, missing_labels)
|
|
617
|
+
else:
|
|
618
|
+
# For other structuring elements, find and preserve the most central pixels
|
|
619
|
+
for label in missing_labels:
|
|
620
|
+
binary = labels == label
|
|
621
|
+
# Find pixels furthest from the object's edge using distance transform
|
|
622
|
+
midpoint = scipy.ndimage.morphology.distance_transform_edt(binary)
|
|
623
|
+
# Preserve pixels at maximum distance (most central)
|
|
624
|
+
y_data[midpoint == numpy.max(midpoint)] = label
|
|
625
|
+
|
|
626
|
+
# Relabel objects if requested
|
|
627
|
+
if relabel_objects:
|
|
628
|
+
y_data = skimage.morphology.label(y_data)
|
|
629
|
+
|
|
630
|
+
return y_data
|
|
631
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from cellprofiler_library.functions.image_processing import enhance_speckles, enhance_neurites, enhance_circles, enhance_texture, enhance_dark_holes, enhance_dic, suppress
|
|
2
|
+
from pydantic import Field, ConfigDict, validate_call
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
from cellprofiler_library.types import ImageGrayscale, ImageGrayscaleMask
|
|
5
|
+
from ..opts.enhanceorsuppressfeatures import OperationMethod, EnhanceMethod, SpeckleAccuracy, NeuriteMethod
|
|
6
|
+
|
|
7
|
+
@validate_call(config=ConfigDict(arbitrary_types_allowed=True))
|
|
8
|
+
def enhance_or_suppress_features(
|
|
9
|
+
im_pixel_data: Annotated[ImageGrayscale, Field(description="Image pixel data")],
|
|
10
|
+
im_mask: Annotated[ImageGrayscaleMask, Field(description="Image mask")],
|
|
11
|
+
im_volumetric: Annotated[bool, Field(description="Image is volumetric")] = False,
|
|
12
|
+
im_spacing: Annotated[tuple[float, ...], Field(description="Image spacing")] = (1.0, 1.0, 1.0),
|
|
13
|
+
radius: Annotated[float, Field(description="Feature size")] = 10,
|
|
14
|
+
method: Annotated[OperationMethod, Field(description="Operation method")] = OperationMethod.ENHANCE,
|
|
15
|
+
enhance_method: Annotated[EnhanceMethod, Field(description="Feature type")] = EnhanceMethod.SPECKLES,
|
|
16
|
+
speckle_accuracy: Annotated[SpeckleAccuracy, Field(description="Speed and accuracy")] = SpeckleAccuracy.FAST,
|
|
17
|
+
neurite_choice: Annotated[NeuriteMethod, Field(description="Neurite choice")] = NeuriteMethod.GRADIENT,
|
|
18
|
+
neurite_rescale: Annotated[bool, Field(description="Rescale result image")] = False,
|
|
19
|
+
dark_hole_radius_min: Annotated[int, Field(description="Dark hole radius min")] = 1,
|
|
20
|
+
dark_hole_radius_max: Annotated[int, Field(description="Dark hole radius max")] = 10,
|
|
21
|
+
smoothing_value: Annotated[float, Field(description="Smoothing value")] = 2.0,
|
|
22
|
+
dic_angle: Annotated[float, Field(description="Angle")] = 0.0,
|
|
23
|
+
dic_decay: Annotated[float, Field(description="Decay")] = 0.95,
|
|
24
|
+
) -> ImageGrayscale:
|
|
25
|
+
if method == OperationMethod.ENHANCE:
|
|
26
|
+
if enhance_method == EnhanceMethod.SPECKLES:
|
|
27
|
+
result = enhance_speckles(im_pixel_data, im_mask, im_volumetric, radius, speckle_accuracy)
|
|
28
|
+
|
|
29
|
+
elif enhance_method == EnhanceMethod.NEURITES:
|
|
30
|
+
result = enhance_neurites(im_pixel_data, im_mask, im_volumetric, im_spacing, smoothing_value, radius, neurite_choice, neurite_rescale)
|
|
31
|
+
|
|
32
|
+
elif enhance_method == EnhanceMethod.DARK_HOLES:
|
|
33
|
+
result = enhance_dark_holes(im_pixel_data, im_mask, im_volumetric, dark_hole_radius_min, dark_hole_radius_max)
|
|
34
|
+
|
|
35
|
+
elif enhance_method == EnhanceMethod.CIRCLES:
|
|
36
|
+
result = enhance_circles(im_pixel_data, im_mask, im_volumetric, radius)
|
|
37
|
+
|
|
38
|
+
elif enhance_method == EnhanceMethod.TEXTURE:
|
|
39
|
+
result = enhance_texture(im_pixel_data, im_mask, smoothing_value)
|
|
40
|
+
|
|
41
|
+
elif enhance_method == EnhanceMethod.DIC:
|
|
42
|
+
result = enhance_dic(im_pixel_data, im_volumetric, dic_angle, dic_decay, smoothing_value)
|
|
43
|
+
|
|
44
|
+
else:
|
|
45
|
+
raise NotImplementedError("Unimplemented enhance method: %s" % enhance_method)
|
|
46
|
+
|
|
47
|
+
elif method == OperationMethod.SUPPRESS:
|
|
48
|
+
result = suppress(im_pixel_data, im_mask, im_volumetric, radius)
|
|
49
|
+
|
|
50
|
+
else:
|
|
51
|
+
raise ValueError("Unknown filtering method: %s" % method)
|
|
52
|
+
|
|
53
|
+
return result
|
|
54
|
+
|
|
55
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
ErodeObjects module for the CellProfiler library.
|
|
5
|
+
|
|
6
|
+
This module contains the core algorithms for object erosion operations.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from pydantic import validate_call, ConfigDict, Field
|
|
10
|
+
from typing import Union, Tuple, Annotated
|
|
11
|
+
from cellprofiler_library.types import StructuringElement, ObjectSegmentation
|
|
12
|
+
from cellprofiler_library.functions.object_processing import erode_objects_with_structuring_element
|
|
13
|
+
from cellprofiler_library.functions.image_processing import get_structuring_element
|
|
14
|
+
from cellprofiler_library.opts.structuring_elements import StructuringElementShape2D, StructuringElementShape3D
|
|
15
|
+
|
|
16
|
+
StructuringElementSize = Annotated[int, Field(description="Size of structuring element", gt=0)]
|
|
17
|
+
StructuringElementParameters = Tuple[Union[StructuringElementShape2D, StructuringElementShape3D], StructuringElementSize]
|
|
18
|
+
|
|
19
|
+
@validate_call(config=ConfigDict(arbitrary_types_allowed=True))
|
|
20
|
+
def erode_objects(
|
|
21
|
+
labels: Annotated[ObjectSegmentation, Field(description="Input object segmentations")],
|
|
22
|
+
structuring_element: Annotated[Union[StructuringElement, StructuringElementParameters], Field(description="Structuring element for erosion operation as either an NDArray or a tuple of (StructuringElement[N]D, size)")],
|
|
23
|
+
preserve_midpoints: Annotated[bool, Field(description="If set to True, the central pixels for each object will not be eroded. This ensures that objects are not lost.")] = False,
|
|
24
|
+
relabel_objects: Annotated[bool, Field(description="Selecting True will assign new label numbers to resulting objects")] = False
|
|
25
|
+
) -> ObjectSegmentation:
|
|
26
|
+
"""Erode objects based on the structuring element provided.
|
|
27
|
+
|
|
28
|
+
This function is similar to the "Shrink" function of ExpandOrShrinkObjects,
|
|
29
|
+
with two major distinctions:
|
|
30
|
+
1. ErodeObjects supports 3D objects, unlike ExpandOrShrinkObjects.
|
|
31
|
+
2. An object smaller than the structuring element will be removed entirely
|
|
32
|
+
unless preserve_midpoints is enabled.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
labels: Input labeled objects array
|
|
36
|
+
structuring_element: Structuring element for erosion operation
|
|
37
|
+
preserve_midpoints: If set to True, the central pixels for each object will not be eroded. This ensures that objects are not lost.
|
|
38
|
+
relabel_objects: If set to True, the resulting objects will be relabeled with new label numbers
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Eroded objects array with same dimensions as input
|
|
42
|
+
"""
|
|
43
|
+
if isinstance(structuring_element, tuple):
|
|
44
|
+
structuring_element = get_structuring_element(structuring_element[0], structuring_element[1])
|
|
45
|
+
return erode_objects_with_structuring_element(
|
|
46
|
+
labels=labels,
|
|
47
|
+
structuring_element=structuring_element,
|
|
48
|
+
preserve_midpoints=preserve_midpoints,
|
|
49
|
+
relabel_objects=relabel_objects
|
|
50
|
+
)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
class OperationMethod(str, Enum):
|
|
4
|
+
ENHANCE = "Enhance"
|
|
5
|
+
SUPPRESS = "Suppress"
|
|
6
|
+
|
|
7
|
+
class EnhanceMethod(str, Enum):
|
|
8
|
+
SPECKLES = "Speckles"
|
|
9
|
+
NEURITES = "Neurites"
|
|
10
|
+
DARK_HOLES = "Dark holes"
|
|
11
|
+
CIRCLES = "Circles"
|
|
12
|
+
TEXTURE = "Texture"
|
|
13
|
+
DIC = "DIC"
|
|
14
|
+
|
|
15
|
+
class SpeckleAccuracy(str, Enum):
|
|
16
|
+
SLOW = "Slow"
|
|
17
|
+
FAST = "Fast"
|
|
18
|
+
|
|
19
|
+
class NeuriteMethod(str, Enum):
|
|
20
|
+
GRADIENT = "Line structures"
|
|
21
|
+
TUBENESS = "Tubeness"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Options and enums for ErodeObjects module
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# Note: ErodeObjects is a simple morphological operation module that doesn't require
|
|
8
|
+
# complex enums. The main configuration is handled through the StructuringElement
|
|
9
|
+
# setting which is managed by the core framework. This file is created for
|
|
10
|
+
# consistency with the refactoring pattern but may be minimal.
|
|
11
|
+
|
|
12
|
+
# Currently no custom enums needed for ErodeObjects as it uses standard
|
|
13
|
+
# StructuringElement configuration from cellprofiler_core. For structuring element shapes,
|
|
14
|
+
# see cellprofiler_library.opts.structuring_elements
|
|
15
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cellprofiler-library-nightly
|
|
3
|
-
Version: 5.0.0.
|
|
3
|
+
Version: 5.0.0.dev336
|
|
4
4
|
Summary: cellprofiler-library implements CellProfiler's image processing and mathematical code, and is usable as a standalone library
|
|
5
5
|
Author: Anne Carpenter, Thouis (Ray) Jones, Lee Kamentsky, Vebjorn Ljosa, David Logan, Mark Bray, Madison Swain-Bowden, Allen Goodman, Claire McQuinn, Alice Lucas, Callum Tromans-Coia
|
|
6
6
|
Author-email: Beth Cimini <bcimini@broadinstitute.org>, David Stirling <dstirling@glencoesoftware.com>, Nodar Gogoberidze <ngogober@broadinstitute.org>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
cellprofiler_library/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
cellprofiler_library/_version.py,sha256=
|
|
2
|
+
cellprofiler_library/_version.py,sha256=vnxlYqRhiedLOL6RtUPR0CE0S0pD8ly0U9lQv_qIKec,721
|
|
3
3
|
cellprofiler_library/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
cellprofiler_library/types.py,sha256=cU38AwLLsMiI3XCwfrmWmDNpGWgLfpCpsuwnijaT8vU,8559
|
|
5
5
|
cellprofiler_library/functions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
cellprofiler_library/functions/file_processing.py,sha256=jumpdgxReyV5xzF4YXZWhkei9CQ9GtWD-VUCuFh-FZM,5168
|
|
7
|
-
cellprofiler_library/functions/image_processing.py,sha256=
|
|
7
|
+
cellprofiler_library/functions/image_processing.py,sha256=d9T0Ro2BaOS9Y9CrNgqUlOjUHTJVLnxOG696IWeLQeg,43556
|
|
8
8
|
cellprofiler_library/functions/measurement.py,sha256=8pXcEb1fLgwOEDiTJho1_O-fFGTtIp-Qn1lStjQBjbo,29221
|
|
9
|
-
cellprofiler_library/functions/object_processing.py,sha256=
|
|
9
|
+
cellprofiler_library/functions/object_processing.py,sha256=5yHR_toKMH0KfWPAtEESQfK9JOdaD3L7WZskjGyoZ2o,23209
|
|
10
10
|
cellprofiler_library/functions/segmentation.py,sha256=LNE22ByY0X7GepQaHqLdxkzlmIXjD3EglAYJjtT2dGo,25257
|
|
11
11
|
cellprofiler_library/modules/__init__.py,sha256=Z4Wy42OTD9ujAON4g1oyLJ0oA6K7h3XQiV66JzHGkOw,789
|
|
12
12
|
cellprofiler_library/modules/_closing.py,sha256=aIqIE0IcT2OcrOmTSWjFzu4iIQKk2yDC9qPHARqRIkc,204
|
|
@@ -18,7 +18,9 @@ cellprofiler_library/modules/_correctilluminationapply.py,sha256=8bZC3AnQv3vpUrN
|
|
|
18
18
|
cellprofiler_library/modules/_crop.py,sha256=0T0sQsK7o5dHVXMZ4OqvAJkskkyez1MXcnPlU5yqsV4,2422
|
|
19
19
|
cellprofiler_library/modules/_dilateimage.py,sha256=9mdB3Ft7muCkArTcEebs-Dz7_Ptg3YZsdL1qkr9K_0o,1812
|
|
20
20
|
cellprofiler_library/modules/_enhanceedges.py,sha256=PaXZck8fPcxRf-IXCstu-OWmsvM_rDDPMMQ3cZFfVZc,2951
|
|
21
|
+
cellprofiler_library/modules/_enhanceorsuppressfeatures.py,sha256=UkcJ2qM32hmnB_68yyjKmdaus78OXcpWi7E5OwRz9R8,3469
|
|
21
22
|
cellprofiler_library/modules/_erodeimage.py,sha256=nFHn4hdpjXJaPvnpSyfPAxWgd7UXi0fUUgPqEl26CCY,1802
|
|
23
|
+
cellprofiler_library/modules/_erodeobjects.py,sha256=ru0n0wdLeBevN4Y1LwO98KltPQO1X6kpfu0LMRUzxGE,2781
|
|
22
24
|
cellprofiler_library/modules/_expandorshrinkobjects.py,sha256=A1oeW_O8C5NLJr-xU1R9pSulDau8XUeWaKiilpr-85g,856
|
|
23
25
|
cellprofiler_library/modules/_fillobjects.py,sha256=1zvlZNJhG8kEzAnVyiSLGPNE338EB5wopD2eK0BVWrc,469
|
|
24
26
|
cellprofiler_library/modules/_gaussianfilter.py,sha256=zVt562oviuoyy6l85Tgg_rjyQdOFCEnYLuykHYnYni8,174
|
|
@@ -40,13 +42,15 @@ cellprofiler_library/opts/convertobjectstoimage.py,sha256=U3jeVtKYFgfxbO7NYndanA
|
|
|
40
42
|
cellprofiler_library/opts/correctilluminationapply.py,sha256=IkAqjMjaRdsoY2aXw5_dLI1iRYqCwvcNwCWEpWNZrN4,96
|
|
41
43
|
cellprofiler_library/opts/crop.py,sha256=GaArWq3WZd_Ykunj1SSbFOYkqDQ6TXy2MDKxG4fA6ZE,879
|
|
42
44
|
cellprofiler_library/opts/dilateimage.py,sha256=KsRf7gTKzFcTcylfIBrwue9csKBtJZdbVPFT5P_OjOM,588
|
|
45
|
+
cellprofiler_library/opts/enhanceorsuppressfeatures.py,sha256=8Ej5TFUX-EKTbUcV3AidcIaomwh_A9A5lNJVRu76pc4,449
|
|
43
46
|
cellprofiler_library/opts/erodeimage.py,sha256=T3LCqu83rTqTDlc_7ebuPBKnr-FKomRHA8WD0uA9Y1g,584
|
|
47
|
+
cellprofiler_library/opts/erodeobjects.py,sha256=jOooDWqy01qdh17nAF0nbluU1lPToO2ZZqqsAzj2iNg,591
|
|
44
48
|
cellprofiler_library/opts/measureimageoverlap.py,sha256=uopQCJTX1Uk-NNDAISsdYEOuOtiEBYOyCwu57ZT7X84,134
|
|
45
49
|
cellprofiler_library/opts/objectsizeshapefeatures.py,sha256=3GIntOH3qXs7F16Tpjmtg7opHYAmmOjEdEwW6q3ht_Y,6306
|
|
46
50
|
cellprofiler_library/opts/structuring_elements.py,sha256=Q4pBdCgDmjPx05t61Zqi40Iof8Nj3UR5k-F7brImLZY,263
|
|
47
51
|
cellprofiler_library/opts/threshold.py,sha256=yg_i5to22Nd9hTakaRxo9UIQZRYWFpavJimjl5JONx4,938
|
|
48
|
-
cellprofiler_library_nightly-5.0.0.
|
|
49
|
-
cellprofiler_library_nightly-5.0.0.
|
|
50
|
-
cellprofiler_library_nightly-5.0.0.
|
|
51
|
-
cellprofiler_library_nightly-5.0.0.
|
|
52
|
-
cellprofiler_library_nightly-5.0.0.
|
|
52
|
+
cellprofiler_library_nightly-5.0.0.dev336.dist-info/licenses/LICENSE,sha256=QLWaBS7kAioYx7PmJNXAMJaY8NODcFAag60YlUWuyz0,2276
|
|
53
|
+
cellprofiler_library_nightly-5.0.0.dev336.dist-info/METADATA,sha256=BQRHsQwGxyIEwjnINX6OLPJEzhsP2ZXEOlH-WGrBJbA,5534
|
|
54
|
+
cellprofiler_library_nightly-5.0.0.dev336.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
55
|
+
cellprofiler_library_nightly-5.0.0.dev336.dist-info/top_level.txt,sha256=LXq0ApDeDD4gotb6YFTySzdyScvHfS_pqoTg1QsNLBs,21
|
|
56
|
+
cellprofiler_library_nightly-5.0.0.dev336.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|