Example #1
0
def ljson_importer(filepath, asset=None, **kwargs):
    r"""
    Importer for the Menpo JSON format. This is an n-dimensional
    landmark type for both images and meshes that encodes semantic labels in
    the format.

    Landmark set label: JSON

    Landmark labels: decided by file

    Parameters
    ----------
    filepath : `Path`
        Absolute filepath of the file.
    asset : `object`, optional
        An optional asset that may help with loading. This is unused for this
        implementation.
    \**kwargs : `dict`, optional
        Any other keyword arguments.

    Returns
    -------
    landmarks : :map:`LandmarkGroup`
        The landmarks including appropriate labels if available.
    """
    with open(str(filepath), 'r') as f:
        # lms_dict is now a dict rep of the JSON
        lms_dict = json.load(f, object_pairs_hook=OrderedDict)
    v = lms_dict.get('version')
    parser = _ljson_parser_for_version.get(v)

    if parser is None:
        raise ValueError("{} has unknown version {} must be "
                         "1, or 2".format(self.filepath, v))
    return LandmarkGroup(*parser(lms_dict))
Example #2
0
def imm_58_points(landmark_group):
    """
    Apply the 58 point semantic labels from the
    IMM dataset to the landmarks in the given landmark group.

    The label applied to this new manager will be 'imm_58_points'.

    The semantic labels applied are as follows:

      - chin
      - leye
      - reye
      - leyebrow
      - reyebrow
      - mouth
      - nose

    Parameters
    ----------
    landmark_group: :class:`menpo.landmark.base.LandmarkGroup`
        The landmark group to apply semantic labels to.

    Returns
    -------
    landmark_group: :class:`menpo.landmark.base.LandmarkGroup`
        New landmark group with group label 'imm_58_points'

    Raises
    ------
    :class:`menpo.landmark.exceptions.LabellingError`
        If the given landmark group contains less than 58 points

    References
    -----------
    .. [1] http://www2.imm.dtu.dk/~aam/
    """
    group_label = 'imm_58_points'
    n_points = landmark_group.lms.n_points

    if n_points != 58:
        raise LabellingError("{0} mark-up expects exactly 58 "
                             "points. However, the given landmark group only "
                             "has {1} points".format(group_label, n_points))

    new_landmark_group = LandmarkGroup(
        landmark_group._target, group_label,
        copy.deepcopy(landmark_group.lms),
        {'all': np.ones(n_points, dtype=np.bool)})

    new_landmark_group['chin'] = np.arange(13)
    new_landmark_group['leye'] = np.arange(13, 21)
    new_landmark_group['reye'] = np.arange(21, 29)
    new_landmark_group['leyebrow'] = np.arange(29, 34)
    new_landmark_group['reyebrow'] = np.arange(34, 39)
    new_landmark_group['mouth'] = np.arange(39, 47)
    new_landmark_group['nose'] = np.arange(47, 58)

    return new_landmark_group
Example #3
0
def ibug_68_closed_mouth(landmark_group):
    """
    Apply the ibug's "standard" 68 point semantic labels (based on the
    original semantic labels of multiPIE) to the landmarks in
    the given landmark group - but ignore the 3 points that are coincident for
    a closed mouth. Therefore, there only 65 points are returned.

    The label applied to this new group will be 'ibug_68_closed_mouth'.

    The semantic labels applied are as follows:

      - tri

    Parameters
    ----------
    landmark_group: :class:`menpo.landmark.base.LandmarkGroup`
        The landmark group to apply semantic labels to.

    Returns
    -------
    landmark_group : :class:`menpo.landmark.base.LandmarkGroup`
        New landmark manager with label 'ibug_68_closed_mouth'

    Raises
    ------
    :class:`menpo.landmark.exceptions.LabellingError`
        If the given landmark group contains less than 65 points

    References
    ----------
    .. [1] http://www.multipie.org/
    """
    group_label = 'ibug_68_closed_mouth'
    n_points = landmark_group.lms.n_points

    if landmark_group.lms.n_points != 68:
        raise LabellingError("{0} mark-up expects exactly 68 "
                             "points. However, the given landmark group only "
                             "has {1} points".format(group_label, n_points))

    # Ignore the 3 coincident points (the last 3 points)
    new_landmarks = copy.deepcopy(landmark_group.lms)
    new_landmarks.points = new_landmarks.points[:-3]
    new_landmark_group = LandmarkGroup(
        landmark_group._target, group_label, new_landmarks,
        {'all': np.ones(new_landmarks.n_points, dtype=np.bool)})

    new_landmark_group['chin'] = np.arange(17)
    new_landmark_group['leye'] = np.arange(36, 42)
    new_landmark_group['reye'] = np.arange(42, 48)
    new_landmark_group['leyebrow'] = np.arange(17, 22)
    new_landmark_group['reyebrow'] = np.arange(22, 27)
    new_landmark_group['mouth'] = np.arange(48, 65)
    new_landmark_group['nose'] = np.arange(27, 36)

    return new_landmark_group
