Repository: scikit-image/scikit-image

Issue:
Odd keyword name `min_size` for morphology's `remove_small_holes`
Should the `min_size` parameter be `max_size`, or something else entirely?  It's not a very intuitive naming.  At worst, we should document this well.

/cc @mcquin


Discussion:
I think `max_size` is more intuitive than `min_size`. When I read `remove_small_x`, I think about removing x up to `max_size` rather than keeping x above `min_size`.

The word "size" is another point of confusion. It could help to define "size" as "total pixels".
I think that as `remove_small_holes` effectively _filters_ out the blobs based upon their area, a **threshold**-themed keyword name would make the most sense, such as `area_threshold`.

Resolving patch:
diff --git a/skimage/morphology/misc.py b/skimage/morphology/misc.py
--- a/skimage/morphology/misc.py
+++ b/skimage/morphology/misc.py
@@ -1,3 +1,4 @@
+"""Miscellaneous morphology functions."""
 import numpy as np
 import functools
 from scipy import ndimage as ndi
@@ -29,6 +30,7 @@ def default_selem(func):
     func_out : function
         The function, using a default structuring element of same dimension
         as the input image with connectivity 1.
+
     """
     @functools.wraps(func)
     def func_out(image, selem=None, *args, **kwargs):
@@ -38,12 +40,14 @@ def func_out(image, selem=None, *args, **kwargs):
 
     return func_out
 
+
 def _check_dtype_supported(ar):
     # Should use `issubdtype` for bool below, but there's a bug in numpy 1.7
     if not (ar.dtype == bool or np.issubdtype(ar.dtype, np.integer)):
         raise TypeError("Only bool or integer image types are supported. "
                         "Got %s." % ar.dtype)
 
+
 def remove_small_objects(ar, min_size=64, connectivity=1, in_place=False):
     """Remove connected components smaller than the specified size.
 
@@ -92,6 +96,7 @@ def remove_small_objects(ar, min_size=64, connectivity=1, in_place=False):
     >>> d = morphology.remove_small_objects(a, 6, in_place=True)
     >>> d is a
     True
+
     """
     # Raising type error if not int or bool
     _check_dtype_supported(ar)
@@ -128,21 +133,25 @@ def remove_small_objects(ar, min_size=64, connectivity=1, in_place=False):
 
     return out
 
-def remove_small_holes(ar, min_size=64, connectivity=1, in_place=False):
+
+def remove_small_holes(ar, area_threshold=64, connectivity=1, in_place=False,
+                       min_size=None):
     """Remove continguous holes smaller than the specified size.
 
     Parameters
     ----------
     ar : ndarray (arbitrary shape, int or bool type)
         The array containing the connected components of interest.
-    min_size : int, optional (default: 64)
-        The hole component size.
+    area_threshold : int, optional (default: 64)
+        The maximum area, in pixels, of a contiguous hole that will be filled.
+        Replaces `min_size`.
     connectivity : int, {1, 2, ..., ar.ndim}, optional (default: 1)
         The connectivity defining the neighborhood of a pixel.
     in_place : bool, optional (default: False)
         If `True`, remove the connected components in the input array itself.
         Otherwise, make a copy.
 
+
     Raises
     ------
     TypeError
@@ -180,35 +189,40 @@ def remove_small_holes(ar, min_size=64, connectivity=1, in_place=False):
 
     Notes
     -----
-
     If the array type is int, it is assumed that it contains already-labeled
     objects. The labels are not kept in the output image (this function always
     outputs a bool image). It is suggested that labeling is completed after
     using this function.
+
     """
     _check_dtype_supported(ar)
 
-    #Creates warning if image is an integer image
+    # Creates warning if image is an integer image
     if ar.dtype != bool:
         warn("Any labeled images will be returned as a boolean array. "
              "Did you mean to use a boolean array?", UserWarning)
 
+    if min_size is not None:
+        warn("the min_size argument is deprecated and will be removed in " +
+             "0.16. Use area_threshold instead.")
+        area_threshold = min_size
+
     if in_place:
         out = ar
     else:
         out = ar.copy()
 
-    #Creating the inverse of ar
+    # Creating the inverse of ar
     if in_place:
-        out = np.logical_not(out,out)
+        out = np.logical_not(out, out)
     else:
         out = np.logical_not(out)
 
-    #removing small objects from the inverse of ar
-    out = remove_small_objects(out, min_size, connectivity, in_place)
+    # removing small objects from the inverse of ar
+    out = remove_small_objects(out, area_threshold, connectivity, in_place)
 
     if in_place:
-        out = np.logical_not(out,out)
+        out = np.logical_not(out, out)
     else:
         out = np.logical_not(out)
 


Test patch:
diff --git a/skimage/morphology/tests/test_misc.py b/skimage/morphology/tests/test_misc.py
--- a/skimage/morphology/tests/test_misc.py
+++ b/skimage/morphology/tests/test_misc.py
@@ -98,7 +98,7 @@ def test_one_connectivity_holes():
                          [0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
                          [0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
                          [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], np.bool_)
-    observed = remove_small_holes(test_holes_image, min_size=3)
+    observed = remove_small_holes(test_holes_image, area_threshold=3)
     assert_array_equal(observed, expected)
 
 
@@ -111,12 +111,14 @@ def test_two_connectivity_holes():
                          [0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
                          [0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
                          [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], np.bool_)
-    observed = remove_small_holes(test_holes_image, min_size=3, connectivity=2)
+    observed = remove_small_holes(test_holes_image, area_threshold=3,
+                                  connectivity=2)
     assert_array_equal(observed, expected)
 
 
 def test_in_place_holes():
-    observed = remove_small_holes(test_holes_image, min_size=3, in_place=True)
+    observed = remove_small_holes(test_holes_image, area_threshold=3,
+                                  in_place=True)
     assert_equal(observed is test_holes_image, True,
                  "remove_small_holes in_place argument failed.")
 
@@ -139,7 +141,7 @@ def test_labeled_image_holes():
                          [0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
                          [0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
                          [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], dtype=np.bool_)
-    observed = remove_small_holes(labeled_holes_image, min_size=3)
+    observed = remove_small_holes(labeled_holes_image, area_threshold=3)
     assert_array_equal(observed, expected)
 
 
@@ -161,7 +163,7 @@ def test_uint_image_holes():
                          [0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
                          [0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
                          [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], dtype=np.bool_)
-    observed = remove_small_holes(labeled_holes_image, min_size=3)
+    observed = remove_small_holes(labeled_holes_image, area_threshold=3)
     assert_array_equal(observed, expected)
 
 
@@ -176,7 +178,7 @@ def test_label_warning_holes():
                                     [0, 0, 0, 0, 0, 0, 0, 2, 2, 2]],
                                    dtype=np.int_)
     with expected_warnings(['use a boolean array?']):
-        remove_small_holes(labeled_holes_image, min_size=3)
+        remove_small_holes(labeled_holes_image, area_threshold=3)
 
 
 def test_float_input_holes():