Loading .travis.yml +1 −0 Original line number Diff line number Diff line Loading @@ -60,3 +60,4 @@ notifications: - krodriguez@usgs.gov on_success: always on_failure: always autocnet/control/control.py +150 −64 Original line number Diff line number Diff line import collections from time import gmtime, strftime import pandas as pd POINT_TYPE = 2 MEASURE_TYPE = 2 class Point(object): """ An n-image correspondence container class to store information common to all identical correspondences across an image set. Attributes ---------- point_id : int A unique identifier for the given point class CSeries(pd.Series): """ A custom pandas series that can accept additional methods subpixel : bool Whether or not the point has been subpixel registered point_type : an ISIS identifier for the type of the point as defined in the ISIS protobuf spec. correspondences : list of image correspondences """ __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 = [] def __repr__(self): return str(self.point_id) def __eq__(self, other): return self.point_id == other def __hash__(self): return hash(self.point_id) @property def _constructor(self): return CSeries # pragma: no cover def subpixel(self): return self._subpixel @subpixel.setter def subpixel(self, v): if isinstance(v, bool): self._subpixel = v if self._subpixel is True: self.point_type = 3 class C(pd.DataFrame): class Correspondence(object): """ Control network designed in the ISIS format. A single correspondence (image measure). Attributes ---------- n : int Number of control points id : int The index of the point in a matches dataframe (stored as an edge attribute) m : int Number of control measures x : float The x coordinate of the measure in image space creationdate : str The date that this control network was created. modifieddate : str The date that this control network was last modified. Examples -------- This example illustrates the manual creation of a pandas dataframe with a multi-index (created from a list of tuples). >>> 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) y : float The y coordinate of the measure in image space measure_type : int The ISIS measure type as per the protobuf spec serial : str A unique serial number for the image the measure corresponds to In the case of an ISIS cube, this is a valid ISIS serial number, else, None. """ __slots__ = 'id', 'x', 'y', 'measure_type', 'serial' def __init__(self, *args, **kwargs): super(C, self).__init__(*args, **kwargs) self._creationdate = strftime("%Y-%m-%d %H:%M:%S", gmtime()) 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 @property def _constructor(self): return C def __repr__(self): return str(self.id) _constructor_sliced = CSeries def __eq__(self, other): return self.id == other @property def n(self): if not getattr(self, '_n', None): self._n = len(self['pid'].unique()) return self._n def __hash__(self): return hash(self.id) @property def m(self): if not getattr(self, '_m', None): self._m = len(self) return self._m class CorrespondenceNetwork(object): """ A container of points and associated correspondences. The primary data structures are point_to_correspondence and correspondence_to_point. These two attributes store the mapping between point and correspondences. Attributes ---------- point_to_correspondence : dict with key equal to an instance of the Point class and values equal to a list of Correspondences. correspondence_to_point : dict with key equal to a correspondence identifier (not the class) and value equal to a unique point_id (not an instance of the Point class). This attribute serves as a low memory reverse lookup table point_id : int The current 'new' point id if an additional point were to be added n_points : int The number of points in the CorrespondenceNetwork n_measures : int The number of Correspondences in the CorrespondenceNetwork creationdate : str The date the instance of this class was first instantiated modifieddata : str The date this class last had correspondences and/or points added """ 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 creationdate(self): return self._creationdate def n_points(self): return len(self.point_to_correspondence.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 n_measures(self): return len(self.correspondence_to_point.keys()) 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 autocnet/control/tests/test_control.py +52 −10 Original line number Diff line number Diff line Loading @@ -3,7 +3,13 @@ import sys from time import gmtime, strftime import unittest from unittest.mock import Mock, MagicMock from autocnet.graph.edge import Edge from autocnet.graph.node import Node import numpy as np import pandas as pd sys.path.insert(0, os.path.abspath('..')) Loading @@ -12,24 +18,60 @@ from autocnet.control import control class TestC(unittest.TestCase): def setUp(self): x = list(range(10)) y = list(range(10)) pid = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2] nid = [1, 2, 1, 2, 1, 2, 1, 2, 1, 2] @classmethod def setUpClass(cls): npts = 10 coords = pd.DataFrame(np.arange(npts * 2).reshape(-1, 2)) source = np.zeros(npts) destination = np.ones(npts) pid = np.arange(npts) matches = pd.DataFrame(np.vstack((source, pid, destination, pid)).T, columns=['source_image', 'source_idx', 'destination_image', 'destination_idx']) edge = Mock(spec=Edge) edge.source = Mock(spec=Node) edge.destination = Mock(spec=Node) edge.source.isis_serial = None edge.destination.isis_serial = None edge.source.get_keypoint_coordinates = MagicMock(return_value=coords) edge.destination.get_keypoint_coordinates = MagicMock(return_value=coords) data = np.array([x, y, pid, nid]).T cls.C = control.CorrespondenceNetwork() cls.C.add_correspondences(edge, matches) self.C = control.C(data, columns=['x', 'y', 'pid', 'nid']) def test_n_point(self): self.assertEqual(self.C.n, 4) self.assertEqual(self.C.n_points, 10) def test_n_measures(self): self.assertEqual(self.C.m, 10) self.assertEqual(self.C.n_measures, 20) def test_modified_date(self): self.assertEqual(self.C.modifieddate, 'Not modified') self.assertIsInstance(self.C.modifieddate, str) def test_creation_date(self): self.assertEqual(self.C.creationdate, strftime("%Y-%m-%d %H:%M:%S", gmtime())) def test_point_subpixel(self): for k, v in self.C.point_to_correspondence.items(): self.assertFalse(k.subpixel) k.subpixel = True self.assertTrue(k.subpixel) break def test_equalities(self): points = [] correspondences = [] for k, v in self.C.point_to_correspondence.items(): points.append(k) correspondences.extend(v) self.assertEqual(points[0], points[0]) self.assertNotEqual(points[-1], points[1]) self.assertEqual(correspondences[1][0], correspondences[1][0]) def test_to_dataframe(self): self.C.to_dataframe() autocnet/fileio/io_controlnetwork.py +17 −19 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 Loading @@ -27,6 +26,7 @@ def write_filelist(lst, path="fromlist.lis"): handle.write('\n') return def to_isis(path, C, mode='w', version=VERSION, headerstartbyte=HEADERSTARTBYTE, networkid='None', targetname='None', Loading Loading @@ -83,7 +83,6 @@ def to_isis(path, C, mode='w', version=VERSION, point_sizes) # Write the buffer header store.write(buffer_header, HEADERSTARTBYTE) # Then write the points, so we know where to start writing, + 1 to avoid overwrite point_start_offset = HEADERSTARTBYTE + buffer_header_size for i, point in enumerate(point_messages): Loading Loading @@ -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) Loading Loading @@ -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) ]) }), Loading autocnet/fileio/tests/test_io_controlnetwork.py +50 −45 Original line number Diff line number Diff line import os from time import gmtime, strftime import unittest import sys sys.path.insert(0, os.path.abspath('..')) import unittest from unittest.mock import Mock, MagicMock import numpy as np import pandas as pd import pvl Loading @@ -12,44 +10,50 @@ from .. import io_controlnetwork from .. import ControlNetFileV0002_pb2 as cnf from autocnet.utils.utils import find_in_dict from autocnet.control.control import C class TestWriteIsisControlNetwork(unittest.TestCase): def setUp(self): """ Not 100% sure how to mock in the DF without creating lots of methods... """ serial_times = {295: '1971-07-31T01:24:11.754', 296: '1971-07-31T01:24:36.970', 297: '1971-07-31T01:25:02.243', 298: '1971-07-31T01:25:27.457', 299: '1971-07-31T01:25:52.669', 300: '1971-07-31T01:26:17.923'} self.serials = ['APOLLO15/METRIC/{}'.format(i) for i in serial_times.values()] x = list(range(5)) y = list(range(5)) pid = [0,0,1,1,1] idx = pid serials = [self.serials[0], self.serials[1], self.serials[2], self.serials[2], self.serials[3]] from autocnet.control.control import CorrespondenceNetwork from autocnet.graph.edge import Edge from autocnet.graph.node import Node sys.path.insert(0, os.path.abspath('..')) columns = ['x', 'y', 'idx', 'pid', 'nid', 'point_type'] self.data_length = 5 data = [x,y, idx, pid, serials, [2] * self.data_length] class TestWriteIsisControlNetwork(unittest.TestCase): self.creation_time = strftime("%Y-%m-%d %H:%M:%S", gmtime()) cnet = C(data, index=columns).T @classmethod def setUpClass(cls): serial_times = {295: '1971-07-31T01:24:11.754', 296: '1971-07-31T01:24:36.970'} cls.serials = ['APOLLO15/METRIC/{}'.format(i) for i in serial_times.values()] # Create an edge and a set of matches cls.npts = 5 coords = pd.DataFrame(np.arange(cls.npts * 2).reshape(-1, 2)) source = np.zeros(cls.npts) destination = np.ones(cls.npts) pid = np.arange(cls.npts) matches = pd.DataFrame(np.vstack((source, pid, destination, pid)).T, columns=['source_image', 'source_idx', 'destination_image', 'destination_idx']) edge = Mock(spec=Edge) edge.source = Mock(spec=Node) edge.destination = Mock(spec=Node) edge.source.isis_serial = cls.serials[0] edge.destination.isis_serial = cls.serials[1] edge.source.get_keypoint_coordinates = MagicMock(return_value=coords) edge.destination.get_keypoint_coordinates = MagicMock(return_value=coords) cnet = CorrespondenceNetwork() cnet.add_correspondences(edge, matches) cls.creation_date = cnet.creationdate cls.modified_date = cnet.modifieddate io_controlnetwork.to_isis('test.net', cnet, mode='wb', targetname='Moon') self.header_message_size = 85 self.point_start_byte = 65621 cls.header_message_size = 98 cls.point_start_byte = 65634 def test_create_buffer_header(self): with open('test.net', 'rb') as f: Loading @@ -63,20 +67,20 @@ class TestWriteIsisControlNetwork(unittest.TestCase): self.assertEqual('Moon', header_protocol.targetName) self.assertEqual(io_controlnetwork.DEFAULTUSERNAME, header_protocol.userName) self.assertEqual(self.creation_time, self.assertEqual(self.creation_date, header_protocol.created) self.assertEqual('None', header_protocol.description) self.assertEqual('Not modified', header_protocol.lastModified) self.assertEqual(self.modified_date, header_protocol.lastModified) #Repeating self.assertEqual([135, 199], header_protocol.pointMessageSizes) self.assertEqual([135] * self.npts, header_protocol.pointMessageSizes) def test_create_point(self): with open('test.net', 'rb') as f: with open('test.net', 'rb') as f: f.seek(self.point_start_byte) for i, length in enumerate([135, 199]): for i, length in enumerate([135] * self.npts): point_protocol = cnf.ControlPointFileEntryV0002() raw_point = f.read(length) point_protocol.ParseFromString(raw_point) Loading @@ -90,16 +94,17 @@ class TestWriteIsisControlNetwork(unittest.TestCase): pvl_header = pvl.load('test.net') npoints = find_in_dict(pvl_header, 'NumberOfPoints') self.assertEqual(2, npoints) self.assertEqual(5, npoints) mpoints = find_in_dict(pvl_header, 'NumberOfMeasures') self.assertEqual(5, mpoints) self.assertEqual(10, mpoints) points_bytes = find_in_dict(pvl_header, 'PointsBytes') self.assertEqual(334, points_bytes) self.assertEqual(675, points_bytes) points_start_byte = find_in_dict(pvl_header, 'PointsStartByte') self.assertEqual(65621, points_start_byte) self.assertEqual(65634, points_start_byte) def tearDown(self): @classmethod def tearDownClass(cls): os.remove('test.net') Loading
.travis.yml +1 −0 Original line number Diff line number Diff line Loading @@ -60,3 +60,4 @@ notifications: - krodriguez@usgs.gov on_success: always on_failure: always
autocnet/control/control.py +150 −64 Original line number Diff line number Diff line import collections from time import gmtime, strftime import pandas as pd POINT_TYPE = 2 MEASURE_TYPE = 2 class Point(object): """ An n-image correspondence container class to store information common to all identical correspondences across an image set. Attributes ---------- point_id : int A unique identifier for the given point class CSeries(pd.Series): """ A custom pandas series that can accept additional methods subpixel : bool Whether or not the point has been subpixel registered point_type : an ISIS identifier for the type of the point as defined in the ISIS protobuf spec. correspondences : list of image correspondences """ __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 = [] def __repr__(self): return str(self.point_id) def __eq__(self, other): return self.point_id == other def __hash__(self): return hash(self.point_id) @property def _constructor(self): return CSeries # pragma: no cover def subpixel(self): return self._subpixel @subpixel.setter def subpixel(self, v): if isinstance(v, bool): self._subpixel = v if self._subpixel is True: self.point_type = 3 class C(pd.DataFrame): class Correspondence(object): """ Control network designed in the ISIS format. A single correspondence (image measure). Attributes ---------- n : int Number of control points id : int The index of the point in a matches dataframe (stored as an edge attribute) m : int Number of control measures x : float The x coordinate of the measure in image space creationdate : str The date that this control network was created. modifieddate : str The date that this control network was last modified. Examples -------- This example illustrates the manual creation of a pandas dataframe with a multi-index (created from a list of tuples). >>> 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) y : float The y coordinate of the measure in image space measure_type : int The ISIS measure type as per the protobuf spec serial : str A unique serial number for the image the measure corresponds to In the case of an ISIS cube, this is a valid ISIS serial number, else, None. """ __slots__ = 'id', 'x', 'y', 'measure_type', 'serial' def __init__(self, *args, **kwargs): super(C, self).__init__(*args, **kwargs) self._creationdate = strftime("%Y-%m-%d %H:%M:%S", gmtime()) 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 @property def _constructor(self): return C def __repr__(self): return str(self.id) _constructor_sliced = CSeries def __eq__(self, other): return self.id == other @property def n(self): if not getattr(self, '_n', None): self._n = len(self['pid'].unique()) return self._n def __hash__(self): return hash(self.id) @property def m(self): if not getattr(self, '_m', None): self._m = len(self) return self._m class CorrespondenceNetwork(object): """ A container of points and associated correspondences. The primary data structures are point_to_correspondence and correspondence_to_point. These two attributes store the mapping between point and correspondences. Attributes ---------- point_to_correspondence : dict with key equal to an instance of the Point class and values equal to a list of Correspondences. correspondence_to_point : dict with key equal to a correspondence identifier (not the class) and value equal to a unique point_id (not an instance of the Point class). This attribute serves as a low memory reverse lookup table point_id : int The current 'new' point id if an additional point were to be added n_points : int The number of points in the CorrespondenceNetwork n_measures : int The number of Correspondences in the CorrespondenceNetwork creationdate : str The date the instance of this class was first instantiated modifieddata : str The date this class last had correspondences and/or points added """ 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 creationdate(self): return self._creationdate def n_points(self): return len(self.point_to_correspondence.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 n_measures(self): return len(self.correspondence_to_point.keys()) 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
autocnet/control/tests/test_control.py +52 −10 Original line number Diff line number Diff line Loading @@ -3,7 +3,13 @@ import sys from time import gmtime, strftime import unittest from unittest.mock import Mock, MagicMock from autocnet.graph.edge import Edge from autocnet.graph.node import Node import numpy as np import pandas as pd sys.path.insert(0, os.path.abspath('..')) Loading @@ -12,24 +18,60 @@ from autocnet.control import control class TestC(unittest.TestCase): def setUp(self): x = list(range(10)) y = list(range(10)) pid = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2] nid = [1, 2, 1, 2, 1, 2, 1, 2, 1, 2] @classmethod def setUpClass(cls): npts = 10 coords = pd.DataFrame(np.arange(npts * 2).reshape(-1, 2)) source = np.zeros(npts) destination = np.ones(npts) pid = np.arange(npts) matches = pd.DataFrame(np.vstack((source, pid, destination, pid)).T, columns=['source_image', 'source_idx', 'destination_image', 'destination_idx']) edge = Mock(spec=Edge) edge.source = Mock(spec=Node) edge.destination = Mock(spec=Node) edge.source.isis_serial = None edge.destination.isis_serial = None edge.source.get_keypoint_coordinates = MagicMock(return_value=coords) edge.destination.get_keypoint_coordinates = MagicMock(return_value=coords) data = np.array([x, y, pid, nid]).T cls.C = control.CorrespondenceNetwork() cls.C.add_correspondences(edge, matches) self.C = control.C(data, columns=['x', 'y', 'pid', 'nid']) def test_n_point(self): self.assertEqual(self.C.n, 4) self.assertEqual(self.C.n_points, 10) def test_n_measures(self): self.assertEqual(self.C.m, 10) self.assertEqual(self.C.n_measures, 20) def test_modified_date(self): self.assertEqual(self.C.modifieddate, 'Not modified') self.assertIsInstance(self.C.modifieddate, str) def test_creation_date(self): self.assertEqual(self.C.creationdate, strftime("%Y-%m-%d %H:%M:%S", gmtime())) def test_point_subpixel(self): for k, v in self.C.point_to_correspondence.items(): self.assertFalse(k.subpixel) k.subpixel = True self.assertTrue(k.subpixel) break def test_equalities(self): points = [] correspondences = [] for k, v in self.C.point_to_correspondence.items(): points.append(k) correspondences.extend(v) self.assertEqual(points[0], points[0]) self.assertNotEqual(points[-1], points[1]) self.assertEqual(correspondences[1][0], correspondences[1][0]) def test_to_dataframe(self): self.C.to_dataframe()
autocnet/fileio/io_controlnetwork.py +17 −19 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 Loading @@ -27,6 +26,7 @@ def write_filelist(lst, path="fromlist.lis"): handle.write('\n') return def to_isis(path, C, mode='w', version=VERSION, headerstartbyte=HEADERSTARTBYTE, networkid='None', targetname='None', Loading Loading @@ -83,7 +83,6 @@ def to_isis(path, C, mode='w', version=VERSION, point_sizes) # Write the buffer header store.write(buffer_header, HEADERSTARTBYTE) # Then write the points, so we know where to start writing, + 1 to avoid overwrite point_start_offset = HEADERSTARTBYTE + buffer_header_size for i, point in enumerate(point_messages): Loading Loading @@ -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) Loading Loading @@ -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) ]) }), Loading
autocnet/fileio/tests/test_io_controlnetwork.py +50 −45 Original line number Diff line number Diff line import os from time import gmtime, strftime import unittest import sys sys.path.insert(0, os.path.abspath('..')) import unittest from unittest.mock import Mock, MagicMock import numpy as np import pandas as pd import pvl Loading @@ -12,44 +10,50 @@ from .. import io_controlnetwork from .. import ControlNetFileV0002_pb2 as cnf from autocnet.utils.utils import find_in_dict from autocnet.control.control import C class TestWriteIsisControlNetwork(unittest.TestCase): def setUp(self): """ Not 100% sure how to mock in the DF without creating lots of methods... """ serial_times = {295: '1971-07-31T01:24:11.754', 296: '1971-07-31T01:24:36.970', 297: '1971-07-31T01:25:02.243', 298: '1971-07-31T01:25:27.457', 299: '1971-07-31T01:25:52.669', 300: '1971-07-31T01:26:17.923'} self.serials = ['APOLLO15/METRIC/{}'.format(i) for i in serial_times.values()] x = list(range(5)) y = list(range(5)) pid = [0,0,1,1,1] idx = pid serials = [self.serials[0], self.serials[1], self.serials[2], self.serials[2], self.serials[3]] from autocnet.control.control import CorrespondenceNetwork from autocnet.graph.edge import Edge from autocnet.graph.node import Node sys.path.insert(0, os.path.abspath('..')) columns = ['x', 'y', 'idx', 'pid', 'nid', 'point_type'] self.data_length = 5 data = [x,y, idx, pid, serials, [2] * self.data_length] class TestWriteIsisControlNetwork(unittest.TestCase): self.creation_time = strftime("%Y-%m-%d %H:%M:%S", gmtime()) cnet = C(data, index=columns).T @classmethod def setUpClass(cls): serial_times = {295: '1971-07-31T01:24:11.754', 296: '1971-07-31T01:24:36.970'} cls.serials = ['APOLLO15/METRIC/{}'.format(i) for i in serial_times.values()] # Create an edge and a set of matches cls.npts = 5 coords = pd.DataFrame(np.arange(cls.npts * 2).reshape(-1, 2)) source = np.zeros(cls.npts) destination = np.ones(cls.npts) pid = np.arange(cls.npts) matches = pd.DataFrame(np.vstack((source, pid, destination, pid)).T, columns=['source_image', 'source_idx', 'destination_image', 'destination_idx']) edge = Mock(spec=Edge) edge.source = Mock(spec=Node) edge.destination = Mock(spec=Node) edge.source.isis_serial = cls.serials[0] edge.destination.isis_serial = cls.serials[1] edge.source.get_keypoint_coordinates = MagicMock(return_value=coords) edge.destination.get_keypoint_coordinates = MagicMock(return_value=coords) cnet = CorrespondenceNetwork() cnet.add_correspondences(edge, matches) cls.creation_date = cnet.creationdate cls.modified_date = cnet.modifieddate io_controlnetwork.to_isis('test.net', cnet, mode='wb', targetname='Moon') self.header_message_size = 85 self.point_start_byte = 65621 cls.header_message_size = 98 cls.point_start_byte = 65634 def test_create_buffer_header(self): with open('test.net', 'rb') as f: Loading @@ -63,20 +67,20 @@ class TestWriteIsisControlNetwork(unittest.TestCase): self.assertEqual('Moon', header_protocol.targetName) self.assertEqual(io_controlnetwork.DEFAULTUSERNAME, header_protocol.userName) self.assertEqual(self.creation_time, self.assertEqual(self.creation_date, header_protocol.created) self.assertEqual('None', header_protocol.description) self.assertEqual('Not modified', header_protocol.lastModified) self.assertEqual(self.modified_date, header_protocol.lastModified) #Repeating self.assertEqual([135, 199], header_protocol.pointMessageSizes) self.assertEqual([135] * self.npts, header_protocol.pointMessageSizes) def test_create_point(self): with open('test.net', 'rb') as f: with open('test.net', 'rb') as f: f.seek(self.point_start_byte) for i, length in enumerate([135, 199]): for i, length in enumerate([135] * self.npts): point_protocol = cnf.ControlPointFileEntryV0002() raw_point = f.read(length) point_protocol.ParseFromString(raw_point) Loading @@ -90,16 +94,17 @@ class TestWriteIsisControlNetwork(unittest.TestCase): pvl_header = pvl.load('test.net') npoints = find_in_dict(pvl_header, 'NumberOfPoints') self.assertEqual(2, npoints) self.assertEqual(5, npoints) mpoints = find_in_dict(pvl_header, 'NumberOfMeasures') self.assertEqual(5, mpoints) self.assertEqual(10, mpoints) points_bytes = find_in_dict(pvl_header, 'PointsBytes') self.assertEqual(334, points_bytes) self.assertEqual(675, points_bytes) points_start_byte = find_in_dict(pvl_header, 'PointsStartByte') self.assertEqual(65621, points_start_byte) self.assertEqual(65634, points_start_byte) def tearDown(self): @classmethod def tearDownClass(cls): os.remove('test.net')