Example #4
0
def ibug_close_eye_points(landmark_group):
    """
    Apply the ibug's "standard" close eye semantic labels to the
    landmarks in the given landmark group.

    The group label will be 'ibug_close_eye_points'.

    The semantic labels applied are as follows:

      - upper eyelid
      - lower eyelid

    Parameters
    ----------
    landmark_group : :map:`LandmarkGroup`
        The landmark group to apply semantic labels to.

    Returns
    -------
    group_label : `str`
        The group label: 'ibug_close_eye_points'
    landmark_group : :map:`LandmarkGroup`
        New landmark group.

    Raises
    ------
    :class:`menpo.landmark.exceptions.LabellingError`
        If the given landmark group contains less than 17 points
    """
    from menpo.shape import PointGraph

    group_label = 'ibug_close_eye_points'
    n_expected_points = 17
    n_points = landmark_group.lms.n_points
    _validate_input(landmark_group, n_expected_points, group_label)

    upper_indices, upper_connectivity = _build_upper_eyelid()

    middle_indices = np.arange(12, 17)
    bottom_indices = np.arange(6, 12)
    lower_indices = np.hstack((bottom_indices, 0, middle_indices))
    lower_connectivity = zip(bottom_indices, bottom_indices[1:])
    lower_connectivity += [(0, 12)]
    lower_connectivity += zip(middle_indices, middle_indices[1:])
    lower_connectivity += [(11, 0)]

    total_connectivity = np.asarray(upper_connectivity + lower_connectivity)
    new_landmark_group = LandmarkGroup(
        PointGraph(landmark_group.lms.points, total_connectivity),
        OrderedDict([('all', np.ones(n_points, dtype=np.bool))]))

    new_landmark_group['upper_eyelid'] = upper_indices
    new_landmark_group['lower_eyelid'] = lower_indices
    del new_landmark_group['all']  # Remove pointless all group

    return group_label, new_landmark_group
Example #5
0
def ibug_68_contour(landmark_group):
    """
    Apply the ibug's "standard" 68 point semantic labels (based on the
    original semantic labels of multiPIE) to the landmarks in
    the given landmark manager.

    The label applied to this new group will be 'ibug_68_contour'.

    The semantic labels applied are as follows:

      - contour

    Parameters
    ----------
    landmark_group: :class:`menpo.landmark.base.LandmarkGroup`
        The landmark group to apply semantic labels to.

    Returns
    -------
    landmark_group : :class:`menpo.landmark.base.LandmarkGroup`
        New landmark group with label 'ibug_68_contour'

    Raises
    ------
    :class:`menpo.landmark.exceptions.LabellingError`
        If the given landmark set contains less than 68 points

    References
    ----------
    .. [1] http://www.multipie.org/
    """
    # TODO: This should probably be some sort of graph that maintains the
    # connectivity defined by ibug (and thus not a PointCloud)
    group_label = 'ibug_68_contour'
    n_points = landmark_group.lms.n_points

    if n_points != 68:
        raise LabellingError("{0} mark-up expects exactly 68 "
                             "points. However, the given landmark group only "
                             "has {1} points".format(group_label, n_points))

    new_landmarks = copy.deepcopy(landmark_group.lms)
    ind = np.hstack((np.arange(17), np.arange(16, 21),
                     np.arange(21, 26), np.arange(1)))
    new_landmarks.points = new_landmarks.points[ind]
    new_landmark_group = LandmarkGroup(
        landmark_group._target, group_label, new_landmarks,
        {'all': np.ones(new_landmarks.n_points, dtype=np.bool)})

    return new_landmark_group
Example #6
0
def ibug_close_eye_trimesh(landmark_group):
    """
    Apply the ibug's "standard" close eye semantic labels to the
    landmarks in the given landmark group.

    The group label will be 'ibug_close_eye_trimesh'.

    The semantic labels applied are as follows:

      - tri

    Parameters
    ----------
    landmark_group : :map:`LandmarkGroup`
        The landmark group to apply semantic labels to.

    Returns
    -------
    group_label : `str`
        The group label: 'ibug_close_eye_trimesh'
    landmark_group : :map:`LandmarkGroup`
        New landmark group.

    Raises
    ------
    :class:`menpo.landmark.exceptions.LabellingError`
        If the given landmark group contains less than 38 points
    """
    from menpo.shape import TriMesh

    group_label = 'ibug_close_eye_trimesh'
    n_expected_points = 17
    n_points = landmark_group.lms.n_points

    _validate_input(landmark_group, n_expected_points, group_label)

    tri_list = np.array([[10, 11, 13], [ 3, 13,  2], [ 4, 14,  3],
                         [15,  5, 16], [12, 11,  0], [13, 14, 10],
                         [13, 12,  2], [14, 13,  3], [ 0,  1, 12],
                         [ 2, 12,  1], [13, 11, 12], [ 9, 10, 14],
                         [15,  9, 14], [ 7,  8, 15], [ 5,  6, 16],
                         [15, 14,  4], [ 7, 15, 16], [ 8,  9, 15],
                         [15,  4,  5], [16,  6,  7]])

    new_landmark_group = LandmarkGroup(
        TriMesh(landmark_group.lms.points, tri_list, copy=False),
        OrderedDict([('tri', np.ones(n_points, dtype=np.bool))]))

    return group_label, new_landmark_group
