Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract patches on image #479

Merged
merged 2 commits into from Oct 16, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 6 additions & 6 deletions menpo/external/skimage/_daisy.py
Expand Up @@ -21,7 +21,7 @@ def _daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8,
* The sigma values of the spatial Gaussian smoothing in this code do not
match the sigma values in the original code by Tola et al. [2]_. In
their code, spatial smoothing is applied to both the input image and
the center histogram. However, this smoothing is not documented in [1]_
the centre histogram. However, this smoothing is not documented in [1]_
and, therefore, it is omitted.

Parameters
Expand All @@ -47,10 +47,10 @@ def _daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8,
* 'off': Disable normalization.

sigmas : 1D array of float, optional
Standard deviation of spatial Gaussian smoothing for the center
Standard deviation of spatial Gaussian smoothing for the centre
histogram and for each ring of histograms. The array of sigmas should
be sorted from the center and out. I.e. the first sigma value defines
the spatial smoothing of the center histogram and the last sigma value
be sorted from the centre and out. I.e. the first sigma value defines
the spatial smoothing of the centre histogram and the last sigma value
defines the spatial smoothing of the outermost ring. Specifying sigmas
overrides the following parameter.

Expand All @@ -64,7 +64,7 @@ def _daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8,
``radius = ring_radii[-1]``

If both sigmas and ring_radii are given, they must satisfy the
following predicate since no radius is needed for the center
following predicate since no radius is needed for the centre
histogram.

``len(ring_radii) == len(sigmas) + 1``
Expand Down Expand Up @@ -123,7 +123,7 @@ def _daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8,
# Weigh bin contribution by the gradient magnitude
hist[i, :, :] = np.multiply(hist[i, :, :], grad_mag)

