Repository: scikit-image/scikit-image

Issue:
Daisy example faulty output
If you look at the example in http://scikit-image.org/docs/dev/auto_examples/plot_daisy.html:

![](http://scikit-image.org/docs/dev/_images/plot_daisy_1.png)

it seems some pixel are "missing". When you run the example localy, you don't have such problem but the overall quality of the circles and line is not so good I would say (circles appears very roughly antialiased).



Discussion:
@rougier I think this is an issue with Matplotlib, which resamples images when displaying. If you save the `descs_img`, do you see the same issue?

When I save the whole fig, the circles are ok (but still "badly" drawn).

@tacaswell, could you comment on issue, please?

Is there any way to visualize the daisies using circle and line objects?

I think the problem is that `desc_img` is an image full of one pixel wide features which is interacting badly with the aliasing when it is raterized on to the canvas.

On a phone so hard to dig much deeper.

Yes, thanks.
I don't know if someone uses `descs_img` besides this example, but we can for sure re-implement it using `matplotlib` primitives.


Resolving patch:
diff --git a/skimage/draw/draw.py b/skimage/draw/draw.py
--- a/skimage/draw/draw.py
+++ b/skimage/draw/draw.py
@@ -125,7 +125,7 @@ def circle(r, c, radius, shape=None):
     return ellipse(r, c, radius, radius, shape)
 
 
-def set_color(img, coords, color):
+def set_color(img, coords, color, alpha=1):
     """Set pixel color in the image at the given coordinates.
 
     Coordinates that exceed the shape of the image will be ignored.
@@ -134,10 +134,13 @@ def set_color(img, coords, color):
     ----------
     img : (M, N, D) ndarray
         Image
-    coords : ((P,) ndarray, (P,) ndarray)
-        Coordinates of pixels to be colored.
+    coords : tuple of ((P,) ndarray, (P,) ndarray)
+        Row and column coordinates of pixels to be colored.
     color : (D,) ndarray
         Color to be assigned to coordinates in the image.
+    alpha : scalar or (N,) ndarray
+        Alpha values used to blend color with image.  0 is transparent,
+        1 is opaque.
 
     Returns
     -------
@@ -163,7 +166,28 @@ def set_color(img, coords, color):
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 1]], dtype=uint8)
 
     """
-
     rr, cc = coords
-    rr, cc = _coords_inside_image(rr, cc, img.shape)
-    img[rr, cc] = color
+
+    if img.ndim == 2:
+        img = img[..., np.newaxis]
+
+    color = np.array(color, ndmin=1, copy=False)
+
+    if img.shape[-1] != color.shape[-1]:
+        raise ValueError('Color shape ({}) must match last '
+                         'image dimension ({}).'.format(color.shape[0],
+                                                        img.shape[-1]))
+
+    if np.isscalar(alpha):
+        # Can be replaced by ``full_like`` when numpy 1.8 becomes
+        # minimum dependency
+        alpha = np.ones_like(rr) * alpha
+
+    rr, cc, alpha = _coords_inside_image(rr, cc, img.shape, val=alpha)
+
+    alpha = alpha[..., np.newaxis]
+
+    color = color * alpha
+    vals = img[rr, cc] * (1 - alpha)
+
+    img[rr, cc] = vals + color
diff --git a/skimage/feature/_daisy.py b/skimage/feature/_daisy.py
--- a/skimage/feature/_daisy.py
+++ b/skimage/feature/_daisy.py
@@ -181,20 +181,20 @@ def daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8,
         for i in range(descs.shape[0]):
             for j in range(descs.shape[1]):
                 # Draw center histogram sigma
-                color = (1, 0, 0)
+                color = [1, 0, 0]
                 desc_y = i * step + radius
                 desc_x = j * step + radius
-                coords = draw.circle_perimeter(desc_y, desc_x, int(sigmas[0]))
-                draw.set_color(descs_img, coords, color)
+                rows, cols, val = draw.circle_perimeter_aa(desc_y, desc_x, int(sigmas[0]))
+                draw.set_color(descs_img, (rows, cols), color, alpha=val)
                 max_bin = np.max(descs[i, j, :])
                 for o_num, o in enumerate(orientation_angles):
                     # Draw center histogram bins
                     bin_size = descs[i, j, o_num] / max_bin
                     dy = sigmas[0] * bin_size * sin(o)
                     dx = sigmas[0] * bin_size * cos(o)
-                    coords = draw.line(desc_y, desc_x, int(desc_y + dy),
-                                       int(desc_x + dx))
-                    draw.set_color(descs_img, coords, color)
+                    rows, cols, val = draw.line_aa(desc_y, desc_x, int(desc_y + dy),
+                                                   int(desc_x + dx))
+                    draw.set_color(descs_img, (rows, cols), color, alpha=val)
                 for r_num, r in enumerate(ring_radii):
                     color_offset = float(1 + r_num) / rings
                     color = (1 - color_offset, 1, color_offset)
@@ -202,9 +202,9 @@ def daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8,
                         # Draw ring histogram sigmas
                         hist_y = desc_y + int(round(r * sin(t)))
                         hist_x = desc_x + int(round(r * cos(t)))
-                        coords = draw.circle_perimeter(hist_y, hist_x,
-                                                       int(sigmas[r_num + 1]))
-                        draw.set_color(descs_img, coords, color)
+                        rows, cols, val = draw.circle_perimeter_aa(hist_y, hist_x,
+                                                                   int(sigmas[r_num + 1]))
+                        draw.set_color(descs_img, (rows, cols), color, alpha=val)
                         for o_num, o in enumerate(orientation_angles):
                             # Draw histogram bins
                             bin_size = descs[i, j, orientations + r_num *
@@ -213,10 +213,10 @@ def daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8,
                             bin_size /= max_bin
                             dy = sigmas[r_num + 1] * bin_size * sin(o)
                             dx = sigmas[r_num + 1] * bin_size * cos(o)
-                            coords = draw.line(hist_y, hist_x,
-                                               int(hist_y + dy),
-                                               int(hist_x + dx))
-                            draw.set_color(descs_img, coords, color)
+                            rows, cols, val = draw.line_aa(hist_y, hist_x,
+                                                           int(hist_y + dy),
+                                                           int(hist_x + dx))
+                            draw.set_color(descs_img, (rows, cols), color, alpha=val)
         return descs, descs_img
     else:
         return descs
diff --git a/skimage/util/dtype.py b/skimage/util/dtype.py
--- a/skimage/util/dtype.py
+++ b/skimage/util/dtype.py
@@ -25,9 +25,8 @@
                     np.int8, np.int16, np.int32, np.int64,
                     np.float32, np.float64)
 
-if np.__version__ >= "1.6.0":
-    dtype_range[np.float16] = (-1, 1)
-    _supported_types += (np.float16, )
+dtype_range[np.float16] = (-1, 1)
+_supported_types += (np.float16, )
 
 
 def dtype_limits(image, clip_negative=True):


Test patch:
diff --git a/skimage/draw/tests/test_draw.py b/skimage/draw/tests/test_draw.py
--- a/skimage/draw/tests/test_draw.py
+++ b/skimage/draw/tests/test_draw.py
@@ -1,4 +1,4 @@
-from numpy.testing import assert_array_equal, assert_equal
+from numpy.testing import assert_array_equal, assert_equal, assert_raises
 import numpy as np
 from skimage._shared.testing import test_parallel
 
@@ -20,6 +20,21 @@ def test_set_color():
     assert_array_equal(img, img_)
 
 
+def test_set_color_with_alpha():
+    img = np.zeros((10, 10))
+
+    rr, cc, alpha = line_aa(0, 0, 0, 30)
+    set_color(img, (rr, cc), 1, alpha=alpha)
+
+    # Wrong dimensionality color
+    assert_raises(ValueError, set_color, img, (rr, cc), (255, 0, 0), alpha=alpha)
+
+    img = np.zeros((10, 10, 3))
+
+    rr, cc, alpha = line_aa(0, 0, 0, 30)
+    set_color(img, (rr, cc), (1, 0, 0), alpha=alpha)
+
+
 @test_parallel()
 def test_line_horizontal():
     img = np.zeros((10, 10))
@@ -72,7 +87,7 @@ def test_line_aa_horizontal():
     img = np.zeros((10, 10))
 
     rr, cc, val = line_aa(0, 0, 0, 9)
-    img[rr, cc] = val
+    set_color(img, (rr, cc), 1, alpha=val)
 
     img_ = np.zeros((10, 10))
     img_[0, :] = 1
@@ -329,12 +344,14 @@ def test_circle_perimeter_aa_shape():
     img = np.zeros((15, 20), 'uint8')
     rr, cc, val = circle_perimeter_aa(7, 10, 9, shape=(15, 20))
     img[rr, cc] = val * 255
+
     shift = 5
     img_ = np.zeros((15 + 2 * shift, 20), 'uint8')
     rr, cc, val = circle_perimeter_aa(7 + shift, 10, 9, shape=None)
     img_[rr, cc] = val * 255
     assert_array_equal(img, img_[shift:-shift, :])
 
+
 def test_ellipse_trivial():
     img = np.zeros((2, 2), 'uint8')
     rr, cc = ellipse(0.5, 0.5, 0.5, 0.5)