Example #7
0
def _relabel_group_from_dict(pointcloud, labels_to_ranges):
    """
    Label the given pointcloud according to the given ordered dictionary
    of labels to ranges. This assumes that you can semantically label the group
    by using ranges in to the existing points e.g ::

        labels_to_ranges = {'chin': (0, 17, False)}

    The third element of the range tuple is whether the range is a closed loop
    or not. For example, for an eye landmark this would be ``True``, as you
    do want to create a closed loop for an eye.

    Parameters
    ----------
    pointcloud : :map:`PointCloud`
        The pointcloud to apply semantic labels to.
    labels_to_ranges : `OrderedDict`
        Ordered dictionary of string labels to range tuples.

    Returns
    -------
    landmark_group: :map:`LandmarkGroup`
        New landmark group

    Raises
    ------
    :class:`menpo.landmark.exceptions.LabellingError`
        If the given pointcloud contains less than ``n_expected_points``
        points.
    """
    from menpo.shape import PointGraph

    n_points = pointcloud.n_points
    masks = OrderedDict()
    adjacency_lists = []
    for label, tup in labels_to_ranges.items():
        range_tuple = tup[:-1]
        close_loop = tup[-1]
        adjacency_lists.append(_connectivity_from_range(
            range_tuple, close_loop=close_loop))
        masks[label] = _mask_from_range(range_tuple, n_points)
    adjacency_array = np.vstack(adjacency_lists)

    new_landmark_group = LandmarkGroup(
        PointGraph(pointcloud.points, adjacency_array), masks)

    return new_landmark_group
        def wrapper(x, return_mapping=False):
            from menpo.shape import PointCloud
            # Accepts LandmarkGroup, PointCloud or ndarray
            if isinstance(x, np.ndarray):
                x = PointCloud(x, copy=False)

            if isinstance(x, PointCloud):
                new_pcloud, mapping = labelling_method(x)
                # This parameter is only provided for internal use so that
                # other labellers can piggyback off one another
                if return_mapping:
                    return new_pcloud, mapping
                else:
                    return new_pcloud
            if isinstance(x, LandmarkGroup):
                new_pcloud, mapping = labelling_method(x.lms)
                return LandmarkGroup.init_from_indices_mapping(
                    new_pcloud, mapping)
Example #9
0
        def wrapper(x, return_mapping=False):
            from menpo.shape import PointCloud
            # Accepts LandmarkGroup, PointCloud or ndarray
            if isinstance(x, np.ndarray):
                x = PointCloud(x, copy=False)

            if isinstance(x, PointCloud):
                new_pcloud, mapping = labelling_method(x)
                # This parameter is only provided for internal use so that
                # other labellers can piggyback off one another
                if return_mapping:
                    return new_pcloud, mapping
                else:
                    return new_pcloud
            if isinstance(x, LandmarkGroup):
                new_pcloud, mapping = labelling_method(x.lms)
                return LandmarkGroup.init_from_indices_mapping(new_pcloud, 
                                                               mapping)
Example #10
0
    def build(self, asset=None):
        """
        Overrides the :meth:`build <menpo.io.base.Importer.build>` method.

        Parse the landmark format and return the label and landmark dictionary.

        Parameters
        ----------
        asset : object, optional
            The asset that the landmarks are being built for. Can be used to
            adjust landmarks as necessary (e.g. rescaling image landmarks
            from 0-1 to image.shape)

        Returns
        -------
        landmark_group : string
            The landmark group parsed from the file.
            Every point will be labelled.
        """
        self._parse_format(asset=asset)
        return LandmarkGroup(self.pointcloud, self.labels_to_masks)
