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

BREAKING LandmarkGroups are now Shapes #675

Merged
merged 18 commits into from Feb 7, 2017
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
10 changes: 0 additions & 10 deletions docs/source/api/landmark/LandmarkGroup.rst

This file was deleted.

3 changes: 2 additions & 1 deletion docs/source/api/landmark/index.rst
Expand Up @@ -29,9 +29,9 @@ Landmarks & Labeller
:maxdepth: 2

LandmarkManager
LandmarkGroup
labeller


Bounding Box Labels
-------------------

Expand All @@ -41,6 +41,7 @@ Bounding Box Labels
bounding_box_mirrored_to_bounding_box
bounding_box_to_bounding_box


Labels
------
Pre-defined landmark labels that normally correspond to standard database
Expand Down
13 changes: 13 additions & 0 deletions docs/source/api/shape/LabelledPointUndirectedGraph.rst
@@ -0,0 +1,13 @@
.. _menpo-shape-LabelledPointUndirectedGraph:

.. currentmodule:: menpo.shape

LabelledPointUndirectedGraph
============================
.. autoclass:: LabelledPointUndirectedGraph
:members:
:inherited-members:
:show-inheritance:

.. automethod:: _view_2d
.. automethod:: _view_landmarks_2d
12 changes: 12 additions & 0 deletions docs/source/api/shape/index.rst
Expand Up @@ -46,6 +46,18 @@ Mix-ins of Graphs and :map:`PointCloud` for graphs with geometry.
PointTree


LabelledPointGraph
------------------

A subclass of :map:`PointUndirectedGraph` that allows the attaching of
`labels` associated with semantic parts of the object.

.. toctree::
:maxdepth: 2

LabelledPointUndirectedGraph


Predefined Graphs
-----------------

