1""" 2 3General Description 4------------------- 5 6These filters compute the local histogram at each pixel, using a sliding window 7similar to the method described in [1]_. A histogram is built using a moving 8window in order to limit redundant computation. The moving window follows a 9snake-like path: 10 11...------------------------↘ 12↙--------------------------↙ 13↘--------------------------... 14 15The local histogram is updated at each pixel as the footprint window 16moves by, i.e. only those pixels entering and leaving the footprint 17update the local histogram. The histogram size is 8-bit (256 bins) for 8-bit 18images and 2- to 16-bit for 16-bit images depending on the maximum value of the 19image. 20 21The filter is applied up to the image border, the neighborhood used is 22adjusted accordingly. The user may provide a mask image (same size as input 23image) where non zero values are the part of the image participating in the 24histogram computation. By default the entire image is filtered. 25 26This implementation outperforms :func:`skimage.morphology.dilation` 27for large footprints. 28 29Input images will be cast in unsigned 8-bit integer or unsigned 16-bit integer 30if necessary. The number of histogram bins is then determined from the maximum 31value present in the image. Eventually, the output image is cast in the input 32dtype, or the `output_dtype` if set. 33 34To do 35----- 36 37* add simple examples, adapt documentation on existing examples 38* add/check existing doc 39* adapting tests for each type of filter 40 41 42References 43---------- 44 45.. [1] Huang, T. ,Yang, G. ; Tang, G.. "A fast two-dimensional 46 median filtering algorithm", IEEE Transactions on Acoustics, Speech and 47 Signal Processing, Feb 1979. Volume: 27 , Issue: 1, Page(s): 13 - 18. 48 49""" 50 51import numpy as np 52from scipy import ndimage as ndi 53 54from ..._shared.utils import check_nD, deprecate_kwarg, warn 55from ...util import img_as_ubyte 56from . import generic_cy 57 58 59__all__ = ['autolevel', 'equalize', 'gradient', 'maximum', 'mean', 60 'geometric_mean', 'subtract_mean', 'median', 'minimum', 'modal', 61 'enhance_contrast', 'pop', 'threshold', 'noise_filter', 62 'entropy', 'otsu'] 63 64 65def _preprocess_input(image, footprint=None, out=None, mask=None, 66 out_dtype=None, pixel_size=1): 67 """Preprocess and verify input for filters.rank methods. 68 69 Parameters 70 ---------- 71 image : 2-D array (integer or float) 72 Input image. 73 footprint : 2-D array (integer or float), optional 74 The neighborhood expressed as a 2-D array of 1's and 0's. 75 out : 2-D array (integer or float), optional 76 If None, a new array is allocated. 77 mask : ndarray (integer or float), optional 78 Mask array that defines (>0) area of the image included in the local 79 neighborhood. If None, the complete image is used (default). 80 out_dtype : data-type, optional 81 Desired output data-type. Default is None, which means we cast output 82 in input dtype. 83 pixel_size : int, optional 84 Dimension of each pixel. Default value is 1. 85 86 Returns 87 ------- 88 image : 2-D array (np.uint8 or np.uint16) 89 footprint : 2-D array (np.uint8) 90 The neighborhood expressed as a binary 2-D array. 91 out : 3-D array (same dtype out_dtype or as input) 92 Output array. The two first dimensions are the spatial ones, the third 93 one is the pixel vector (length 1 by default). 94 mask : 2-D array (np.uint8) 95 Mask array that defines (>0) area of the image included in the local 96 neighborhood. 97 n_bins : int 98 Number of histogram bins. 99 100 """ 101 check_nD(image, 2) 102 input_dtype = image.dtype 103 if (input_dtype in (bool, bool) or out_dtype in (bool, bool)): 104 raise ValueError('dtype cannot be bool.') 105 if input_dtype not in (np.uint8, np.uint16): 106 message = (f'Possible precision loss converting image of type ' 107 f'{input_dtype} to uint8 as required by rank filters. ' 108 f'Convert manually using skimage.util.img_as_ubyte to ' 109 f'silence this warning.') 110 warn(message, stacklevel=5) 111 image = img_as_ubyte(image) 112 113 footprint = np.ascontiguousarray(img_as_ubyte(footprint > 0)) 114 if footprint.ndim != image.ndim: 115 raise ValueError('Image dimensions and neighborhood dimensions' 116 'do not match') 117 118 image = np.ascontiguousarray(image) 119 120 if mask is not None: 121 mask = img_as_ubyte(mask) 122 mask = np.ascontiguousarray(mask) 123 124 if image is out: 125 raise NotImplementedError("Cannot perform rank operation in place.") 126 127 if out is None: 128 if out_dtype is None: 129 out_dtype = image.dtype 130 out = np.empty(image.shape + (pixel_size,), dtype=out_dtype) 131 else: 132 if len(out.shape) == 2: 133 out = out.reshape(out.shape + (pixel_size,)) 134 135 if image.dtype in (np.uint8, np.int8): 136 n_bins = 256 137 else: 138 # Convert to a Python int to avoid the potential overflow when we add 139 # 1 to the maximum of the image. 140 n_bins = int(max(3, image.max())) + 1 141 142 if n_bins > 2 ** 10: 143 warn(f'Bad rank filter performance is expected due to a ' 144 f'large number of bins ({n_bins}), equivalent to an approximate ' 145 f'bitdepth of {np.log2(n_bins):.1f}.', 146 stacklevel=2) 147 148 return image, footprint, out, mask, n_bins 149 150 151def _handle_input_3D(image, footprint=None, out=None, mask=None, 152 out_dtype=None, pixel_size=1): 153 """Preprocess and verify input for filters.rank methods. 154 155 Parameters 156 ---------- 157 image : 3-D array (integer or float) 158 Input image. 159 footprint : 3-D array (integer or float), optional 160 The neighborhood expressed as a 3-D array of 1's and 0's. 161 out : 3-D array (integer or float), optional 162 If None, a new array is allocated. 163 mask : ndarray (integer or float), optional 164 Mask array that defines (>0) area of the image included in the local 165 neighborhood. If None, the complete image is used (default). 166 out_dtype : data-type, optional 167 Desired output data-type. Default is None, which means we cast output 168 in input dtype. 169 pixel_size : int, optional 170 Dimension of each pixel. Default value is 1. 171 172 Returns 173 ------- 174 image : 3-D array (np.uint8 or np.uint16) 175 footprint : 3-D array (np.uint8) 176 The neighborhood expressed as a binary 3-D array. 177 out : 3-D array (same dtype out_dtype or as input) 178 Output array. The two first dimensions are the spatial ones, the third 179 one is the pixel vector (length 1 by default). 180 mask : 3-D array (np.uint8) 181 Mask array that defines (>0) area of the image included in the local 182 neighborhood. 183 n_bins : int 184 Number of histogram bins. 185 186 """ 187 check_nD(image, 3) 188 if image.dtype not in (np.uint8, np.uint16): 189 message = (f'Possible precision loss converting image of type ' 190 f'{image.dtype} to uint8 as required by rank filters. ' 191 f'Convert manually using skimage.util.img_as_ubyte to ' 192 f'silence this warning.') 193 warn(message, stacklevel=2) 194 image = img_as_ubyte(image) 195 196 footprint = np.ascontiguousarray(img_as_ubyte(footprint > 0)) 197 if footprint.ndim != image.ndim: 198 raise ValueError('Image dimensions and neighborhood dimensions' 199 'do not match') 200 image = np.ascontiguousarray(image) 201 202 if mask is None: 203 mask = np.ones(image.shape, dtype=np.uint8) 204 else: 205 mask = img_as_ubyte(mask) 206 mask = np.ascontiguousarray(mask) 207 208 if image is out: 209 raise NotImplementedError("Cannot perform rank operation in place.") 210 211 if out is None: 212 if out_dtype is None: 213 out_dtype = image.dtype 214 out = np.empty(image.shape + (pixel_size,), dtype=out_dtype) 215 else: 216 out = out.reshape(out.shape + (pixel_size,)) 217 218 is_8bit = image.dtype in (np.uint8, np.int8) 219 220 if is_8bit: 221 n_bins = 256 222 else: 223 # Convert to a Python int to avoid the potential overflow when we add 224 # 1 to the maximum of the image. 225 n_bins = int(max(3, image.max())) + 1 226 227 if n_bins > 2**10: 228 warn(f'Bad rank filter performance is expected due to a ' 229 f'large number of bins ({n_bins}), equivalent to an approximate ' 230 f'bitdepth of {np.log2(n_bins):.1f}.', 231 stacklevel=2) 232 233 return image, footprint, out, mask, n_bins 234 235 236def _apply_scalar_per_pixel(func, image, footprint, out, mask, shift_x, 237 shift_y, out_dtype=None): 238 """Process the specific cython function to the image. 239 240 Parameters 241 ---------- 242 func : function 243 Cython function to apply. 244 image : 2-D array (integer or float) 245 Input image. 246 footprint : 2-D array (integer or float) 247 The neighborhood expressed as a 2-D array of 1's and 0's. 248 out : 2-D array (integer or float) 249 If None, a new array is allocated. 250 mask : ndarray (integer or float) 251 Mask array that defines (>0) area of the image included in the local 252 neighborhood. If None, the complete image is used (default). 253 shift_x, shift_y : int 254 Offset added to the footprint center point. Shift is bounded to the 255 footprint sizes (center must be inside the given footprint). 256 out_dtype : data-type, optional 257 Desired output data-type. Default is None, which means we cast output 258 in input dtype. 259 260 """ 261 # preprocess and verify the input 262 image, footprint, out, mask, n_bins = _preprocess_input(image, footprint, 263 out, mask, 264 out_dtype) 265 266 # apply cython function 267 func(image, footprint, shift_x=shift_x, shift_y=shift_y, mask=mask, 268 out=out, n_bins=n_bins) 269 270 return np.squeeze(out, axis=-1) 271 272 273def _apply_scalar_per_pixel_3D(func, image, footprint, out, mask, shift_x, 274 shift_y, shift_z, out_dtype=None): 275 276 image, footprint, out, mask, n_bins = _handle_input_3D( 277 image, footprint, out, mask, out_dtype 278 ) 279 280 func(image, footprint, shift_x=shift_x, shift_y=shift_y, shift_z=shift_z, 281 mask=mask, out=out, n_bins=n_bins) 282 283 return out.reshape(out.shape[:3]) 284 285 286def _apply_vector_per_pixel(func, image, footprint, out, mask, shift_x, 287 shift_y, out_dtype=None, pixel_size=1): 288 """ 289 290 Parameters 291 ---------- 292 func : function 293 Cython function to apply. 294 image : 2-D array (integer or float) 295 Input image. 296 footprint : 2-D array (integer or float) 297 The neighborhood expressed as a 2-D array of 1's and 0's. 298 out : 2-D array (integer or float) 299 If None, a new array is allocated. 300 mask : ndarray (integer or float) 301 Mask array that defines (>0) area of the image included in the local 302 neighborhood. If None, the complete image is used (default). 303 shift_x, shift_y : int 304 Offset added to the footprint center point. Shift is bounded to the 305 footprint sizes (center must be inside the given footprint). 306 out_dtype : data-type, optional 307 Desired output data-type. Default is None, which means we cast output 308 in input dtype. 309 pixel_size : int, optional 310 Dimension of each pixel. 311 312 Returns 313 ------- 314 out : 3-D array with float dtype of dimensions (H,W,N), where (H,W) are 315 the dimensions of the input image and N is n_bins or 316 ``image.max() + 1`` if no value is provided as a parameter. 317 Effectively, each pixel is a N-D feature vector that is the histogram. 318 The sum of the elements in the feature vector will be 1, unless no 319 pixels in the window were covered by both footprint and mask, in which 320 case all elements will be 0. 321 322 """ 323 # preprocess and verify the input 324 image, footprint, out, mask, n_bins = _preprocess_input(image, footprint, 325 out, mask, 326 out_dtype, 327 pixel_size) 328 329 # apply cython function 330 func(image, footprint, shift_x=shift_x, shift_y=shift_y, mask=mask, 331 out=out, n_bins=n_bins) 332 333 return out 334 335 336@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 337 deprecated_version="0.19") 338def autolevel(image, footprint, out=None, mask=None, 339 shift_x=False, shift_y=False, shift_z=False): 340 """Auto-level image using local histogram. 341 342 This filter locally stretches the histogram of gray values to cover the 343 entire range of values from "white" to "black". 344 345 Parameters 346 ---------- 347 image : ([P,] M, N) ndarray (uint8, uint16) 348 Input image. 349 footprint : ndarray 350 The neighborhood expressed as an ndarray of 1's and 0's. 351 out : ([P,] M, N) array (same dtype as input) 352 If None, a new array is allocated. 353 mask : ndarray (integer or float), optional 354 Mask array that defines (>0) area of the image included in the local 355 neighborhood. If None, the complete image is used (default). 356 shift_x, shift_y, shift_z : int 357 Offset added to the footprint center point. Shift is bounded to the 358 footprint sizes (center must be inside the given footprint). 359 360 Returns 361 ------- 362 out : ([P,] M, N) ndarray (same dtype as input image) 363 Output image. 364 365 Examples 366 -------- 367 >>> from skimage import data 368 >>> from skimage.morphology import disk, ball 369 >>> from skimage.filters.rank import autolevel 370 >>> import numpy as np 371 >>> img = data.camera() 372 >>> rng = np.random.default_rng() 373 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 374 >>> auto = autolevel(img, disk(5)) 375 >>> auto_vol = autolevel(volume, ball(5)) 376 377 """ 378 379 np_image = np.asanyarray(image) 380 if np_image.ndim == 2: 381 return _apply_scalar_per_pixel(generic_cy._autolevel, image, footprint, 382 out=out, mask=mask, 383 shift_x=shift_x, shift_y=shift_y) 384 else: 385 return _apply_scalar_per_pixel_3D(generic_cy._autolevel_3D, image, 386 footprint, out=out, mask=mask, 387 shift_x=shift_x, shift_y=shift_y, 388 shift_z=shift_z) 389 390 391@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 392 deprecated_version="0.19") 393def equalize(image, footprint, out=None, mask=None, 394 shift_x=False, shift_y=False, shift_z=False): 395 """Equalize image using local histogram. 396 397 Parameters 398 ---------- 399 image : ([P,] M, N) ndarray (uint8, uint16) 400 Input image. 401 footprint : ndarray 402 The neighborhood expressed as an ndarray of 1's and 0's. 403 out : ([P,] M, N) array (same dtype as input) 404 If None, a new array is allocated. 405 mask : ndarray (integer or float), optional 406 Mask array that defines (>0) area of the image included in the local 407 neighborhood. If None, the complete image is used (default). 408 shift_x, shift_y, shift_z : int 409 Offset added to the footprint center point. Shift is bounded to the 410 footprint sizes (center must be inside the given footprint). 411 412 Returns 413 ------- 414 out : ([P,] M, N) ndarray (same dtype as input image) 415 Output image. 416 417 Examples 418 -------- 419 >>> from skimage import data 420 >>> from skimage.morphology import disk, ball 421 >>> from skimage.filters.rank import equalize 422 >>> import numpy as np 423 >>> img = data.camera() 424 >>> rng = np.random.default_rng() 425 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 426 >>> equ = equalize(img, disk(5)) 427 >>> equ_vol = equalize(volume, ball(5)) 428 429 """ 430 431 np_image = np.asanyarray(image) 432 if np_image.ndim == 2: 433 return _apply_scalar_per_pixel(generic_cy._equalize, image, footprint, 434 out=out, mask=mask, 435 shift_x=shift_x, shift_y=shift_y) 436 else: 437 return _apply_scalar_per_pixel_3D(generic_cy._equalize_3D, image, 438 footprint, out=out, mask=mask, 439 shift_x=shift_x, shift_y=shift_y, 440 shift_z=shift_z) 441 442 443@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 444 deprecated_version="0.19") 445def gradient(image, footprint, out=None, mask=None, 446 shift_x=False, shift_y=False, shift_z=False): 447 """Return local gradient of an image (i.e. local maximum - local minimum). 448 449 Parameters 450 ---------- 451 image : ([P,] M, N) ndarray (uint8, uint16) 452 Input image. 453 footprint : ndarray 454 The neighborhood expressed as an ndarray of 1's and 0's. 455 out : ([P,] M, N) array (same dtype as input) 456 If None, a new array is allocated. 457 mask : ndarray (integer or float), optional 458 Mask array that defines (>0) area of the image included in the local 459 neighborhood. If None, the complete image is used (default). 460 shift_x, shift_y, shift_z : int 461 Offset added to the footprint center point. Shift is bounded to the 462 footprint sizes (center must be inside the given footprint). 463 464 Returns 465 ------- 466 out : ([P,] M, N) ndarray (same dtype as input image) 467 Output image. 468 469 Examples 470 -------- 471 >>> from skimage import data 472 >>> from skimage.morphology import disk, ball 473 >>> from skimage.filters.rank import gradient 474 >>> import numpy as np 475 >>> img = data.camera() 476 >>> rng = np.random.default_rng() 477 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 478 >>> out = gradient(img, disk(5)) 479 >>> out_vol = gradient(volume, ball(5)) 480 481 """ 482 483 np_image = np.asanyarray(image) 484 if np_image.ndim == 2: 485 return _apply_scalar_per_pixel(generic_cy._gradient, image, footprint, 486 out=out, mask=mask, 487 shift_x=shift_x, shift_y=shift_y) 488 else: 489 return _apply_scalar_per_pixel_3D(generic_cy._gradient_3D, image, 490 footprint, out=out, mask=mask, 491 shift_x=shift_x, shift_y=shift_y, 492 shift_z=shift_z) 493 494 495@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 496 deprecated_version="0.19") 497def maximum(image, footprint, out=None, mask=None, 498 shift_x=False, shift_y=False, shift_z=False): 499 """Return local maximum of an image. 500 501 Parameters 502 ---------- 503 image : ([P,] M, N) ndarray (uint8, uint16) 504 Input image. 505 footprint : ndarray 506 The neighborhood expressed as an ndarray of 1's and 0's. 507 out : ([P,] M, N) array (same dtype as input) 508 If None, a new array is allocated. 509 mask : ndarray (integer or float), optional 510 Mask array that defines (>0) area of the image included in the local 511 neighborhood. If None, the complete image is used (default). 512 shift_x, shift_y, shift_z : int 513 Offset added to the footprint center point. Shift is bounded to the 514 footprint sizes (center must be inside the given footprint). 515 516 Returns 517 ------- 518 out : ([P,] M, N) ndarray (same dtype as input image) 519 Output image. 520 521 See also 522 -------- 523 skimage.morphology.dilation 524 525 Notes 526 ----- 527 The lower algorithm complexity makes `skimage.filters.rank.maximum` 528 more efficient for larger images and footprints. 529 530 Examples 531 -------- 532 >>> from skimage import data 533 >>> from skimage.morphology import disk, ball 534 >>> from skimage.filters.rank import maximum 535 >>> import numpy as np 536 >>> img = data.camera() 537 >>> rng = np.random.default_rng() 538 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 539 >>> out = maximum(img, disk(5)) 540 >>> out_vol = maximum(volume, ball(5)) 541 542 """ 543 544 np_image = np.asanyarray(image) 545 if np_image.ndim == 2: 546 return _apply_scalar_per_pixel(generic_cy._maximum, image, footprint, 547 out=out, mask=mask, 548 shift_x=shift_x, shift_y=shift_y) 549 else: 550 return _apply_scalar_per_pixel_3D(generic_cy._maximum_3D, image, 551 footprint, out=out, mask=mask, 552 shift_x=shift_x, shift_y=shift_y, 553 shift_z=shift_z) 554 555 556@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 557 deprecated_version="0.19") 558def mean(image, footprint, out=None, mask=None, 559 shift_x=False, shift_y=False, shift_z=False): 560 """Return local mean of an image. 561 562 Parameters 563 ---------- 564 image : ([P,] M, N) ndarray (uint8, uint16) 565 Input image. 566 footprint : ndarray 567 The neighborhood expressed as an ndarray of 1's and 0's. 568 out : ([P,] M, N) array (same dtype as input) 569 If None, a new array is allocated. 570 mask : ndarray (integer or float), optional 571 Mask array that defines (>0) area of the image included in the local 572 neighborhood. If None, the complete image is used (default). 573 shift_x, shift_y, shift_z : int 574 Offset added to the footprint center point. Shift is bounded to the 575 footprint sizes (center must be inside the given footprint). 576 577 Returns 578 ------- 579 out : ([P,] M, N) ndarray (same dtype as input image) 580 Output image. 581 582 Examples 583 -------- 584 >>> from skimage import data 585 >>> from skimage.morphology import disk, ball 586 >>> from skimage.filters.rank import mean 587 >>> import numpy as np 588 >>> img = data.camera() 589 >>> rng = np.random.default_rng() 590 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 591 >>> avg = mean(img, disk(5)) 592 >>> avg_vol = mean(volume, ball(5)) 593 594 """ 595 596 np_image = np.asanyarray(image) 597 if np_image.ndim == 2: 598 return _apply_scalar_per_pixel(generic_cy._mean, image, footprint, 599 out=out, mask=mask, 600 shift_x=shift_x, shift_y=shift_y) 601 else: 602 return _apply_scalar_per_pixel_3D(generic_cy._mean_3D, image, 603 footprint, out=out, mask=mask, 604 shift_x=shift_x, shift_y=shift_y, 605 shift_z=shift_z) 606 607 608@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 609 deprecated_version="0.19") 610def geometric_mean(image, footprint, out=None, mask=None, 611 shift_x=False, shift_y=False, shift_z=False): 612 """Return local geometric mean of an image. 613 614 Parameters 615 ---------- 616 image : ([P,] M, N) ndarray (uint8, uint16) 617 Input image. 618 footprint : ndarray 619 The neighborhood expressed as an ndarray of 1's and 0's. 620 out : ([P,] M, N) array (same dtype as input) 621 If None, a new array is allocated. 622 mask : ndarray (integer or float), optional 623 Mask array that defines (>0) area of the image included in the local 624 neighborhood. If None, the complete image is used (default). 625 shift_x, shift_y, shift_z : int 626 Offset added to the footprint center point. Shift is bounded to the 627 footprint sizes (center must be inside the given footprint). 628 629 Returns 630 ------- 631 out : ([P,] M, N) ndarray (same dtype as input image) 632 Output image. 633 634 Examples 635 -------- 636 >>> from skimage import data 637 >>> from skimage.morphology import disk, ball 638 >>> from skimage.filters.rank import mean 639 >>> import numpy as np 640 >>> img = data.camera() 641 >>> rng = np.random.default_rng() 642 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 643 >>> avg = geometric_mean(img, disk(5)) 644 >>> avg_vol = geometric_mean(volume, ball(5)) 645 646 References 647 ---------- 648 .. [1] Gonzalez, R. C. and Wood, R. E. "Digital Image Processing (3rd Edition)." 649 Prentice-Hall Inc, 2006. 650 651 """ 652 653 np_image = np.asanyarray(image) 654 if np_image.ndim == 2: 655 return _apply_scalar_per_pixel(generic_cy._geometric_mean, image, 656 footprint, out=out, mask=mask, 657 shift_x=shift_x, shift_y=shift_y) 658 else: 659 return _apply_scalar_per_pixel_3D(generic_cy._geometric_mean_3D, image, 660 footprint, out=out, mask=mask, 661 shift_x=shift_x, shift_y=shift_y, 662 shift_z=shift_z) 663 664 665@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 666 deprecated_version="0.19") 667def subtract_mean(image, footprint, out=None, mask=None, 668 shift_x=False, shift_y=False, shift_z=False): 669 """Return image subtracted from its local mean. 670 671 Parameters 672 ---------- 673 image : ([P,] M, N) ndarray (uint8, uint16) 674 Input image. 675 footprint : ndarray 676 The neighborhood expressed as an ndarray of 1's and 0's. 677 out : ([P,] M, N) array (same dtype as input) 678 If None, a new array is allocated. 679 mask : ndarray (integer or float), optional 680 Mask array that defines (>0) area of the image included in the local 681 neighborhood. If None, the complete image is used (default). 682 shift_x, shift_y, shift_z : int 683 Offset added to the footprint center point. Shift is bounded to the 684 footprint sizes (center must be inside the given footprint). 685 686 Returns 687 ------- 688 out : ([P,] M, N) ndarray (same dtype as input image) 689 Output image. 690 691 Notes 692 ----- 693 Subtracting the mean value may introduce underflow. To compensate 694 this potential underflow, the obtained difference is downscaled by 695 a factor of 2 and shifted by `n_bins / 2 - 1`, the median value of 696 the local histogram (`n_bins = max(3, image.max()) +1` for 16-bits 697 images and 256 otherwise). 698 699 Examples 700 -------- 701 >>> from skimage import data 702 >>> from skimage.morphology import disk, ball 703 >>> from skimage.filters.rank import subtract_mean 704 >>> import numpy as np 705 >>> img = data.camera() 706 >>> rng = np.random.default_rng() 707 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 708 >>> out = subtract_mean(img, disk(5)) 709 >>> out_vol = subtract_mean(volume, ball(5)) 710 711 """ 712 713 np_image = np.asanyarray(image) 714 if np_image.ndim == 2: 715 return _apply_scalar_per_pixel(generic_cy._subtract_mean, image, 716 footprint, out=out, mask=mask, 717 shift_x=shift_x, shift_y=shift_y) 718 else: 719 return _apply_scalar_per_pixel_3D(generic_cy._subtract_mean_3D, image, 720 footprint, out=out, mask=mask, 721 shift_x=shift_x, shift_y=shift_y, 722 shift_z=shift_z) 723 724 725@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 726 deprecated_version="0.19") 727def median(image, footprint=None, out=None, mask=None, 728 shift_x=False, shift_y=False, shift_z=False): 729 """Return local median of an image. 730 731 Parameters 732 ---------- 733 image : ([P,] M, N) ndarray (uint8, uint16) 734 Input image. 735 footprint : ndarray 736 The neighborhood expressed as an ndarray of 1's and 0's. If None, a 737 full square of size 3 is used. 738 out : ([P,] M, N) array (same dtype as input) 739 If None, a new array is allocated. 740 mask : ndarray (integer or float), optional 741 Mask array that defines (>0) area of the image included in the local 742 neighborhood. If None, the complete image is used (default). 743 shift_x, shift_y, shift_z : int 744 Offset added to the footprint center point. Shift is bounded to the 745 footprint sizes (center must be inside the given footprint). 746 747 Returns 748 ------- 749 out : ([P,] M, N) ndarray (same dtype as input image) 750 Output image. 751 752 See also 753 -------- 754 skimage.filters.median : Implementation of a median filtering which handles 755 images with floating precision. 756 757 Examples 758 -------- 759 >>> from skimage import data 760 >>> from skimage.morphology import disk, ball 761 >>> from skimage.filters.rank import median 762 >>> import numpy as np 763 >>> img = data.camera() 764 >>> rng = np.random.default_rng() 765 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 766 >>> med = median(img, disk(5)) 767 >>> med_vol = median(volume, ball(5)) 768 769 """ 770 771 np_image = np.asanyarray(image) 772 if footprint is None: 773 footprint = ndi.generate_binary_structure(image.ndim, image.ndim) 774 if np_image.ndim == 2: 775 return _apply_scalar_per_pixel(generic_cy._median, image, footprint, 776 out=out, mask=mask, 777 shift_x=shift_x, shift_y=shift_y) 778 else: 779 return _apply_scalar_per_pixel_3D(generic_cy._median_3D, image, 780 footprint, out=out, mask=mask, 781 shift_x=shift_x, shift_y=shift_y, 782 shift_z=shift_z) 783 784 785@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 786 deprecated_version="0.19") 787def minimum(image, footprint, out=None, mask=None, 788 shift_x=False, shift_y=False, shift_z=False): 789 """Return local minimum of an image. 790 791 Parameters 792 ---------- 793 image : ([P,] M, N) ndarray (uint8, uint16) 794 Input image. 795 footprint : ndarray 796 The neighborhood expressed as an ndarray of 1's and 0's. 797 out : ([P,] M, N) array (same dtype as input) 798 If None, a new array is allocated. 799 mask : ndarray (integer or float), optional 800 Mask array that defines (>0) area of the image included in the local 801 neighborhood. If None, the complete image is used (default). 802 shift_x, shift_y, shift_z : int 803 Offset added to the footprint center point. Shift is bounded to the 804 footprint sizes (center must be inside the given footprint). 805 806 Returns 807 ------- 808 out : ([P,] M, N) ndarray (same dtype as input image) 809 Output image. 810 811 See also 812 -------- 813 skimage.morphology.erosion 814 815 Notes 816 ----- 817 The lower algorithm complexity makes `skimage.filters.rank.minimum` more 818 efficient for larger images and footprints. 819 820 Examples 821 -------- 822 >>> from skimage import data 823 >>> from skimage.morphology import disk, ball 824 >>> from skimage.filters.rank import minimum 825 >>> import numpy as np 826 >>> img = data.camera() 827 >>> rng = np.random.default_rng() 828 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 829 >>> out = minimum(img, disk(5)) 830 >>> out_vol = minimum(volume, ball(5)) 831 832 """ 833 834 np_image = np.asanyarray(image) 835 if np_image.ndim == 2: 836 return _apply_scalar_per_pixel(generic_cy._minimum, image, footprint, 837 out=out, mask=mask, 838 shift_x=shift_x, shift_y=shift_y) 839 else: 840 return _apply_scalar_per_pixel_3D(generic_cy._minimum_3D, image, 841 footprint, out=out, mask=mask, 842 shift_x=shift_x, shift_y=shift_y, 843 shift_z=shift_z) 844 845 846@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 847 deprecated_version="0.19") 848def modal(image, footprint, out=None, mask=None, 849 shift_x=False, shift_y=False, shift_z=False): 850 """Return local mode of an image. 851 852 The mode is the value that appears most often in the local histogram. 853 854 Parameters 855 ---------- 856 image : ([P,] M, N) ndarray (uint8, uint16) 857 Input image. 858 footprint : ndarray 859 The neighborhood expressed as an ndarray of 1's and 0's. 860 out : ([P,] M, N) array (same dtype as input) 861 If None, a new array is allocated. 862 mask : ndarray (integer or float), optional 863 Mask array that defines (>0) area of the image included in the local 864 neighborhood. If None, the complete image is used (default). 865 shift_x, shift_y, shift_z : int 866 Offset added to the footprint center point. Shift is bounded to the 867 footprint sizes (center must be inside the given footprint). 868 869 Returns 870 ------- 871 out : ([P,] M, N) ndarray (same dtype as input image) 872 Output image. 873 874 Examples 875 -------- 876 >>> from skimage import data 877 >>> from skimage.morphology import disk, ball 878 >>> from skimage.filters.rank import modal 879 >>> import numpy as np 880 >>> img = data.camera() 881 >>> rng = np.random.default_rng() 882 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 883 >>> out = modal(img, disk(5)) 884 >>> out_vol = modal(volume, ball(5)) 885 886 """ 887 888 np_image = np.asanyarray(image) 889 if np_image.ndim == 2: 890 return _apply_scalar_per_pixel(generic_cy._modal, image, footprint, 891 out=out, mask=mask, 892 shift_x=shift_x, shift_y=shift_y) 893 else: 894 return _apply_scalar_per_pixel_3D(generic_cy._modal_3D, image, 895 footprint, out=out, mask=mask, 896 shift_x=shift_x, shift_y=shift_y, 897 shift_z=shift_z) 898 899 900@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 901 deprecated_version="0.19") 902def enhance_contrast(image, footprint, out=None, mask=None, 903 shift_x=False, shift_y=False, shift_z=False): 904 """Enhance contrast of an image. 905 906 This replaces each pixel by the local maximum if the pixel gray value is 907 closer to the local maximum than the local minimum. Otherwise it is 908 replaced by the local minimum. 909 910 Parameters 911 ---------- 912 image : ([P,] M, N) ndarray (uint8, uint16) 913 Input image. 914 footprint : ndarray 915 The neighborhood expressed as an ndarray of 1's and 0's. 916 out : ([P,] M, N) array (same dtype as input) 917 If None, a new array is allocated. 918 mask : ndarray (integer or float), optional 919 Mask array that defines (>0) area of the image included in the local 920 neighborhood. If None, the complete image is used (default). 921 shift_x, shift_y, shift_z : int 922 Offset added to the footprint center point. Shift is bounded to the 923 footprint sizes (center must be inside the given footprint). 924 925 Returns 926 ------- 927 out : ([P,] M, N) ndarray (same dtype as input image) 928 Output image 929 930 Examples 931 -------- 932 >>> from skimage import data 933 >>> from skimage.morphology import disk, ball 934 >>> from skimage.filters.rank import enhance_contrast 935 >>> import numpy as np 936 >>> img = data.camera() 937 >>> rng = np.random.default_rng() 938 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 939 >>> out = enhance_contrast(img, disk(5)) 940 >>> out_vol = enhance_contrast(volume, ball(5)) 941 942 """ 943 944 np_image = np.asanyarray(image) 945 if np_image.ndim == 2: 946 return _apply_scalar_per_pixel(generic_cy._enhance_contrast, image, 947 footprint, out=out, mask=mask, 948 shift_x=shift_x, shift_y=shift_y) 949 else: 950 return _apply_scalar_per_pixel_3D(generic_cy._enhance_contrast_3D, 951 image, footprint, out=out, mask=mask, 952 shift_x=shift_x, shift_y=shift_y, 953 shift_z=shift_z) 954 955 956@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 957 deprecated_version="0.19") 958def pop(image, footprint, out=None, mask=None, 959 shift_x=False, shift_y=False, shift_z=False): 960 """Return the local number (population) of pixels. 961 962 The number of pixels is defined as the number of pixels which are included 963 in the footprint and the mask. 964 965 Parameters 966 ---------- 967 image : ([P,] M, N) ndarray (uint8, uint16) 968 Input image. 969 footprint : ndarray 970 The neighborhood expressed as an ndarray of 1's and 0's. 971 out : ([P,] M, N) array (same dtype as input) 972 If None, a new array is allocated. 973 mask : ndarray (integer or float), optional 974 Mask array that defines (>0) area of the image included in the local 975 neighborhood. If None, the complete image is used (default). 976 shift_x, shift_y, shift_z : int 977 Offset added to the footprint center point. Shift is bounded to the 978 footprint sizes (center must be inside the given footprint). 979 980 Returns 981 ------- 982 out : ([P,] M, N) ndarray (same dtype as input image) 983 Output image. 984 985 Examples 986 -------- 987 >>> from skimage.morphology import square, cube # Need to add 3D example 988 >>> import skimage.filters.rank as rank 989 >>> img = 255 * np.array([[0, 0, 0, 0, 0], 990 ... [0, 1, 1, 1, 0], 991 ... [0, 1, 1, 1, 0], 992 ... [0, 1, 1, 1, 0], 993 ... [0, 0, 0, 0, 0]], dtype=np.uint8) 994 >>> rank.pop(img, square(3)) 995 array([[4, 6, 6, 6, 4], 996 [6, 9, 9, 9, 6], 997 [6, 9, 9, 9, 6], 998 [6, 9, 9, 9, 6], 999 [4, 6, 6, 6, 4]], dtype=uint8) 1000 1001 """ 1002 1003 np_image = np.asanyarray(image) 1004 if np_image.ndim == 2: 1005 return _apply_scalar_per_pixel(generic_cy._pop, image, footprint, 1006 out=out, mask=mask, 1007 shift_x=shift_x, shift_y=shift_y) 1008 else: 1009 return _apply_scalar_per_pixel_3D(generic_cy._pop_3D, image, 1010 footprint, out=out, mask=mask, 1011 shift_x=shift_x, shift_y=shift_y, 1012 shift_z=shift_z) 1013 1014 1015@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 1016 deprecated_version="0.19") 1017def sum(image, footprint, out=None, mask=None, 1018 shift_x=False, shift_y=False, shift_z=False): 1019 """Return the local sum of pixels. 1020 1021 Note that the sum may overflow depending on the data type of the input 1022 array. 1023 1024 Parameters 1025 ---------- 1026 image : ([P,] M, N) ndarray (uint8, uint16) 1027 Input image. 1028 footprint : ndarray 1029 The neighborhood expressed as an ndarray of 1's and 0's. 1030 out : ([P,] M, N) array (same dtype as input) 1031 If None, a new array is allocated. 1032 mask : ndarray (integer or float), optional 1033 Mask array that defines (>0) area of the image included in the local 1034 neighborhood. If None, the complete image is used (default). 1035 shift_x, shift_y, shift_z : int 1036 Offset added to the footprint center point. Shift is bounded to the 1037 footprint sizes (center must be inside the given footprint). 1038 1039 Returns 1040 ------- 1041 out : ([P,] M, N) ndarray (same dtype as input image) 1042 Output image. 1043 1044 Examples 1045 -------- 1046 >>> from skimage.morphology import square, cube # Need to add 3D example 1047 >>> import skimage.filters.rank as rank # Cube seems to fail but 1048 >>> img = np.array([[0, 0, 0, 0, 0], # Ball can pass 1049 ... [0, 1, 1, 1, 0], 1050 ... [0, 1, 1, 1, 0], 1051 ... [0, 1, 1, 1, 0], 1052 ... [0, 0, 0, 0, 0]], dtype=np.uint8) 1053 >>> rank.sum(img, square(3)) 1054 array([[1, 2, 3, 2, 1], 1055 [2, 4, 6, 4, 2], 1056 [3, 6, 9, 6, 3], 1057 [2, 4, 6, 4, 2], 1058 [1, 2, 3, 2, 1]], dtype=uint8) 1059 1060 """ 1061 1062 np_image = np.asanyarray(image) 1063 if np_image.ndim == 2: 1064 return _apply_scalar_per_pixel(generic_cy._sum, image, footprint, 1065 out=out, mask=mask, 1066 shift_x=shift_x, shift_y=shift_y) 1067 else: 1068 return _apply_scalar_per_pixel_3D(generic_cy._sum_3D, image, 1069 footprint, out=out, mask=mask, 1070 shift_x=shift_x, shift_y=shift_y, 1071 shift_z=shift_z) 1072 1073 1074@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 1075 deprecated_version="0.19") 1076def threshold(image, footprint, out=None, mask=None, 1077 shift_x=False, shift_y=False, shift_z=False): 1078 """Local threshold of an image. 1079 1080 The resulting binary mask is True if the gray value of the center pixel is 1081 greater than the local mean. 1082 1083 Parameters 1084 ---------- 1085 image : ([P,] M, N) ndarray (uint8, uint16) 1086 Input image. 1087 footprint : ndarray 1088 The neighborhood expressed as an ndarray of 1's and 0's. 1089 out : ([P,] M, N) array (same dtype as input) 1090 If None, a new array is allocated. 1091 mask : ndarray (integer or float), optional 1092 Mask array that defines (>0) area of the image included in the local 1093 neighborhood. If None, the complete image is used (default). 1094 shift_x, shift_y, shift_z : int 1095 Offset added to the footprint center point. Shift is bounded to the 1096 footprint sizes (center must be inside the given footprint). 1097 1098 Returns 1099 ------- 1100 out : ([P,] M, N) ndarray (same dtype as input image) 1101 Output image. 1102 1103 Examples 1104 -------- 1105 >>> from skimage.morphology import square, cube # Need to add 3D example 1106 >>> from skimage.filters.rank import threshold 1107 >>> img = 255 * np.array([[0, 0, 0, 0, 0], 1108 ... [0, 1, 1, 1, 0], 1109 ... [0, 1, 1, 1, 0], 1110 ... [0, 1, 1, 1, 0], 1111 ... [0, 0, 0, 0, 0]], dtype=np.uint8) 1112 >>> threshold(img, square(3)) 1113 array([[0, 0, 0, 0, 0], 1114 [0, 1, 1, 1, 0], 1115 [0, 1, 0, 1, 0], 1116 [0, 1, 1, 1, 0], 1117 [0, 0, 0, 0, 0]], dtype=uint8) 1118 1119 """ 1120 1121 np_image = np.asanyarray(image) 1122 if np_image.ndim == 2: 1123 return _apply_scalar_per_pixel(generic_cy._threshold, image, footprint, 1124 out=out, mask=mask, 1125 shift_x=shift_x, shift_y=shift_y) 1126 else: 1127 return _apply_scalar_per_pixel_3D(generic_cy._threshold_3D, image, 1128 footprint, out=out, mask=mask, 1129 shift_x=shift_x, shift_y=shift_y, 1130 shift_z=shift_z) 1131 1132 1133@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 1134 deprecated_version="0.19") 1135def noise_filter(image, footprint, out=None, mask=None, 1136 shift_x=False, shift_y=False, shift_z=False): 1137 """Noise feature. 1138 1139 Parameters 1140 ---------- 1141 image : ([P,] M, N) ndarray (uint8, uint16) 1142 Input image. 1143 footprint : ndarray 1144 The neighborhood expressed as an ndarray of 1's and 0's. 1145 out : ([P,] M, N) array (same dtype as input) 1146 If None, a new array is allocated. 1147 mask : ndarray (integer or float), optional 1148 Mask array that defines (>0) area of the image included in the local 1149 neighborhood. If None, the complete image is used (default). 1150 shift_x, shift_y, shift_z : int 1151 Offset added to the footprint center point. Shift is bounded to the 1152 footprint sizes (center must be inside the given footprint). 1153 1154 References 1155 ---------- 1156 .. [1] N. Hashimoto et al. Referenceless image quality evaluation 1157 for whole slide imaging. J Pathol Inform 2012;3:9. 1158 1159 Returns 1160 ------- 1161 out : ([P,] M, N) ndarray (same dtype as input image) 1162 Output image. 1163 1164 Examples 1165 -------- 1166 >>> from skimage import data 1167 >>> from skimage.morphology import disk, ball 1168 >>> from skimage.filters.rank import noise_filter 1169 >>> import numpy as np 1170 >>> img = data.camera() 1171 >>> rng = np.random.default_rng() 1172 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 1173 >>> out = noise_filter(img, disk(5)) 1174 >>> out_vol = noise_filter(volume, ball(5)) 1175 1176 """ 1177 1178 np_image = np.asanyarray(image) 1179 if np_image.ndim == 2: 1180 # ensure that the central pixel in the footprint is empty 1181 centre_r = int(footprint.shape[0] / 2) + shift_y 1182 centre_c = int(footprint.shape[1] / 2) + shift_x 1183 # make a local copy 1184 footprint_cpy = footprint.copy() 1185 footprint_cpy[centre_r, centre_c] = 0 1186 1187 return _apply_scalar_per_pixel(generic_cy._noise_filter, image, 1188 footprint_cpy, out=out, mask=mask, 1189 shift_x=shift_x, shift_y=shift_y) 1190 else: 1191 # ensure that the central pixel in the footprint is empty 1192 centre_r = int(footprint.shape[0] / 2) + shift_y 1193 centre_c = int(footprint.shape[1] / 2) + shift_x 1194 centre_z = int(footprint.shape[2] / 2) + shift_z 1195 # make a local copy 1196 footprint_cpy = footprint.copy() 1197 footprint_cpy[centre_r, centre_c, centre_z] = 0 1198 1199 return _apply_scalar_per_pixel_3D(generic_cy._noise_filter_3D, 1200 image, footprint_cpy, out=out, 1201 mask=mask, shift_x=shift_x, 1202 shift_y=shift_y, shift_z=shift_z) 1203 1204 1205@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 1206 deprecated_version="0.19") 1207def entropy(image, footprint, out=None, mask=None, 1208 shift_x=False, shift_y=False, shift_z=False): 1209 """Local entropy. 1210 1211 The entropy is computed using base 2 logarithm i.e. the filter returns the 1212 minimum number of bits needed to encode the local gray level 1213 distribution. 1214 1215 Parameters 1216 ---------- 1217 image : ([P,] M, N) ndarray (uint8, uint16) 1218 Input image. 1219 footprint : ndarray 1220 The neighborhood expressed as an ndarray of 1's and 0's. 1221 out : ([P,] M, N) array (same dtype as input) 1222 If None, a new array is allocated. 1223 mask : ndarray (integer or float), optional 1224 Mask array that defines (>0) area of the image included in the local 1225 neighborhood. If None, the complete image is used (default). 1226 shift_x, shift_y, shift_z : int 1227 Offset added to the footprint center point. Shift is bounded to the 1228 footprint sizes (center must be inside the given footprint). 1229 1230 Returns 1231 ------- 1232 out : ([P,] M, N) ndarray (float) 1233 Output image. 1234 1235 References 1236 ---------- 1237 .. [1] `https://en.wikipedia.org/wiki/Entropy_(information_theory) <https://en.wikipedia.org/wiki/Entropy_(information_theory)>`_ 1238 1239 Examples 1240 -------- 1241 >>> from skimage import data 1242 >>> from skimage.filters.rank import entropy 1243 >>> from skimage.morphology import disk, ball 1244 >>> import numpy as np 1245 >>> img = data.camera() 1246 >>> rng = np.random.default_rng() 1247 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 1248 >>> ent = entropy(img, disk(5)) 1249 >>> ent_vol = entropy(volume, ball(5)) 1250 1251 """ 1252 1253 np_image = np.asanyarray(image) 1254 if np_image.ndim == 2: 1255 return _apply_scalar_per_pixel(generic_cy._entropy, image, footprint, 1256 out=out, mask=mask, 1257 shift_x=shift_x, shift_y=shift_y, 1258 out_dtype=np.double) 1259 else: 1260 return _apply_scalar_per_pixel_3D(generic_cy._entropy_3D, image, 1261 footprint, out=out, mask=mask, 1262 shift_x=shift_x, shift_y=shift_y, 1263 shift_z=shift_z, out_dtype=np.double) 1264 1265 1266@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 1267 deprecated_version="0.19") 1268def otsu(image, footprint, out=None, mask=None, 1269 shift_x=False, shift_y=False, shift_z=False): 1270 """Local Otsu's threshold value for each pixel. 1271 1272 Parameters 1273 ---------- 1274 image : ([P,] M, N) ndarray (uint8, uint16) 1275 Input image. 1276 footprint : ndarray 1277 The neighborhood expressed as an ndarray of 1's and 0's. 1278 out : ([P,] M, N) array (same dtype as input) 1279 If None, a new array is allocated. 1280 mask : ndarray (integer or float), optional 1281 Mask array that defines (>0) area of the image included in the local 1282 neighborhood. If None, the complete image is used (default). 1283 shift_x, shift_y, shift_z : int 1284 Offset added to the footprint center point. Shift is bounded to the 1285 footprint sizes (center must be inside the given footprint). 1286 1287 Returns 1288 ------- 1289 out : ([P,] M, N) ndarray (same dtype as input image) 1290 Output image. 1291 1292 References 1293 ---------- 1294 .. [1] https://en.wikipedia.org/wiki/Otsu's_method 1295 1296 Examples 1297 -------- 1298 >>> from skimage import data 1299 >>> from skimage.filters.rank import otsu 1300 >>> from skimage.morphology import disk, ball 1301 >>> import numpy as np 1302 >>> img = data.camera() 1303 >>> rng = np.random.default_rng() 1304 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 1305 >>> local_otsu = otsu(img, disk(5)) 1306 >>> thresh_image = img >= local_otsu 1307 >>> local_otsu_vol = otsu(volume, ball(5)) 1308 >>> thresh_image_vol = volume >= local_otsu_vol 1309 1310 """ 1311 1312 np_image = np.asanyarray(image) 1313 if np_image.ndim == 2: 1314 return _apply_scalar_per_pixel(generic_cy._otsu, image, footprint, 1315 out=out, mask=mask, 1316 shift_x=shift_x, shift_y=shift_y) 1317 else: 1318 return _apply_scalar_per_pixel_3D(generic_cy._otsu_3D, image, 1319 footprint, out=out, mask=mask, 1320 shift_x=shift_x, shift_y=shift_y, 1321 shift_z=shift_z) 1322 1323 1324@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 1325 deprecated_version="0.19") 1326def windowed_histogram(image, footprint, out=None, mask=None, 1327 shift_x=False, shift_y=False, n_bins=None): 1328 """Normalized sliding window histogram 1329 1330 Parameters 1331 ---------- 1332 image : 2-D array (integer or float) 1333 Input image. 1334 footprint : 2-D array (integer or float) 1335 The neighborhood expressed as a 2-D array of 1's and 0's. 1336 out : 2-D array (integer or float), optional 1337 If None, a new array is allocated. 1338 mask : ndarray (integer or float), optional 1339 Mask array that defines (>0) area of the image included in the local 1340 neighborhood. If None, the complete image is used (default). 1341 shift_x, shift_y : int, optional 1342 Offset added to the footprint center point. Shift is bounded to the 1343 footprint sizes (center must be inside the given footprint). 1344 n_bins : int or None 1345 The number of histogram bins. Will default to ``image.max() + 1`` 1346 if None is passed. 1347 1348 Returns 1349 ------- 1350 out : 3-D array (float) 1351 Array of dimensions (H,W,N), where (H,W) are the dimensions of the 1352 input image and N is n_bins or ``image.max() + 1`` if no value is 1353 provided as a parameter. Effectively, each pixel is a N-D feature 1354 vector that is the histogram. The sum of the elements in the feature 1355 vector will be 1, unless no pixels in the window were covered by both 1356 footprint and mask, in which case all elements will be 0. 1357 1358 Examples 1359 -------- 1360 >>> from skimage import data 1361 >>> from skimage.filters.rank import windowed_histogram 1362 >>> from skimage.morphology import disk, ball 1363 >>> import numpy as np 1364 >>> img = data.camera() 1365 >>> rng = np.random.default_rng() 1366 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 1367 >>> hist_img = windowed_histogram(img, disk(5)) 1368 1369 """ 1370 1371 if n_bins is None: 1372 n_bins = int(image.max()) + 1 1373 1374 return _apply_vector_per_pixel(generic_cy._windowed_hist, image, footprint, 1375 out=out, mask=mask, 1376 shift_x=shift_x, shift_y=shift_y, 1377 out_dtype=np.double, 1378 pixel_size=n_bins) 1379 1380 1381@deprecate_kwarg(kwarg_mapping={'selem': 'footprint'}, removed_version="1.0", 1382 deprecated_version="0.19") 1383def majority(image, footprint, *, out=None, mask=None, 1384 shift_x=False, shift_y=False, shift_z=False): 1385 """Assign to each pixel the most common value within its neighborhood. 1386 1387 Parameters 1388 ---------- 1389 image : ndarray 1390 Image array (uint8, uint16 array). 1391 footprint : 2-D array (integer or float) 1392 The neighborhood expressed as a 2-D array of 1's and 0's. 1393 out : ndarray (integer or float), optional 1394 If None, a new array will be allocated. 1395 mask : ndarray (integer or float), optional 1396 Mask array that defines (>0) area of the image included in the local 1397 neighborhood. If None, the complete image is used (default). 1398 shift_x, shift_y : int, optional 1399 Offset added to the footprint center point. Shift is bounded to the 1400 footprint sizes (center must be inside the given footprint). 1401 1402 Returns 1403 ------- 1404 out : 2-D array (same dtype as input image) 1405 Output image. 1406 1407 Examples 1408 -------- 1409 >>> from skimage import data 1410 >>> from skimage.filters.rank import majority 1411 >>> from skimage.morphology import disk, ball 1412 >>> import numpy as np 1413 >>> img = data.camera() 1414 >>> rng = np.random.default_rng() 1415 >>> volume = rng.integers(0, 255, size=(10,10,10), dtype=np.uint8) 1416 >>> maj_img = majority(img, disk(5)) 1417 >>> maj_img_vol = majority(volume, ball(5)) 1418 1419 """ 1420 1421 np_image = np.asanyarray(image) 1422 if np_image.ndim == 2: 1423 return _apply_scalar_per_pixel(generic_cy._majority, image, 1424 footprint, out=out, mask=mask, 1425 shift_x=shift_x, shift_y=shift_y) 1426 else: 1427 return _apply_scalar_per_pixel_3D(generic_cy._majority_3D, 1428 image, footprint, out=out, mask=mask, 1429 shift_x=shift_x, shift_y=shift_y, 1430 shift_z=shift_z) 1431