Example #11
0
def lm2_importer(filepath, asset=None, **kwargs):
    r"""
    Importer for the LM2 file format from the bosphorus dataset. This is a 2D
    landmark type and so it is assumed it only applies to images.

    Landmark set label: LM2

    Landmark labels:

    +------------------------+
    | label                  |
    +========================+
    | outer_left_eyebrow     |
    | middle_left_eyebrow    |
    | inner_left_eyebrow     |
    | inner_right_eyebrow    |
    | middle_right_eyebrow   |
    | outer_right_eyebrow    |
    | outer_left_eye_corner  |
    | inner_left_eye_corner  |
    | inner_right_eye_corner |
    | outer_right_eye_corner |
    | nose_saddle_left       |
    | nose_saddle_right      |
    | left_nose_peak         |
    | nose_tip               |
    | right_nose_peak        |
    | left_mouth_corner      |
    | upper_lip_outer_middle |
    | right_mouth_corner     |
    | upper_lip_inner_middle |
    | lower_lip_inner_middle |
    | lower_lip_outer_middle |
    | chin_middle            |
    +------------------------+

    Parameters
    ----------
    filepath : `Path`
        Absolute filepath of the file.
    asset : `object`, optional
        An optional asset that may help with loading. This is unused for this
        implementation.
    \**kwargs : `dict`, optional
        Any other keyword arguments.

    Returns
    -------
    landmarks : :map:`LandmarkGroup`
        The landmarks including appropriate labels if available.
    """
    with open(str(filepath), 'r') as f:
        landmarks = f.read()

    # Remove comments and blank lines
    landmark_text = [
        l for l in landmarks.splitlines() if (l.rstrip() and '#' not in l)
    ]

    # First line says how many landmarks there are: 22 Landmarks
    # So pop it off the front
    num_points = int(landmark_text.pop(0).split()[0])
    labels = []

    # The next set of lines defines the labels
    labels_str = landmark_text.pop(0)
    if not labels_str == 'Labels:':
        raise ValueError("LM2 landmarks are incorrectly formatted. "
                         "Expected a list of labels beginning with "
                         "'Labels:' but found '{0}'".format(labels_str))
    for i in range(num_points):
        # Lowercase, remove spaces and replace with underscores
        l = landmark_text.pop(0)
        l = '_'.join(l.lower().split())
        labels.append(l)

    # The next set of lines defines the coordinates
    coords_str = landmark_text.pop(0)
    if not coords_str == '2D Image coordinates:':
        raise ValueError("LM2 landmarks are incorrectly formatted. "
                         "Expected a list of coordinates beginning with "
                         "'2D Image coordinates:' "
                         "but found '{0}'".format(coords_str))
    xs = []
    ys = []
    for i in range(num_points):
        p = landmark_text.pop(0).split()
        xs.append(float(p[0]))
        ys.append(float(p[1]))

    xs = np.array(xs, dtype=np.float).reshape((-1, 1))
    ys = np.array(ys, dtype=np.float).reshape((-1, 1))

    # Flip the x and y
    pointcloud = PointCloud(np.hstack([ys, xs]), copy=False)
    # Create the mask whereby there is one landmark per label
    # (identity matrix)
    masks = np.eye(num_points).astype(np.bool)
    masks = np.vsplit(masks, num_points)
    masks = [np.squeeze(m) for m in masks]
    labels_to_masks = OrderedDict(zip(labels, masks))

    return LandmarkGroup(pointcloud, labels_to_masks)
Example #12
0
def asf_importer(filepath, asset=None, image_origin=True, **kwargs):
    r"""
    Abstract base class for an importer for the ASF file format.
    Currently **does not support the connectivity specified in the format**.

    Implementations of this class should override the :meth:`_build_points`
    which determines the ordering of axes. For example, for images, the
    `x` and `y` axes are flipped such that the first axis is `y` (height
    in the image domain).

    Landmark set label: ASF

    Landmark labels:

    +---------+
    | label   |
    +=========+
    | all     |
    +---------+

    Parameters
    ----------
    filepath : `Path`
        Absolute filepath of the file.
    asset : `object`, optional
        An optional asset that may help with loading. This is unused for this
        implementation.
    image_origin : `bool`, optional
        If ``True``, assume that the landmarks exist within an image and thus
        the origin is the image origin.
    \**kwargs : `dict`, optional
        Any other keyword arguments.

    Returns
    -------
    landmarks : :map:`LandmarkGroup`
        The landmarks including appropriate labels if available.

    References
    ----------
    .. [1] http://www2.imm.dtu.dk/~aam/datasets/datasets.html
    """
    with open(str(filepath), 'r') as f:
        landmarks = f.read()

    # Remove comments and blank lines
    landmarks = [
        l for l in landmarks.splitlines() if (l.rstrip() and not '#' in l)
    ]

    # Pop the front of the list for the number of landmarks
    count = int(landmarks.pop(0))
    # Pop the last element of the list for the image_name
    image_name = landmarks.pop()

    xs = np.empty([count, 1])
    ys = np.empty([count, 1])
    connectivity = np.empty([count, 2], dtype=np.int)
    for i in range(count):
        # Though unpacked, they are still all strings
        # Only unpack the first 7
        (path_num, path_type, xpos, ypos, point_num, connects_from,
         connects_to) = landmarks[i].split()[:7]
        xs[i, ...] = float(xpos)
        ys[i, ...] = float(ypos)
        connectivity[i, ...] = [int(connects_from), int(connects_to)]

    if image_origin:
        points = np.hstack([ys, xs])
    else:
        points = np.hstack([xs, ys])
    if asset is not None:
        # we've been given an asset. As ASF files are normalized,
        # fix that here
        points = Scale(np.array(asset.shape)).apply(points)

    # TODO: Use connectivity and create a graph type instead of PointCloud
    # edges = scaled_points[connectivity]

    return LandmarkGroup(
        PointCloud(points, copy=False),
        OrderedDict([('all', np.ones(points.shape[0], dtype=np.bool))]))