Expand Down
2 changes: 1 addition & 1 deletion docs/source/changelog.rst
Expand Up @@ -375,7 +375,7 @@ Breaking Changes
not been deprecated due to the changes. However, the new changes mean
that the naming scheme of labels is now much more intuitive. Practically,
the usage of labelling has only changed in that now it is possible to label
not only :map:`LandmarkGroup` but also :map:`PointCloud` and numpy arrays
not only `LandmarkGroup` but also :map:`PointCloud` and numpy arrays
directly.
- Landmarks are now warped by default, where previously they were not.
- All vlfeat features have now become optional and will not appear if
Expand Down
3 changes: 2 additions & 1 deletion docs/xref_map.py
Expand Up @@ -24,10 +24,10 @@
'ImageBoundaryError': ('class', 'menpo.image.ImageBoundaryError'),
'InstanceBackedModel': ('class', 'menpo.model.instancebacked.InstanceBackedModel'),
'Invertible': ('class', 'menpo.transform.base.invertible.Invertible'),
'LabelledPointUndirectedGraph': ('class', 'menpo.shape.LabelledPointUndirectedGraph'),
'Landmarkable': ('class', 'menpo.landmark.Landmarkable'),
'LandmarkableViewable': ('class', 'menpo.visualize.LandmarkableViewable'),
'landmark_file_paths': ('function', 'menpo.io.landmark_file_paths'),
'LandmarkGroup': ('class', 'menpo.landmark.LandmarkGroup'),
'LandmarkManager': ('class', 'menpo.landmark.LandmarkManager'),
'LabellingError': ('class', 'menpo.landmark.LabellingError'),
'LazyList': ('class', 'menpo.base.LazyList'),
Expand All @@ -37,6 +37,7 @@
'MeanInstanceLinearModel': ('class', 'menpo.model.MeanInstanceLinearModel'),
'MeanLinearModel': ('class', 'menpo.model.linear.MeanLinearModel'),
'MultipleAlignment': ('class', 'menpo.transform.MultipleAlignment'),
'pickle_paths': ('function', 'menpo.io.input.base.pickle_paths'),
'PCAModel': ('class', 'menpo.model.pca.PCAModel'),
'PCAVectorModel': ('class', 'menpo.model.pca.PCAVectorModel'),
'PiecewiseAffine': ('class', 'menpo.transform.PiecewiseAffine'),
Expand Down
10 changes: 5 additions & 5 deletions menpo/feature/test/test_features.py
Expand Up @@ -302,14 +302,14 @@ def test_constrain_landmarks():
breaking_bad = breaking_bad.resize([50, 50])
breaking_bad.constrain_mask_to_landmarks()
hog_b = hog(breaking_bad, mode='sparse')
x = np.where(hog_b.landmarks['PTS'].lms.points[:, 0] > hog_b.shape[1] - 1)
y = np.where(hog_b.landmarks['PTS'].lms.points[:, 0] > hog_b.shape[0] - 1)
x = np.where(hog_b.landmarks['PTS'].points[:, 0] > hog_b.shape[1] - 1)
y = np.where(hog_b.landmarks['PTS'].points[:, 0] > hog_b.shape[0] - 1)
assert_allclose(len(x[0]) + len(y[0]), 12)
hog_b = hog(breaking_bad, mode='sparse')
hog_b.landmarks['PTS'] = hog_b.landmarks['PTS'].lms.constrain_to_bounds(
hog_b.landmarks['PTS'] = hog_b.landmarks['PTS'].constrain_to_bounds(
hog_b.bounds())
x = np.where(hog_b.landmarks['PTS'].lms.points[:, 0] > hog_b.shape[1] - 1)
y = np.where(hog_b.landmarks['PTS'].lms.points[:, 0] > hog_b.shape[0] - 1)
x = np.where(hog_b.landmarks['PTS'].points[:, 0] > hog_b.shape[1] - 1)
y = np.where(hog_b.landmarks['PTS'].points[:, 0] > hog_b.shape[0] - 1)
assert_allclose(len(x[0]) + len(y[0]), 0)


Expand Down
24 changes: 12 additions & 12 deletions menpo/image/base.py
Expand Up @@ -1256,7 +1256,7 @@ def crop_to_landmarks(self, group=None, boundary=0,
Raised if ``constrain_to_boundary=False``, and an attempt is made
to crop the image in a way that violates the image bounds.
"""
pc = self.landmarks[group].lms
pc = self.landmarks[group]
return self.crop_to_pointcloud(
pc, boundary=boundary, constrain_to_boundary=constrain_to_boundary,
return_transform=return_transform)
Expand Down Expand Up @@ -1359,7 +1359,7 @@ def crop_to_landmarks_proportion(self, boundary_proportion,
Raised if ``constrain_to_boundary=False``, and an attempt is made
to crop the image in a way that violates the image bounds.
"""
pc = self.landmarks[group].lms
pc = self.landmarks[group]
return self.crop_to_pointcloud_proportion(
pc, boundary_proportion, minimum=minimum,
constrain_to_boundary=constrain_to_boundary,
Expand Down Expand Up @@ -1493,7 +1493,7 @@ def extract_patches_around_landmarks(
ValueError
If image is not 2D
"""
return self.extract_patches(self.landmarks[group].lms,
return self.extract_patches(self.landmarks[group],
patch_shape=patch_shape,
sample_offsets=sample_offsets,
as_single_array=as_single_array)
Expand Down Expand Up @@ -1610,7 +1610,7 @@ def set_patches_around_landmarks(self, patches, group=None,
ValueError
If offset does not have shape (1, 2)
"""
return self.set_patches(patches, self.landmarks[group].lms,
return self.set_patches(patches, self.landmarks[group],
offset=offset, offset_index=offset_index)

def warp_to_mask(self, template_mask, transform, warp_landmarks=True,
Expand Down Expand Up @@ -2035,7 +2035,7 @@ def rescale_to_pointcloud(self, pointcloud, group=None,
The transform that was used. It only applies if
`return_transform` is ``True``.
"""
pc = self.landmarks[group].lms
pc = self.landmarks[group]
scale = AlignmentUniformScale(pc, pointcloud).as_vector().copy()
return self.rescale(scale, round=round, order=order,
return_transform=return_transform)
Expand Down Expand Up @@ -2084,7 +2084,7 @@ def rescale_landmarks_to_diagonal_range(self, diagonal_range, group=None,
The transform that was used. It only applies if
`return_transform` is ``True``.
"""
x, y = self.landmarks[group].lms.range()
x, y = self.landmarks[group].range()
scale = diagonal_range / np.sqrt(x ** 2 + y ** 2)
return self.rescale(scale, round=round, order=order,
return_transform=return_transform)
Expand Down Expand Up @@ -2723,7 +2723,7 @@ def has_landmarks_outside_bounds(self):
"""
if self.has_landmarks:
for l_group in self.landmarks:
pc = self.landmarks[l_group].lms.points
pc = self.landmarks[l_group].points
if np.any(np.logical_or(self.shape - pc < 1, pc < 0)):
return True
return False
Expand All @@ -2735,7 +2735,7 @@ def constrain_landmarks_to_bounds(self):
method. For example:

>>> im.constrain_landmarks_to_bounds() # Equivalent to below
>>> im.landmarks['test'] = im.landmarks['test'].lms.constrain_to_bounds(im.bounds())
>>> im.landmarks['test'] = im.landmarks['test'].constrain_to_bounds(im.bounds())
"""
warn('This method is no longer supported and will be removed in a '
'future version of Menpo. '
Expand All @@ -2744,11 +2744,11 @@ def constrain_landmarks_to_bounds(self):

for l_group in self.landmarks:
l = self.landmarks[l_group]
for k in range(l.lms.points.shape[1]):
tmp = l.lms.points[:, k]
for k in range(l.points.shape[1]):
tmp = l.points[:, k]
tmp[tmp < 0] = 0
tmp[tmp > self.shape[k] - 1] = self.shape[k] - 1
l.lms.points[:, k] = tmp
l.points[:, k] = tmp
self.landmarks[l_group] = l

def normalize_std(self, mode='all', **kwargs):
Expand Down Expand Up @@ -2959,7 +2959,7 @@ def _create_patches_image(patches, patch_centers, patches_indices=None,
r"""
Creates an :map:`Image` object in which the patches are located on the
correct regions based on the centers. Thus, the image is a block-sparse
matrix. It has also two attached :map:`LandmarkGroup` objects. The
matrix. It has also two attached :map:`PointCloud` objects. The
`all_patch_centers` one contains all the patch centers, while the
`selected_patch_centers` one contains only the centers that correspond to
the patches that the user selected to set.
Expand Down
2 changes: 1 addition & 1 deletion menpo/image/boolean.py
Expand Up @@ -605,7 +605,7 @@ def constrain_to_landmarks(self, group=None, batch_size=None):
constrained : :map:`BooleanImage`
The new boolean image, constrained by the given landmark group.
"""
return self.constrain_to_pointcloud(self.landmarks[group].lms,
return self.constrain_to_pointcloud(self.landmarks[group],
batch_size=batch_size)

def constrain_to_pointcloud(self, pointcloud, batch_size=None,
Expand Down
4 changes: 2 additions & 2 deletions menpo/image/masked.py
Expand Up @@ -1158,7 +1158,7 @@ def constrain_mask_to_landmarks(self, group=None, batch_size=None,
"""
copy = self.copy()
copy.mask = copy.mask.constrain_to_pointcloud(
copy.landmarks[group].lms, batch_size=batch_size,
copy.landmarks[group], batch_size=batch_size,
point_in_pointcloud=point_in_pointcloud)
return copy

Expand Down Expand Up @@ -1198,7 +1198,7 @@ def constrain_mask_to_patches_around_landmarks(self, patch_shape,
"""
copy = self.copy()
# get the selected pointcloud
pc = copy.landmarks[group].lms
pc = copy.landmarks[group]
# temporarily set all mask values to False
copy.mask.pixels[:] = False
# create a patches array of the correct size, full of True values
Expand Down
4 changes: 2 additions & 2 deletions menpo/image/rasterize.py
Expand Up @@ -236,9 +236,9 @@ def rasterize_landmarks_2d(image, group=None, render_lines=True, line_style='-',

if backend in _RASTERIZE_BACKENDS:
if isinstance(group, list):
landmarks = [image.landmarks[g].lms for g in group]
landmarks = [image.landmarks[g] for g in group]
else:
landmarks = [image.landmarks[group].lms]
landmarks = [image.landmarks[group]]

# Validate all the parameters for multiple landmark groups being
# passed in
Expand Down
2 changes: 1 addition & 1 deletion menpo/image/test/image_basics_test.py
Expand Up @@ -144,4 +144,4 @@ def test_constrain_landmarks_to_bounds():
warnings.simplefilter('ignore')
im.constrain_landmarks_to_bounds()
assert not im.has_landmarks_outside_bounds()
assert_allclose(im.landmarks['test'].lms.bounds(), im.bounds())
assert_allclose(im.landmarks['test'].bounds(), im.bounds())
12 changes: 6 additions & 6 deletions menpo/image/test/image_copy_test.py
Expand Up @@ -13,8 +13,8 @@ def test_image_copy():
im_copy = im.copy()

assert (not is_same_array(im.pixels, im_copy.pixels))
assert (not is_same_array(im_copy.landmarks['test'].lms.points,
im.landmarks['test'].lms.points))
assert (not is_same_array(im_copy.landmarks['test'].points,
im.landmarks['test'].points))


def test_booleanimage_copy():
Expand All @@ -25,8 +25,8 @@ def test_booleanimage_copy():
im_copy = im.copy()

assert (not is_same_array(im.pixels, im_copy.pixels))
assert (not is_same_array(im_copy.landmarks['test'].lms.points,
im.landmarks['test'].lms.points))
assert (not is_same_array(im_copy.landmarks['test'].points,
im.landmarks['test'].points))


def test_maskedimage_copy():
Expand All @@ -37,5 +37,5 @@ def test_maskedimage_copy():
im_copy = im.copy()

assert (not is_same_array(im.pixels, im_copy.pixels))
assert (not is_same_array(im_copy.landmarks['test'].lms.points,
im.landmarks['test'].lms.points))
assert (not is_same_array(im_copy.landmarks['test'].points,
im.landmarks['test'].points))
28 changes: 14 additions & 14 deletions menpo/image/test/image_patches_test.py
Expand Up @@ -14,7 +14,7 @@
def test_double_type():
image = mio.import_builtin_asset('breakingbad.jpg')
patch_shape = (16, 16)
patches = image.extract_patches(image.landmarks['PTS'].lms,
patches = image.extract_patches(image.landmarks['PTS'],
patch_shape=patch_shape,
as_single_array=False)
assert(patches[0].pixels.dtype == np.float64)
Expand All @@ -24,7 +24,7 @@ def test_float_type():
image = mio.import_builtin_asset('breakingbad.jpg')
image.pixels = image.pixels.astype(np.float32)
patch_shape = (16, 16)
patches = image.extract_patches(image.landmarks['PTS'].lms,
patches = image.extract_patches(image.landmarks['PTS'],
patch_shape=patch_shape,
as_single_array=False)
assert(patches[0].pixels.dtype == np.float32)
Expand All @@ -33,7 +33,7 @@ def test_float_type():
def test_uint8_type():
image = mio.import_builtin_asset('breakingbad.jpg', normalize=False)
patch_shape = (16, 16)
patches = image.extract_patches(image.landmarks['PTS'].lms,
patches = image.extract_patches(image.landmarks['PTS'],
patch_shape=patch_shape,
as_single_array=False)
assert(patches[0].pixels.dtype == np.uint8)
Expand Down Expand Up @@ -62,7 +62,7 @@ def test_int_pointcloud():
def test_uint8_type_single_array():
image = mio.import_builtin_asset('breakingbad.jpg', normalize=False)
patch_shape = (16, 16)
patches = image.extract_patches(image.landmarks['PTS'].lms,
patches = image.extract_patches(image.landmarks['PTS'],
patch_shape=patch_shape,
as_single_array=True)
assert(patches.dtype == np.uint8)
Expand All @@ -71,7 +71,7 @@ def test_uint8_type_single_array():
def test_squared_even_patches():
image = mio.import_builtin_asset('breakingbad.jpg')
patch_shape = (16, 16)
patches = image.extract_patches(image.landmarks['PTS'].lms,
patches = image.extract_patches(image.landmarks['PTS'],
patch_shape=patch_shape,
as_single_array=False)
assert_equals(len(patches), 68)
Expand All @@ -80,7 +80,7 @@ def test_squared_even_patches():
def test_squared_odd_patches():
image = mio.import_builtin_asset('breakingbad.jpg')
patch_shape = (15, 15)
patches = image.extract_patches(image.landmarks['PTS'].lms,
patches = image.extract_patches(image.landmarks['PTS'],
patch_shape=patch_shape,
as_single_array=False)
assert_equals(len(patches), 68)
Expand All @@ -89,7 +89,7 @@ def test_squared_odd_patches():
def test_nonsquared_even_patches():
image = mio.import_builtin_asset('breakingbad.jpg')
patch_shape = (16, 18)
patches = image.extract_patches(image.landmarks['PTS'].lms,
patches = image.extract_patches(image.landmarks['PTS'],
patch_shape=patch_shape,
as_single_array=False)
assert_equals(len(patches), 68)
Expand All @@ -98,7 +98,7 @@ def test_nonsquared_even_patches():
def test_nonsquared_odd_patches():
image = mio.import_builtin_asset('breakingbad.jpg')
patch_shape = (15, 17)
patches = image.extract_patches(image.landmarks['PTS'].lms,
patches = image.extract_patches(image.landmarks['PTS'],
patch_shape=patch_shape,
as_single_array=False)
assert_equals(len(patches), 68)
Expand All @@ -107,7 +107,7 @@ def test_nonsquared_odd_patches():
def test_nonsquared_even_odd_patches():
image = mio.import_builtin_asset('breakingbad.jpg')
patch_shape = (15, 16)
patches = image.extract_patches(image.landmarks['PTS'].lms,
patches = image.extract_patches(image.landmarks['PTS'],
patch_shape=patch_shape,
as_single_array=False)
assert_equals(len(patches), 68)
Expand All @@ -125,7 +125,7 @@ def test_squared_even_patches_landmarks():
def test_squared_even_patches_single_array():
image = mio.import_builtin_asset('breakingbad.jpg')
patch_shape = (16, 16)
patches = image.extract_patches(image.landmarks['PTS'].lms,
patches = image.extract_patches(image.landmarks['PTS'],
as_single_array=True,
patch_shape=patch_shape)
assert_equals(patches.shape, ((68, 1, 3) + patch_shape))
Expand All @@ -134,7 +134,7 @@ def test_squared_even_patches_single_array():
def test_squared_even_patches_sample_offsets():
image = mio.import_builtin_asset('breakingbad.jpg')
sample_offsets = np.array([[0, 0], [1, 0]])
patches = image.extract_patches(image.landmarks['PTS'].lms,
patches = image.extract_patches(image.landmarks['PTS'],
sample_offsets=sample_offsets,
as_single_array=False)
assert_equals(len(patches), 136)
Expand Down Expand Up @@ -225,9 +225,9 @@ def test_create_patches_image():
image = mio.import_builtin_asset.lenna_png()
patches = image.extract_patches_around_landmarks(
patch_shape=patch_shape, as_single_array=True)
pc = image.landmarks['LJSON'].lms
pc = image.landmarks['LJSON']
patches_image = _create_patches_image(patches, pc, patches_indices=range(17))
assert(patches_image.n_channels == patches.shape[2])
assert(patches_image.landmarks.n_groups == 2)
assert(patches_image.landmarks['selected_patch_centers'].lms.n_points == 17)
assert(patches_image.landmarks['all_patch_centers'].lms.n_points == 68)
assert(patches_image.landmarks['selected_patch_centers'].n_points == 17)
assert(patches_image.landmarks['all_patch_centers'].n_points == 68)