We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`min_size` is not strictly conformed in the implementation of felzenszwalb
## Description

With `min_size` specified, there're still some segments with sizes that less than it. I don't know if it is an inherent flaw of the algorithm.
## Way to reproduce

```
>>> I = skimage.io.imread('dragonbaby.jpg')
>>> fz = felzenszwalb(I, scale=300, sigma=0.8, min_size=80)
>>> (fz==9).sum()
1
```

![dragonbaby](https://cloud.githubusercontent.com/assets/7010007/14789864/39cd4a56-0ad4-11e6-88a4-235ebdd1e2fd.jpg)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `skimage/segmentation/_felzenszwalb.py`
Content:
```
1 import numpy as np
2 
3 from .._shared.utils import warn
4 from ._felzenszwalb_cy import _felzenszwalb_grey
5 
6 
7 def felzenszwalb(image, scale=1, sigma=0.8, min_size=20):
8     """Computes Felsenszwalb's efficient graph based image segmentation.
9 
10     Produces an oversegmentation of a multichannel (i.e. RGB) image
11     using a fast, minimum spanning tree based clustering on the image grid.
12     The parameter ``scale`` sets an observation level. Higher scale means
13     less and larger segments. ``sigma`` is the diameter of a Gaussian kernel,
14     used for smoothing the image prior to segmentation.
15 
16     The number of produced segments as well as their size can only be
17     controlled indirectly through ``scale``. Segment size within an image can
18     vary greatly depending on local contrast.
19 
20     For RGB images, the algorithm computes a separate segmentation for each
21     channel and then combines these. The combined segmentation is the
22     intersection of the separate segmentations on the color channels.
23 
24     Parameters
25     ----------
26     image : (width, height, 3) or (width, height) ndarray
27         Input image.
28     scale : float
29         Free parameter. Higher means larger clusters.
30     sigma : float
31         Width of Gaussian kernel used in preprocessing.
32     min_size : int
33         Minimum component size. Enforced using postprocessing.
34 
35     Returns
36     -------
37     segment_mask : (width, height) ndarray
38         Integer mask indicating segment labels.
39 
40     References
41     ----------
42     .. [1] Efficient graph-based image segmentation, Felzenszwalb, P.F. and
43            Huttenlocher, D.P.  International Journal of Computer Vision, 2004
44 
45     Examples
46     --------
47     >>> from skimage.segmentation import felzenszwalb
48     >>> from skimage.data import coffee
49     >>> img = coffee()
50     >>> segments = felzenszwalb(img, scale=3.0, sigma=0.95, min_size=5)
51     """
52 
53     if image.ndim == 2:
54         # assume single channel image
55         return _felzenszwalb_grey(image, scale=scale, sigma=sigma,
56                                   min_size=min_size)
57 
58     elif image.ndim != 3:
59         raise ValueError("Felzenswalb segmentation can only operate on RGB and"
60                          " grey images, but input array of ndim %d given."
61                          % image.ndim)
62 
63     # assume we got 2d image with multiple channels
64     n_channels = image.shape[2]
65     if n_channels != 3:
66         warn("Got image with %d channels. Is that really what you"
67              " wanted?" % image.shape[2])
68     segmentations = []
69     # compute quickshift for each channel
70     for c in range(n_channels):
71         channel = np.ascontiguousarray(image[:, :, c])
72         s = _felzenszwalb_grey(channel, scale=scale, sigma=sigma,
73                                min_size=min_size)
74         segmentations.append(s)
75 
76     # put pixels in same segment only if in the same segment in all images
77     # we do this by combining the channels to one number
78     n0 = segmentations[0].max() + 1
79     n1 = segmentations[1].max() + 1
80     segmentation = (segmentations[0] + segmentations[1] * n0
81                     + segmentations[2] * n0 * n1)
82     # make segment labels consecutive numbers starting at 0
83     labels = np.unique(segmentation, return_inverse=True)[1]
84     return labels.reshape(image.shape[:2])
85
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/skimage/segmentation/_felzenszwalb.py b/skimage/segmentation/_felzenszwalb.py
--- a/skimage/segmentation/_felzenszwalb.py
+++ b/skimage/segmentation/_felzenszwalb.py
@@ -1,7 +1,7 @@
 import numpy as np
 
 from .._shared.utils import warn
-from ._felzenszwalb_cy import _felzenszwalb_grey
+from ._felzenszwalb_cy import _felzenszwalb_cython
 
 
 def felzenszwalb(image, scale=1, sigma=0.8, min_size=20):
@@ -17,9 +17,8 @@
     controlled indirectly through ``scale``. Segment size within an image can
     vary greatly depending on local contrast.
 
-    For RGB images, the algorithm computes a separate segmentation for each
-    channel and then combines these. The combined segmentation is the
-    intersection of the separate segmentations on the color channels.
+    For RGB images, the algorithm uses the euclidean distance between pixels in
+    color space.
 
     Parameters
     ----------
@@ -50,35 +49,6 @@
     >>> segments = felzenszwalb(img, scale=3.0, sigma=0.95, min_size=5)
     """
 
-    if image.ndim == 2:
-        # assume single channel image
-        return _felzenszwalb_grey(image, scale=scale, sigma=sigma,
-                                  min_size=min_size)
-
-    elif image.ndim != 3:
-        raise ValueError("Felzenswalb segmentation can only operate on RGB and"
-                         " grey images, but input array of ndim %d given."
-                         % image.ndim)
-
-    # assume we got 2d image with multiple channels
-    n_channels = image.shape[2]
-    if n_channels != 3:
-        warn("Got image with %d channels. Is that really what you"
-             " wanted?" % image.shape[2])
-    segmentations = []
-    # compute quickshift for each channel
-    for c in range(n_channels):
-        channel = np.ascontiguousarray(image[:, :, c])
-        s = _felzenszwalb_grey(channel, scale=scale, sigma=sigma,
-                               min_size=min_size)
-        segmentations.append(s)
-
-    # put pixels in same segment only if in the same segment in all images
-    # we do this by combining the channels to one number
-    n0 = segmentations[0].max() + 1
-    n1 = segmentations[1].max() + 1
-    segmentation = (segmentations[0] + segmentations[1] * n0
-                    + segmentations[2] * n0 * n1)
-    # make segment labels consecutive numbers starting at 0
-    labels = np.unique(segmentation, return_inverse=True)[1]
-    return labels.reshape(image.shape[:2])
+    image = np.atleast_3d(image)
+    return _felzenszwalb_cython(image, scale=scale, sigma=sigma,
+                                min_size=min_size)

{"golden_diff": "diff --git a/skimage/segmentation/_felzenszwalb.py b/skimage/segmentation/_felzenszwalb.py\n--- a/skimage/segmentation/_felzenszwalb.py\n+++ b/skimage/segmentation/_felzenszwalb.py\n@@ -1,7 +1,7 @@\n import numpy as np\n \n from .._shared.utils import warn\n-from ._felzenszwalb_cy import _felzenszwalb_grey\n+from ._felzenszwalb_cy import _felzenszwalb_cython\n \n \n def felzenszwalb(image, scale=1, sigma=0.8, min_size=20):\n@@ -17,9 +17,8 @@\n     controlled indirectly through ``scale``. Segment size within an image can\n     vary greatly depending on local contrast.\n \n-    For RGB images, the algorithm computes a separate segmentation for each\n-    channel and then combines these. The combined segmentation is the\n-    intersection of the separate segmentations on the color channels.\n+    For RGB images, the algorithm uses the euclidean distance between pixels in\n+    color space.\n \n     Parameters\n     ----------\n@@ -50,35 +49,6 @@\n     >>> segments = felzenszwalb(img, scale=3.0, sigma=0.95, min_size=5)\n     \"\"\"\n \n-    if image.ndim == 2:\n-        # assume single channel image\n-        return _felzenszwalb_grey(image, scale=scale, sigma=sigma,\n-                                  min_size=min_size)\n-\n-    elif image.ndim != 3:\n-        raise ValueError(\"Felzenswalb segmentation can only operate on RGB and\"\n-                         \" grey images, but input array of ndim %d given.\"\n-                         % image.ndim)\n-\n-    # assume we got 2d image with multiple channels\n-    n_channels = image.shape[2]\n-    if n_channels != 3:\n-        warn(\"Got image with %d channels. Is that really what you\"\n-             \" wanted?\" % image.shape[2])\n-    segmentations = []\n-    # compute quickshift for each channel\n-    for c in range(n_channels):\n-        channel = np.ascontiguousarray(image[:, :, c])\n-        s = _felzenszwalb_grey(channel, scale=scale, sigma=sigma,\n-                               min_size=min_size)\n-        segmentations.append(s)\n-\n-    # put pixels in same segment only if in the same segment in all images\n-    # we do this by combining the channels to one number\n-    n0 = segmentations[0].max() + 1\n-    n1 = segmentations[1].max() + 1\n-    segmentation = (segmentations[0] + segmentations[1] * n0\n-                    + segmentations[2] * n0 * n1)\n-    # make segment labels consecutive numbers starting at 0\n-    labels = np.unique(segmentation, return_inverse=True)[1]\n-    return labels.reshape(image.shape[:2])\n+    image = np.atleast_3d(image)\n+    return _felzenszwalb_cython(image, scale=scale, sigma=sigma,\n+                                min_size=min_size)\n", "issue": "`min_size` is not strictly conformed in the implementation of felzenszwalb\n## Description\n\nWith `min_size` specified, there're still some segments with sizes that less than it. I don't know if it is an inherent flaw of the algorithm.\n## Way to reproduce\n\n```\n>>> I = skimage.io.imread('dragonbaby.jpg')\n>>> fz = felzenszwalb(I, scale=300, sigma=0.8, min_size=80)\n>>> (fz==9).sum()\n1\n```\n\n![dragonbaby](https://cloud.githubusercontent.com/assets/7010007/14789864/39cd4a56-0ad4-11e6-88a4-235ebdd1e2fd.jpg)\n\n", "before_files": [{"content": "import numpy as np\n\nfrom .._shared.utils import warn\nfrom ._felzenszwalb_cy import _felzenszwalb_grey\n\n\ndef felzenszwalb(image, scale=1, sigma=0.8, min_size=20):\n    \"\"\"Computes Felsenszwalb's efficient graph based image segmentation.\n\n    Produces an oversegmentation of a multichannel (i.e. RGB) image\n    using a fast, minimum spanning tree based clustering on the image grid.\n    The parameter ``scale`` sets an observation level. Higher scale means\n    less and larger segments. ``sigma`` is the diameter of a Gaussian kernel,\n    used for smoothing the image prior to segmentation.\n\n    The number of produced segments as well as their size can only be\n    controlled indirectly through ``scale``. Segment size within an image can\n    vary greatly depending on local contrast.\n\n    For RGB images, the algorithm computes a separate segmentation for each\n    channel and then combines these. The combined segmentation is the\n    intersection of the separate segmentations on the color channels.\n\n    Parameters\n    ----------\n    image : (width, height, 3) or (width, height) ndarray\n        Input image.\n    scale : float\n        Free parameter. Higher means larger clusters.\n    sigma : float\n        Width of Gaussian kernel used in preprocessing.\n    min_size : int\n        Minimum component size. Enforced using postprocessing.\n\n    Returns\n    -------\n    segment_mask : (width, height) ndarray\n        Integer mask indicating segment labels.\n\n    References\n    ----------\n    .. [1] Efficient graph-based image segmentation, Felzenszwalb, P.F. and\n           Huttenlocher, D.P.  International Journal of Computer Vision, 2004\n\n    Examples\n    --------\n    >>> from skimage.segmentation import felzenszwalb\n    >>> from skimage.data import coffee\n    >>> img = coffee()\n    >>> segments = felzenszwalb(img, scale=3.0, sigma=0.95, min_size=5)\n    \"\"\"\n\n    if image.ndim == 2:\n        # assume single channel image\n        return _felzenszwalb_grey(image, scale=scale, sigma=sigma,\n                                  min_size=min_size)\n\n    elif image.ndim != 3:\n        raise ValueError(\"Felzenswalb segmentation can only operate on RGB and\"\n                         \" grey images, but input array of ndim %d given.\"\n                         % image.ndim)\n\n    # assume we got 2d image with multiple channels\n    n_channels = image.shape[2]\n    if n_channels != 3:\n        warn(\"Got image with %d channels. Is that really what you\"\n             \" wanted?\" % image.shape[2])\n    segmentations = []\n    # compute quickshift for each channel\n    for c in range(n_channels):\n        channel = np.ascontiguousarray(image[:, :, c])\n        s = _felzenszwalb_grey(channel, scale=scale, sigma=sigma,\n                               min_size=min_size)\n        segmentations.append(s)\n\n    # put pixels in same segment only if in the same segment in all images\n    # we do this by combining the channels to one number\n    n0 = segmentations[0].max() + 1\n    n1 = segmentations[1].max() + 1\n    segmentation = (segmentations[0] + segmentations[1] * n0\n                    + segmentations[2] * n0 * n1)\n    # make segment labels consecutive numbers starting at 0\n    labels = np.unique(segmentation, return_inverse=True)[1]\n    return labels.reshape(image.shape[:2])\n", "path": "skimage/segmentation/_felzenszwalb.py"}], "after_files": [{"content": "import numpy as np\n\nfrom .._shared.utils import warn\nfrom ._felzenszwalb_cy import _felzenszwalb_cython\n\n\ndef felzenszwalb(image, scale=1, sigma=0.8, min_size=20):\n    \"\"\"Computes Felsenszwalb's efficient graph based image segmentation.\n\n    Produces an oversegmentation of a multichannel (i.e. RGB) image\n    using a fast, minimum spanning tree based clustering on the image grid.\n    The parameter ``scale`` sets an observation level. Higher scale means\n    less and larger segments. ``sigma`` is the diameter of a Gaussian kernel,\n    used for smoothing the image prior to segmentation.\n\n    The number of produced segments as well as their size can only be\n    controlled indirectly through ``scale``. Segment size within an image can\n    vary greatly depending on local contrast.\n\n    For RGB images, the algorithm uses the euclidean distance between pixels in\n    color space.\n\n    Parameters\n    ----------\n    image : (width, height, 3) or (width, height) ndarray\n        Input image.\n    scale : float\n        Free parameter. Higher means larger clusters.\n    sigma : float\n        Width of Gaussian kernel used in preprocessing.\n    min_size : int\n        Minimum component size. Enforced using postprocessing.\n\n    Returns\n    -------\n    segment_mask : (width, height) ndarray\n        Integer mask indicating segment labels.\n\n    References\n    ----------\n    .. [1] Efficient graph-based image segmentation, Felzenszwalb, P.F. and\n           Huttenlocher, D.P.  International Journal of Computer Vision, 2004\n\n    Examples\n    --------\n    >>> from skimage.segmentation import felzenszwalb\n    >>> from skimage.data import coffee\n    >>> img = coffee()\n    >>> segments = felzenszwalb(img, scale=3.0, sigma=0.95, min_size=5)\n    \"\"\"\n\n    image = np.atleast_3d(image)\n    return _felzenszwalb_cython(image, scale=scale, sigma=sigma,\n                                min_size=min_size)\n", "path": "skimage/segmentation/_felzenszwalb.py"}]}