Example #13
0
def ibug_68_trimesh(landmark_group):
    """
    Apply the ibug's "standard" 68 point semantic labels (based on the
    original semantic labels of multiPIE) to the landmarks in
    the given landmark group.

    The label applied to this new group will be 'ibug_68_trimesh'.

    The semantic labels applied are as follows:

      - tri

    Parameters
    ----------
    landmark_group: :class:`menpo.landmark.base.LandmarkGroup`
        The landmark group to apply semantic labels to.

    Returns
    -------
    landmark_group : :class:`menpo.landmark.base.LandmarkGroup`
        New landmark manager with label 'ibug_68_trimesh'

    Raises
    ------
    :class:`menpo.landmark.exceptions.LabellingError`
        If the given landmark group contains less than 68 points

    References
    ----------
    .. [1] http://www.multipie.org/
    """
    from menpo.shape import TriMesh

    group_label = 'ibug_68_trimesh'
    n_points = landmark_group.lms.n_points

    if n_points != 68:
        raise LabellingError("{0} mark-up expects exactly 68 "
                             "points. However, the given landmark group only "
                             "has {1} points".format(group_label, n_points))

    tri_list = np.array([[47, 29, 28], [44, 43, 23], [38, 20, 21], [47, 28,42],
                        [49, 61, 60], [40, 41, 37], [37, 19, 20], [28, 40, 39],
                        [38, 21, 39], [36,  1, 	0], [48, 59,  4], [49, 60, 48],
                        [67, 59, 60], [13, 53, 14], [61, 51, 62], [57,  8,  7],
                        [52, 51, 33], [61, 67, 60], [52, 63, 51], [66, 56, 57],
                        [35, 30, 29], [53, 52, 35], [37, 36, 17], [18, 37, 17],
                        [37, 38, 40], [38, 37, 20], [19, 37, 18], [38, 39, 40],
                        [28, 29, 40], [41, 36, 37], [27, 39, 21], [41, 31,  1],
                        [30, 32, 31], [33, 51, 50], [33, 30, 34], [31, 40, 29],
                        [36,  0, 17], [31,  2,  1], [31, 41, 40], [ 1, 36, 41],
                        [31, 49,  2], [ 2, 49,  3], [60, 59, 48], [ 3, 49, 48],
                        [31, 32, 50], [48,  4,  3], [59,  5,  4], [58, 67, 66],
                        [ 5, 59, 58], [58, 59, 67], [ 7,  6, 58], [66, 57, 58],
                        [13, 54, 53], [ 7, 58, 57], [ 6,  5, 58], [50, 61, 49],
                        [62, 67, 61], [31, 50, 49], [32, 33, 50], [30, 33, 32],
                        [34, 52, 33], [35, 52, 34], [53, 63, 52], [62, 63, 65],
                        [62, 51, 63], [66, 65, 56], [63, 53, 64], [62, 66, 67],
                        [62, 65, 66], [57, 56,  9], [65, 63, 64], [ 8, 57,  9],
                        [ 9, 56, 10], [10, 56, 11], [11, 56, 55], [11, 55, 12],
                        [56, 65, 55], [55, 64, 54], [55, 65, 64], [55, 54, 12],
                        [64, 53, 54], [12, 54, 13], [45, 46, 44], [35, 34, 30],
                        [14, 53, 35], [15, 46, 45], [27, 28, 39], [27, 42, 28],
                        [35, 29, 47], [30, 31, 29], [15, 35, 46], [15, 14, 35],
                        [43, 22, 23], [27, 21, 22], [24, 44, 23], [44, 47, 43],
                        [43, 47, 42], [46, 35, 47], [26, 45, 44], [46, 47, 44],
                        [25, 44, 24], [25, 26, 44], [16, 15, 45], [16, 45, 26],
                        [22, 42, 43], [50, 51, 61], [27, 22, 42]])
    new_landmark_group = LandmarkGroup(
        landmark_group._target, group_label,
        TriMesh(copy.deepcopy(landmark_group.lms.points), tri_list),
        {'all': np.ones(n_points, dtype=np.bool)})

    return new_landmark_group
