Commit 16609f4a authored by jay's avatar jay
Browse files

Updates to the CorrespondenceNetwork logic and IO.

parent c70bf3e4
Loading
Loading
Loading
Loading
+84 −67
Original line number Diff line number Diff line
import collections
from time import gmtime, strftime

import pandas as pd
class Point(object):
    """

POINT_TYPE = 2
MEASURE_TYPE = 2
    """
    __slots__ = '_subpixel', 'point_id', 'point_type', 'correspondences'

    def __init__(self, pid, point_type=2):
        self.point_id = pid
        self._subpixel = False
        self.point_type = point_type
        self.correspondences = []

class CSeries(pd.Series):
    """
    A custom pandas series that can accept additional methods
    """
    @property
    def _constructor(self):
        return CSeries  # pragma: no cover
    def __repr__(self):
        return str(self.point_id)

    def __eq__(self, other):
        return self.point_id == other

class C(pd.DataFrame):
    """
    Control network designed in the ISIS format.
    def __hash__(self):
        return hash(self.point_id)

    Attributes
    ----------
    @property
    def subpixel(self):
        return self._subpixel

    n : int
        Number of control points
    @subpixel.setter
    def subpixel(self, v):
        if isinstance(v, bool):
            self._subpixel = v
        if self._subpixel is True:
            self.point_type = 3

    m : int
        Number of control measures

    creationdate : str
                   The date that this control network was created.
class Correspondence(object):

    modifieddate : str
                   The date that this control network was last modified.
    __slots__ = 'id', 'x', 'y', 'measure_type', 'serial'

    Examples
    --------
    This example illustrates the manual creation of a pandas dataframe with
    a multi-index (created from a list of tuples).
    def __init__(self, id, x, y, measure_type=2, serial=None):
        self.id = id
        self.x = x
        self.y = y
        self.measure_type = measure_type
        self.serial = serial

    >>> ids = ['pt1','pt1', 'pt1', 'pt2', 'pt2']
    >>> ptype = [2,2,2,2,2]
    >>> serials = ['a', 'b', 'c', 'b', 'c']
    >>> mtype = [2,2,2,2,2]
    >>> multi_index = pd.MultiIndex.from_tuples(list(zip(ids, ptype, serials, mtype)),\
                                    names=['Id', 'Type', 'Serial Number', 'Measure Type'])
    >>> columns = ['Random Number']
    >>> data_length = 5
    >>> data = np.random.randn(data_length)
    >>> C = control.C(data, index=multi_index, columns=columns)

    """
    def __repr__(self):
        return str(self.id)

    def __init__(self, *args, **kwargs):
        super(C, self).__init__(*args, **kwargs)
        self._creationdate = strftime("%Y-%m-%d %H:%M:%S", gmtime())
    def __eq__(self, other):
        return self.id == other

    @property
    def _constructor(self):
        return C
    def __hash__(self):
        return hash(self.id)

    _constructor_sliced = CSeries

    @property
    def n(self):
        if not getattr(self, '_n', None):
            self._n = len(self['pid'].unique())
        return self._n
class CorrespondenceNetwork(object):
    def __init__(self):
        self.point_to_correspondence = collections.defaultdict(list)
        self.correspondence_to_point = {}
        self.point_id = 0
        self.creationdate = strftime("%Y-%m-%d %H:%M:%S", gmtime())
        self.modifieddate = strftime("%Y-%m-%d %H:%M:%S", gmtime())

    @property
    def m(self):
        if not getattr(self, '_m', None):
            self._m = len(self)
        return self._m
    def n_points(self):
        return len(self.point_to_correspondence.keys())

    @property
    def creationdate(self):
        return self._creationdate
    def n_measures(self):
        return len(self.correspondence_to_point.keys())

    @property
    def modifieddate(self):
        if not getattr(self, '_modifieddate', None):
            self._modifieddate = 'Not modified'
        return self._modifieddate

    '''
    @modifieddate.setter
    def update_modifieddate(self):
        self._modifieddate = strftime("%Y-%m-%d %H:%M:%S", gmtime())
    '''
    def add_correspondences(self, edge, matches):
        # Convert the matches dataframe to a dict
        df = matches.to_dict()
        source_image = next(iter(df['source_image'].values()))
        destination_image = next(iter(df['destination_image'].values()))

        # TODO: Handle subpixel registration here
        s_kps = edge.source.get_keypoint_coordinates().values
        d_kps = edge.destination.get_keypoint_coordinates().values

        # Load the correspondence to point data structure
        for k, source_idx in df['source_idx'].items():
            p = Point(self.point_id)
            destination_idx = df['destination_idx'][k]

            sidx = Correspondence(source_idx, *s_kps[source_idx], serial=edge.source.isis_serial)
            didx = Correspondence(destination_idx, *d_kps[destination_idx], serial=edge.destination.isis_serial)

            p.correspondences = [sidx, didx]

            self.correspondence_to_point[(source_image, source_idx)] = self.point_id
            self.correspondence_to_point[(destination_image, destination_idx)] = self.point_id

            self.point_to_correspondence[p].append((source_image, sidx))
            self.point_to_correspondence[p].append((destination_image, didx))

            self.point_id += 1
        self._update_modified_date()

    def _update_modified_date(self):
        self.modifieddate = strftime("%Y-%m-%d %H:%M:%S", gmtime())

    def to_dataframe(self):
        pass
+15 −17
Original line number Diff line number Diff line
import pvl

from autocnet.fileio import ControlNetFileV0002_pb2 as cnf
from autocnet.control.control import POINT_TYPE, MEASURE_TYPE

#TODO: Protobuf3 should be a conditional import, if availble use it, otherwise bail

@@ -150,28 +149,27 @@ class IsisStore(object):
        """
        point_sizes = []
        point_messages = []
        for pid, point in cnet.groupby('pid'):
            # Instantiate the proto spec
            point_spec = cnf.ControlPointFileEntryV0002()

            # Get the subset of the dataframe
            try:
                point_spec.id = pid
            except:
        for pid, measure_list in cnet.point_to_correspondence.items():
            point_spec = cnf.ControlPointFileEntryV0002()
            point_spec.id = str(pid)
            point_spec.type = POINT_TYPE
            point_spec.type = pid.point_type

            # The reference index should always be the image with the lowest index
            point_spec.referenceIndex = 0

            # A single extend call is cheaper than many add calls to pack points
            measure_iterable = []
            for name, row in point.iterrows():

            for node_id, m in measure_list:
                measure_spec = point_spec.Measure()
                measure_spec.serialnumber = row.nid
                measure_spec.type = row.point_type
                measure_spec.sample = row.x
                measure_spec.line = row.y
                try:
                    measure_spec.serialnumber = m.serial
                except:
                    measure_spec.serialnumber = str(m.serial)
                measure_spec.type = m.measure_type
                measure_spec.sample = float(m.x)
                measure_spec.line = float(m.y)

                measure_iterable.append(measure_spec)
            point_spec.measures.extend(measure_iterable)
@@ -291,8 +289,8 @@ class IsisStore(object):
                        ('Created', cnet.creationdate),
                        ('LastModified', cnet.modifieddate),
                        ('Description', description),
                        ('NumberOfPoints', cnet.n),
                        ('NumberOfMeasures', cnet.m),
                        ('NumberOfPoints', cnet.n_points),
                        ('NumberOfMeasures', cnet.n_measures),
                        ('Version', version)
                        ])
                  }),