# Smooth orientation histograms for the center and all rings.
# Smooth orientation histograms for the centre and all rings.
sigmas = [sigmas[0]] + sigmas
hist_smooth = np.empty((rings + 1,) + hist.shape, dtype=float)
for i in range(rings + 1):
Expand Down
8 changes: 4 additions & 4 deletions menpo/feature/features.py
Expand Up @@ -454,10 +454,10 @@ def daisy(pixels, step=1, radius=15, rings=2, histograms=2, orientations=8,
If None then no normalization is employed.

sigmas : 1D array of `float`, Optional
Standard deviation of spatial Gaussian smoothing for the center
Standard deviation of spatial Gaussian smoothing for the centre
histogram and for each ring of histograms. The array of sigmas should
be sorted from the center and out. I.e. the first sigma value defines
the spatial smoothing of the center histogram and the last sigma value
be sorted from the centre and out. I.e. the first sigma value defines
the spatial smoothing of the centre histogram and the last sigma value
defines the spatial smoothing of the outermost ring. Specifying sigmas
overrides the following parameter.

Expand All @@ -471,7 +471,7 @@ def daisy(pixels, step=1, radius=15, rings=2, histograms=2, orientations=8,
``radius = ring_radii[-1]``

If both sigmas and ring_radii are given, they must satisfy the
following predicate since no radius is needed for the center
following predicate since no radius is needed for the centre
histogram.

``len(ring_radii) == len(sigmas) + 1``
Expand Down
15 changes: 5 additions & 10 deletions menpo/fit/regression/trainer.py
Expand Up @@ -3,9 +3,7 @@
import numpy as np

from menpo.image import Image
from menpo.fitmultilevel.functions import (noisy_align, build_sampling_grid,
extract_local_patches_fast,
extract_local_patches)
from menpo.fitmultilevel.functions import (noisy_align, build_sampling_grid)
from menpo.feature import sparse_hog
from menpo.fit.fittingresult import (NonParametricFittingResult,
SemiParametricFittingResult,
Expand Down Expand Up @@ -321,14 +319,12 @@ def features(self, image, shape):
The current shape.
"""
# extract patches
patches = extract_local_patches_fast(image, shape, self.patch_shape)
patches = image.extract_patches(shape, patch_size=self.patch_shape)

features = np.zeros((shape.n_points, self._feature_patch_length))
for j, patch in enumerate(patches):
# build patch image
patch_img = Image(patch, copy=False)
# compute features
features[j, ...] = self.regression_features(patch_img).as_vector()
features[j, ...] = self.regression_features(patch).as_vector()

return np.hstack((features.ravel(), 1))

Expand Down Expand Up @@ -670,8 +666,7 @@ def features(self, image, shape):
shape : :map:`PointCloud`
The current shape.
"""
# TODO: in the future this should be extract_local_patches_fast
patches = extract_local_patches(image, shape, self.sampling_grid)
features = [clf(np.reshape(patch, (-1, patch.shape[-1])))
patches = image.extract_patches(shape, patch_size=self.patch_shape)
features = [clf(patch.as_vector(keep_channels=True))
for (clf, patch) in zip(self.classifiers, patches)]
return np.hstack((np.asarray(features).ravel(), 1))
8 changes: 4 additions & 4 deletions menpo/fitmultilevel/clm/builder.py
Expand Up @@ -315,14 +315,14 @@ def build(self, images, group=None, label=None, verbose=False):
def get_pos_neg_grid_positions(sampling_grid, positive_grid_size=(1, 1)):
r"""
Divides a sampling grid in positive and negative pixel positions. By
default only the center of the grid is considered to be positive.
default only the centre of the grid is considered to be positive.
"""
positive_grid_size = np.array(positive_grid_size)
mask = np.zeros(sampling_grid.shape[:-1], dtype=np.bool)
center = np.round(np.array(mask.shape) / 2).astype(int)
centre = np.round(np.array(mask.shape) / 2).astype(int)
positive_grid_size -= [1, 1]
start = center - positive_grid_size
end = center + positive_grid_size + 1
start = centre - positive_grid_size
end = centre + positive_grid_size + 1
mask[start[0]:end[0], start[1]:end[1]] = True
positive = sampling_grid[mask]
negative = sampling_grid[~mask]
Expand Down
76 changes: 0 additions & 76 deletions menpo/fitmultilevel/functions.py
Expand Up @@ -64,82 +64,6 @@ def extract_local_patches(image, centres, sampling_grid):
return patches


def extract_local_patches_fast(image, centres, patch_shape, out=None):
r"""
Extract square patches from an image about centres.

Parameters
----------
image : :map:`Image`
The image to extract patches from

centres : :map:`PointCloud`
The centres around which the patches should be extracted

patch_shape : `tuple` of `ints`
The size of the patch in each dimension

out : `ndarray` of shape: ``n_centres, + patch_shape + n_channels,``,
optional
The output array to be assigned to. If `None`, a new numpy array
will be created.

Returns
-------
patches : `ndarray` of shape: ``n_centres, + patch_shape + n_channels,``
The patches as a single numpy array.
"""
if out is not None:
patches = out
else:
patches = np.empty(
(centres.n_points,) + patch_shape + (image.n_channels,))
# 0 out the patches array
patches[...] = 0
image_size = np.array(image.shape, dtype=np.int)
patch_shape = np.array(patch_shape, dtype=np.int)
centres = np.require(centres.points, dtype=np.int)
half_patch_shape = np.require(np.floor(patch_shape / 2), dtype=np.int)
# deal with odd patch shapes
# - add_to_patch[axis] = 0 if patch_shape[axis] is odd
# - add_to_patch[axis] = 1 if patch_shape[axis] is even
add_to_patch = np.mod(patch_shape, 2)
# 1. compute the extents
c_min = centres - half_patch_shape
c_max = centres + half_patch_shape + add_to_patch
out_min_min = c_min < 0
out_min_max = c_min > image_size
out_max_min = c_max < 0
out_max_max = c_max > image_size

# 1. Build the extraction slices
ext_s_min = c_min.copy()
ext_s_max = c_max.copy()
# Clamp the min to 0
ext_s_min[out_min_min] = 0
ext_s_max[out_max_min] = 0
# Clamp the max to image bounds across each dimension
for i in xrange(image.n_dims):
ext_s_max[out_max_max[:, i], i] = image_size[i] - 1
ext_s_min[out_min_max[:, i], i] = image_size[i] - 1

# 2. Build the insertion slices
ins_s_min = ext_s_min - c_min
ins_s_max = np.maximum(ext_s_max - c_max + patch_shape, (0, 0))

for i, (e_a, e_b, i_a, i_b) in enumerate(zip(ext_s_min, ext_s_max,
ins_s_min, ins_s_max)):
# build a list of insertion slices and extraction slices
i_slices = [slice(a, b) for a, b in zip(i_a, i_b)]
e_slices = [slice(a, b) for a, b in zip(e_a, e_b)]
# get a view onto the patch we are on
patch = patches[i, ...]
# apply the slices to map
patch[i_slices] = image.pixels[e_slices]

return patches


# TODO: Should this be a method on Similarity? AlignableTransforms?
def noisy_align(source, target, noise_std=0.04, rotation=False):
r"""
Expand Down
43 changes: 0 additions & 43 deletions menpo/fitmultilevel/test/functions_test.py

This file was deleted.

1 change: 1 addition & 0 deletions menpo/image/.gitignore
@@ -0,0 +1 @@
extract_patches.cpp