Example #14
0
def ibug_49_points(landmark_group):
    """
    Apply the ibug's "standard" 49 point semantic labels (based on the
    original semantic labels of multiPIE but removing the annotations
    corresponding to the chin region and the 2 describing the inner mouth
    corners) to the landmark group.

    The group label will be 'ibug_49_points'.

    The semantic labels applied are as follows:

      - leye
      - reye
      - leyebrow
      - reyebrow
      - mouth
      - nose

    Parameters
    ----------
    landmark_group: :class:`menpo.landmark.base.LandmarkGroup`
        The landmark group to apply semantic labels to.

    Returns
    -------
    landmark_group : :class:`menpo.landmark.base.LandmarkGroup`
        New landmark group with group label 'ibug_49_points'. The pointcloud
        is also copied.

    Raises
    ------
    :class:`menpo.landmark.exceptions.LabellingError`
        If the given landmark group contains less than 68 points

    References
    ----------
    .. [1] http://www.multipie.org/
    """
    group_label = 'ibug_49_points'
    n_points = landmark_group.lms.n_points

    if landmark_group.lms.n_points != 68:
        raise LabellingError("{0} mark-up expects exactly 68 "
                             "points. However, the given landmark group only "
                             "has {1} points".format(group_label, n_points))

    # Ignore the chin region and the 2 inner mouth corners
    new_landmarks = copy.deepcopy(landmark_group.lms)
    ind = np.hstack((np.arange(17, 60), np.arange(61, 64),
                     np.arange(65, 68)))
    new_landmarks.points = new_landmarks.points[ind]
    new_landmark_group = LandmarkGroup(
        landmark_group._target, group_label, new_landmarks,
        {'all': np.ones(new_landmarks.n_points, dtype=np.bool)})

    new_landmark_group['leye'] = np.arange(19, 25)
    new_landmark_group['reye'] = np.arange(25, 31)
    new_landmark_group['leyebrow'] = np.arange(0, 5)
    new_landmark_group['reyebrow'] = np.arange(5, 10)
    new_landmark_group['mouth'] = np.arange(31, 49)
    new_landmark_group['nose'] = np.arange(10, 19)

    return new_landmark_group
Example #15
0
def ibug_open_eye_points(landmark_group):
    """
    Apply the ibug's "standard" open eye semantic labels to the
    landmarks in the given landmark group.

    The group label will be 'ibug_open_eye_points'.

    The semantic labels applied are as follows:

      - upper eyelid
      - lower eyelid
      - iris
      - pupil
      - sclera

    Parameters
    ----------
    landmark_group : :map:`LandmarkGroup`
        The landmark group to apply semantic labels to.

    Returns
    -------
    group_label : `str`
        The group label: 'ibug_open_eye_points'
    landmark_group : :map:`LandmarkGroup`
        New landmark group.

    Raises
    ------
    :class:`menpo.landmark.exceptions.LabellingError`
        If the given landmark group contains less than 38 points
    """
    from menpo.shape import PointGraph

    group_label = 'ibug_open_eye_points'
    n_expected_points = 38
    n_points = landmark_group.lms.n_points

    _validate_input(landmark_group, n_expected_points, group_label)

    upper_el_indices, upper_el_connectivity = _build_upper_eyelid()

    iris_range = (22, 30)
    pupil_range = (30, 38)
    sclera_top = np.arange(12, 17)
    sclera_bottom = np.arange(17, 22)
    sclera_indices = np.hstack((0, sclera_top, 6, sclera_bottom))
    lower_el_top = np.arange(17, 22)
    lower_el_bottom = np.arange(7, 12)
    lower_el_indices = np.hstack((6, lower_el_top, 0, lower_el_bottom))

    iris_connectivity = _connectivity_from_range(iris_range, close_loop=True)
    pupil_connectivity = _connectivity_from_range(pupil_range, close_loop=True)

    sclera_connectivity = zip(sclera_top, sclera_top[1:])
    sclera_connectivity += [(0, 21)]
    sclera_connectivity += zip(sclera_bottom, sclera_bottom[1:])
    sclera_connectivity += [(6, 17)]

    lower_el_connectivity = zip(lower_el_top, lower_el_top[1:])
    lower_el_connectivity += [(6, 7)]
    lower_el_connectivity += zip(lower_el_bottom, lower_el_bottom[1:])
    lower_el_connectivity += [(11, 0)]

    total_connectivity = np.asarray(upper_el_connectivity +
                                    lower_el_connectivity +
                                    iris_connectivity.tolist() +
                                    pupil_connectivity.tolist() +
                                    sclera_connectivity)
    new_landmark_group = LandmarkGroup(
        PointGraph(landmark_group.lms.points, total_connectivity),
        OrderedDict([('all', np.ones(n_points, dtype=np.bool))]))

    new_landmark_group['upper_eyelid'] = upper_el_indices
    new_landmark_group['lower_eyelid'] = lower_el_indices
    new_landmark_group['pupil'] = np.arange(*pupil_range)
    new_landmark_group['iris'] = np.arange(*iris_range)
    new_landmark_group['sclera'] = sclera_indices
    del new_landmark_group['all']  # Remove pointless all group

    return group_label, new_landmark_group
