From 6c19cf0693ca85eff0d43ff68693fcf3f2d83b48 Mon Sep 17 00:00:00 2001 From: Anders Boesen Lindbo Larsen Date: Sat, 15 Dec 2012 18:44:23 +0100 Subject: [PATCH] Add DAISY visualization + example plot. --- doc/examples/plot_daisy.py | 28 ++++++++++++ doc/examples/plot_shapes.py | 8 +++- skimage/feature/_daisy.py | 70 ++++++++++++++++++++++++++--- skimage/feature/tests/test_daisy.py | 5 +++ 4 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 doc/examples/plot_daisy.py diff --git a/doc/examples/plot_daisy.py b/doc/examples/plot_daisy.py new file mode 100644 index 00000000..af78103d --- /dev/null +++ b/doc/examples/plot_daisy.py @@ -0,0 +1,28 @@ +""" +=============================== +Dense DAISY feature description +=============================== + +The DAISY local image descriptor is based on gradient orientation histograms +similar to the SIFT descriptor. It is formulated in a way that allows for fast +dense extraction which is useful for e.g. bag-of-features image +representations. + +In this example a limited number of DAISY descriptors are extracted at a large +scale for illustrative purposes. +""" + +from skimage.feature import daisy +from skimage import data +import matplotlib.pyplot as plt + + +img = data.camera() +descs, descs_img = daisy(img, step=180, radius=58, rings=2, histograms=6, + orientations=8, visualize=True) + +plt.axis('off') +plt.imshow(descs_img) +descs_num = descs.shape[0] * descs.shape[1] +plt.title('%i DAISY descriptors extracted:' % descs_num) +plt.show() diff --git a/doc/examples/plot_shapes.py b/doc/examples/plot_shapes.py index 9e586209..25a48ebe 100644 --- a/doc/examples/plot_shapes.py +++ b/doc/examples/plot_shapes.py @@ -13,7 +13,7 @@ This example shows how to fill several different shapes: import matplotlib.pyplot as plt -from skimage.draw import line, polygon, circle, ellipse +from skimage.draw import line, polygon, circle, circle_perimeter, ellipse import numpy as np @@ -42,5 +42,9 @@ img[rr,cc,:] = (255, 255, 0) rr, cc = ellipse(300, 300, 100, 200, img.shape) img[rr,cc,2] = 255 +# circle +rr, cc = circle_perimeter(120, 400, 50) +img[rr, cc, :] = (255, 0, 255) + plt.imshow(img) -plt.show() \ No newline at end of file +plt.show() diff --git a/skimage/feature/_daisy.py b/skimage/feature/_daisy.py index b0cc6748..85e259d0 100644 --- a/skimage/feature/_daisy.py +++ b/skimage/feature/_daisy.py @@ -6,7 +6,7 @@ from skimage import img_as_float def daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8, - normalization='l1', sigmas=None, ring_radii=None): + normalization='l1', sigmas=None, ring_radii=None, visualize=False): '''Extract DAISY feature descriptors densely for the given image. DAISY is a feature descriptor similar to SIFT formulated in a way that @@ -65,6 +65,8 @@ def daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8, following predicate since no radius is needed for the center histogram. ``len(ring_radii) == len(sigmas)+1`` + visualize : bool, optional + Generate a visualization of the DAISY descriptors Returns @@ -75,10 +77,12 @@ def daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8, | ``P = ceil((M-radius*2)/step)`` | ``Q = ceil((N-radius*2)/step)`` | ``R = (rings*histograms + 1)*orientations`` + descs_img : (M, N, 3) array (only if visualize==True) + Visualization of the DAISY descriptors. References ---------- - .. [1] Tola et al. "Daisy\: An efficient dense descriptor applied to wide- + .. [1] Tola et al. "Daisy: An efficient dense descriptor applied to wide- baseline stereo." Pattern Analysis and Machine Intelligence, IEEE Transactions on 32.5 (2010): 815-830. .. [2] http://cvlab.epfl.ch/alumni/tola/daisy.html @@ -120,10 +124,11 @@ def daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8, kappa = 1. / hist_sigma bessel = iv(0, kappa) hist = np.empty((orientations,) + img.shape, dtype=float) - for i in range(orientations): - mu = 2 * i * pi / orientations - pi + orientation_angles = [2 * o * pi / orientations - pi + for o in range(orientations)] + for i, o in enumerate(orientation_angles): # Weigh bin contribution by the circular normal distribution - hist[i, :, :] = exp(kappa * cos(grad_ori - mu)) / (2 * pi * bessel) + hist[i, :, :] = exp(kappa * cos(grad_ori - o)) / (2 * pi * bessel) # Weigh bin contribution by the gradient magnitude hist[i, :, :] = np.multiply(hist[i, :, :], grad_mag) @@ -169,4 +174,57 @@ def daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8, axis=2)) descs[:, :, i:i + orientations] /= norms[:, :, np.newaxis] - return descs + if visualize: + from skimage import draw + from skimage import color + descs_img = color.gray2rgb(img) + for i in range(descs.shape[0]): + for j in range(descs.shape[1]): + # Draw center histogram sigma + color = (1, 0, 0) + desc_y = i * step + radius + desc_x = j * step + radius + coords = draw.circle_perimeter(desc_y, desc_x, sigmas[0]) + set_color(descs_img, coords, color) + 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, desc_y + dy, + desc_x + dx) + set_color(descs_img, coords, color) + for r_num, r in enumerate(ring_radii): + color_offset = float(1 + r_num) / rings + color = (1 - color_offset, 1, color_offset) + for t_num, t in enumerate(theta): + # 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, + sigmas[r_num + 1]) + set_color(descs_img, coords, color) + for o_num, o in enumerate(orientation_angles): + # Draw histogram bins + bin_size = descs[i, j, orientations + r_num * + histograms * orientations + + t_num * orientations + o_num] + 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, hist_y + dy, + hist_x + dx) + set_color(descs_img, coords, color) + return descs, descs_img + else: + return descs + + +def set_color(img, coords, color): + ''' Set pixel color at the given coordiantes in the image.''' + coords = filter(lambda (y, x): y >= 0 and y < img.shape[0] and x >= 0 + and x < img.shape[1], zip(*coords)) + if coords: + rr, cc = zip(*coords) + img[rr, cc, :] = color diff --git a/skimage/feature/tests/test_daisy.py b/skimage/feature/tests/test_daisy.py index b0dd28de..40781a64 100644 --- a/skimage/feature/tests/test_daisy.py +++ b/skimage/feature/tests/test_daisy.py @@ -85,6 +85,11 @@ def test_daisy_normalization(): assert_raises(ValueError, daisy, img, normalization='does_not_exist') +def test_daisy_visualization(): + img = img_as_float(data.lena()[:128, :128].mean(axis=2)) + descs, descs_img = daisy(img, visualize=True) + assert(descs_img.shape == (128, 128, 3)) + if __name__ == '__main__': from numpy import testing testing.run_module_suite()