Example #16
0
def ibug_68_trimesh(landmark_group):
    """
    Apply the ibug's "standard" 68 point semantic labels (based on the
    original semantic labels of multiPIE) to the landmarks in
    the given landmark group.

    The group label will be 'ibug_68_trimesh'.

    The semantic labels applied are as follows:

      - tri

    Parameters
    ----------
    landmark_group : :map:`LandmarkGroup`
        The landmark group to apply semantic labels to.

    Returns
    -------
    group_label : `str`
        The group label: 'ibug_68_trimesh'
    landmark_group : :map:`LandmarkGroup`
        New landmark group.

    Raises
    ------
    :class:`menpo.landmark.exceptions.LabellingError`
        If the given landmark group contains less than 68 points

    References
    ----------
    .. [1] http://www.multipie.org/
    """
    from menpo.shape import TriMesh

    group_label = 'ibug_68_trimesh'
    n_expected_points = 68
    n_points = landmark_group.lms.n_points

    _validate_input(landmark_group, n_expected_points, group_label)

    tri_list = np.array([[47, 29, 28], [44, 43, 23], [38, 20, 21], [47, 28,42],
                        [49, 61, 60], [40, 41, 37], [37, 19, 20], [28, 40, 39],
                        [38, 21, 39], [36,  1, 	0], [48, 59,  4], [49, 60, 48],
                        [67, 59, 60], [13, 53, 14], [61, 51, 62], [57,  8,  7],
                        [52, 51, 33], [61, 67, 60], [52, 63, 51], [66, 56, 57],
                        [35, 30, 29], [53, 52, 35], [37, 36, 17], [18, 37, 17],
                        [37, 38, 40], [38, 37, 20], [19, 37, 18], [38, 39, 40],
                        [28, 29, 40], [41, 36, 37], [27, 39, 21], [41, 31,  1],
                        [30, 32, 31], [33, 51, 50], [33, 30, 34], [31, 40, 29],
                        [36,  0, 17], [31,  2,  1], [31, 41, 40], [ 1, 36, 41],
                        [31, 49,  2], [ 2, 49,  3], [60, 59, 48], [ 3, 49, 48],
                        [31, 32, 50], [48,  4,  3], [59,  5,  4], [58, 67, 66],
                        [ 5, 59, 58], [58, 59, 67], [ 7,  6, 58], [66, 57, 58],
                        [13, 54, 53], [ 7, 58, 57], [ 6,  5, 58], [50, 61, 49],
                        [62, 67, 61], [31, 50, 49], [32, 33, 50], [30, 33, 32],
                        [34, 52, 33], [35, 52, 34], [53, 63, 52], [62, 63, 65],
                        [62, 51, 63], [66, 65, 56], [63, 53, 64], [62, 66, 67],
                        [62, 65, 66], [57, 56,  9], [65, 63, 64], [ 8, 57,  9],
                        [ 9, 56, 10], [10, 56, 11], [11, 56, 55], [11, 55, 12],
                        [56, 65, 55], [55, 64, 54], [55, 65, 64], [55, 54, 12],
                        [64, 53, 54], [12, 54, 13], [45, 46, 44], [35, 34, 30],
                        [14, 53, 35], [15, 46, 45], [27, 28, 39], [27, 42, 28],
                        [35, 29, 47], [30, 31, 29], [15, 35, 46], [15, 14, 35],
                        [43, 22, 23], [27, 21, 22], [24, 44, 23], [44, 47, 43],
                        [43, 47, 42], [46, 35, 47], [26, 45, 44], [46, 47, 44],
                        [25, 44, 24], [25, 26, 44], [16, 15, 45], [16, 45, 26],
                        [22, 42, 43], [50, 51, 61], [27, 22, 42]])
    new_landmark_group = LandmarkGroup(
        TriMesh(landmark_group.lms.points, tri_list, copy=False),
        OrderedDict([('tri', np.ones(n_points, dtype=np.bool))]))

    return group_label, new_landmark_group
Example #17
0
def ibug_68_points(landmark_group):
    """
    Apply the ibug's "standard" 68 point semantic labels (based on the
    original semantic labels of multiPIE) to the landmark group.

    The group label will be 'ibug_68_points'.

    The semantic labels applied are as follows:

      - chin
      - leye
      - reye
      - leyebrow
      - reyebrow
      - mouth
      - nose

    Parameters
    ----------
    landmark_group: :class:`menpo.landmark.base.LandmarkGroup`
        The landmark group to apply semantic labels to.

    Returns
    -------
    landmark_group : :class:`menpo.landmark.base.LandmarkGroup`
        New landmark group with group label 'ibug_68_points'. The pointcloud
        is also copied.

    Raises
    ------
    :class:`menpo.landmark.exceptions.LabellingError`
        If the given landmark group contains less than 68 points

    References
    ----------
    .. [1] http://www.multipie.org/
    """
    # TODO: This should probably be some sort of graph that maintains the
    # connectivity defined by ibug (and thus not a PointCloud)
    group_label = 'ibug_68_points'
    n_points = landmark_group.lms.n_points

    if n_points != 68:
        raise LabellingError("{0} mark-up expects exactly 68 "
                             "points. However, the given landmark group only "
                             "has {1} points".format(group_label, n_points))

    new_landmark_group = LandmarkGroup(
        landmark_group._target, group_label,
        copy.deepcopy(landmark_group.lms),
        {'all': np.ones(n_points, dtype=np.bool)})

    new_landmark_group['chin'] = np.arange(17)
    new_landmark_group['leye'] = np.arange(36, 42)
    new_landmark_group['reye'] = np.arange(42, 48)
    new_landmark_group['leyebrow'] = np.arange(17, 22)
    new_landmark_group['reyebrow'] = np.arange(22, 27)
    new_landmark_group['mouth'] = np.arange(48, 68)
    new_landmark_group['nose'] = np.arange(27, 36)

    return new_landmark_group
Example #18
0
def pts_importer(filepath, asset=None, image_origin=True, **kwargs):
    r"""
    Importer for the PTS file format. Assumes version 1 of the format.

    Implementations of this class should override the :meth:`_build_points`
    which determines the ordering of axes. For example, for images, the
    `x` and `y` axes are flipped such that the first axis is `y` (height
    in the image domain).

    Note that PTS has a very loose format definition. Here we make the
    assumption (as is common) that PTS landmarks are 1-based. That is,
    landmarks on a 480x480 image are in the range [1-480]. As Menpo is
    consistently 0-based, we *subtract 1* off each landmark value
    automatically.

    If you want to use PTS landmarks that are 0-based, you will have to
    manually add one back on to landmarks post importing.

    Landmark set label: PTS

    Landmark labels:

    +---------+
    | label   |
    +=========+
    | all     |
    +---------+

    Parameters
    ----------
    filepath : `Path`
        Absolute filepath of the file.
    asset : `object`, optional
        An optional asset that may help with loading. This is unused for this
        implementation.
    image_origin : `bool`, optional
        If ``True``, assume that the landmarks exist within an image and thus
        the origin is the image origin.
    \**kwargs : `dict`, optional
        Any other keyword arguments.

    Returns
    -------
    landmarks : :map:`LandmarkGroup`
        The landmarks including appropriate labels if available.
    """
    f = open(str(filepath), 'r')
    for line in f:
        if line.split()[0] == '{':
            break
    xs = []
    ys = []
    for line in f:
        if line.split()[0] != '}':
            xpos, ypos = line.split()[0:2]
            xs.append(xpos)
            ys.append(ypos)
    xs = np.array(xs, dtype=np.float).reshape((-1, 1))
    ys = np.array(ys, dtype=np.float).reshape((-1, 1))
    # PTS landmarks are 1-based, need to convert to 0-based (subtract 1)
    if image_origin:
        points = np.hstack([ys - 1, xs - 1])
    else:
        points = np.hstack([xs - 1, ys - 1])

    return LandmarkGroup(
        PointCloud(points, copy=False),
        OrderedDict([('all', np.ones(points.shape[0], dtype=np.bool))]))
Example #19
0
def ibug_open_eye_trimesh(landmark_group):
    """
    Apply the ibug's "standard" open eye semantic labels to the
    landmarks in the given landmark group.

    The group label will be 'ibug_open_eye_trimesh'.

    The semantic labels applied are as follows:

      - tri

    Parameters
    ----------
    landmark_group : :map:`LandmarkGroup`
        The landmark group to apply semantic labels to.

    Returns
    -------
    group_label : `str`
        The group label: 'ibug_open_eye_trimesh'
    landmark_group : :map:`LandmarkGroup`
        New landmark group.

    Raises
    ------
    :class:`menpo.landmark.exceptions.LabellingError`
        If the given landmark group contains less than 38 points
    """
    from menpo.shape import TriMesh

    group_label = 'ibug_open_eye_trimesh'
    n_expected_points = 38
    n_points = landmark_group.lms.n_points

    _validate_input(landmark_group, n_expected_points, group_label)

    tri_list = np.array([[29, 36, 28], [22, 13, 23], [12,  1,  2],
                         [29, 30, 37], [13,  3, 14], [13, 12,  2],
                         [19,  8,  9], [25, 33, 24], [36, 37, 33],
                         [24, 32, 31], [33, 37, 31], [35, 34, 27],
                         [35, 36, 33], [ 3, 13,  2], [14, 24, 23],
                         [33, 32, 24], [15, 25, 14], [25, 26, 34],
                         [22, 30, 29], [31, 37, 30], [24, 31, 23],
                         [32, 33, 31], [22, 12, 13], [ 0,  1, 12],
                         [14, 23, 13], [31, 30, 23], [28, 19, 20],
                         [21, 11,  0], [12, 21,  0], [20, 11, 21],
                         [20, 10, 11], [21, 29, 20], [21, 12, 22],
                         [30, 22, 23], [29, 21, 22], [27, 19, 28],
                         [29, 37, 36], [29, 28, 20], [36, 35, 28],
                         [20, 19, 10], [10, 19,  9], [28, 35, 27],
                         [19, 19,  8], [17, 16,  6], [18,  7,  8],
                         [25, 34, 33], [18, 27, 17], [18, 19, 27],
                         [18, 17,  7], [27, 26, 17], [17,  6,  7],
                         [14, 25, 24], [34, 35, 33], [17, 26, 16],
                         [27, 34, 26], [ 3, 15, 14], [15, 26, 25],
                         [ 4, 15,  3], [16, 26, 15], [16,  4,  5],
                         [16, 15,  4], [16,  5,  6], [8, 18, 19]])

    new_landmark_group = LandmarkGroup(
        TriMesh(landmark_group.lms.points, tri_list, copy=False),
        OrderedDict([('tri', np.ones(n_points, dtype=np.bool))]))

    return group_label, new_landmark_group