Commit da3c9b66 authored by Kelvin Rodriguez's avatar Kelvin Rodriguez Committed by GitHub
Browse files

Adding isis ground_to_image/image_to_ground variants in (#331)

* added cnet matcher

* removed old mosaic matcher

* removed old mosaic matcher

Updated db to use mixin and adds tests

try except srid config table look up and PROJ_LIB set in Demo nb (#301)

added param

geopandas -> gpd

removed less than useful error message

* fixing some stuff

* distance check for phase matcher

* potential bug in subpixel

* python loops are dumb

* left print line in matcher

* removed unused init lines

* removed try except

* added isis image_to_ground/ground_to_image calls

* sample -> samp

* I hate everything

* I hate everything

* added code to prefer isis footprints over CSM if available

* updated comments

* addressed jesses comments on the comments
parent 5a09f394
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -649,9 +649,15 @@ class NetworkNode(Node):
    @property
    def footprint(self):
        res = Session().query(Images).filter(Images.id == self['node_id']).first()
        # not in database, create footprint
        if res is None:
            # get ISIS footprint if possible
            if utils.find_in_dict(self.geodata.metadata, "Polygon"):
                footprint_latlon =  shapely.wkt.loads(self.geodata.footprint.ExportToWkt())
                return footprint_latlon
            # Get CSM footprint
            else:
                boundary = generate_boundary(self.geodata.raster_size[::-1])  # yx to xy
            spatial = config.get('spatial')
                try:
                    geodata = GeoDataset(spatial.get('dem'))
                except Exception as e:
@@ -660,6 +666,7 @@ class NetworkNode(Node):
                footprint_latlon = generate_latlon_footprint(self.camera, boundary, dem=geodata)
                footprint_latlon.FlattenTo2D()
        else:
            # in database, return footprint
            footprint_latlon = res.footprint_latlon
            return footprint_latlon

+2 −2
Original line number Diff line number Diff line
@@ -163,7 +163,7 @@ def themis_ground_to_ctx_matcher(cnet):
                dx, dy = scaled_ctx_sample, scaled_ctx_line
                try:
                    # not sure what the best parameters are here
                    ret = iterative_phase(sx, sy, dx, dy, themis_arr, ctx_arr, size=30, reduction=1, convergence_threshold=2)
                    ret = iterative_phase(sx, sy, dx, dy, themis_arr, ctx_arr, size=20, reduction=1, max_dist=2, convergence_threshold=2)
                except Exception as ex:
                    match_results.append(ex)
                    continue
@@ -197,7 +197,7 @@ def themis_ground_to_ctx_matcher(cnet):

            images.append(row["path"])
            ctx_constrained_net.append([cpoint,                # point id
                                       3,                      # point type
                                       4,                      # point type
                                       "autocnet",             # choosername
                                       measure["datetime"].iloc[1],    # datetime
                                       False,                  # EditLock
+96 −0
Original line number Diff line number Diff line
import pvl
from pysis import isis
from warnings import warn
from pysis.exceptions import ProcessError
from numbers import Number
import numpy as np
import tempfile

def point_info(cube_path, x, y, point_type):
    """
    Use Isis's campt to get image/ground point info from an image

    Parameters
    ----------
    cube_path : str
                path to the input cube

    x : float
        point in the x direction. Either a sample or a longitude value
        depending on the point_type flag

    y : float
        point in the y direction. Either a line or a latitude value
        depending on the point_type flag

    point_type : str
                 Options: {"image", "ground"}
                 Pass "image" if  x,y are in image space (sample, line) or
                 "ground" if in ground space (longitude, lattiude)

    Returns
    -------
    : PvlObject
      Pvl object containing campt returns
    """
    if isinstance(x, Number) and isinstance(y, Number):
        x, y = [x], [y]

    with tempfile.NamedTemporaryFile("w+") as f:
        # ISIS wants points in a file, so write to a temp file
        f.write("\n".join(["{}, {}".format(xval,yval) for xval,yval in zip(x, y)]))
        f.flush()
        try:
            pvlres = isis.campt(from_=cube_path, coordlist=f.name ,usecoordlist=True, coordtype=point_type)
        except ProcessError as e:
            warn(f"CAMPT call failed, image: {cube_path}\n{e.stderr}")
            return

        pvlres = pvl.loads(pvlres)

    return pvlres


def image_to_ground(cube_path, line, sample, lattype="PlanetocentricLatitude", lonttype="PositiveEast360Longitude"):
    """
    Use Isis's campt to convert a line sample point on an image to lat lon

    Returns
    -------
    lats : np.array, float
           1-D array of latitudes or single floating point latitude

    lons : np.array, float
           1-D array of longitudes or single floating point longitude

    """
    # campt always does x,y
    pvlres = point_info(cube_path, sample, line, "image")
    lats, lons = np.asarray([[r[1][lattype].value, r[1][lonttype].value] for r in pvlres]).T
    if len(lats) == 1 and len(lons) == 1:
        lats, lons = lats[0], lons[0]

    return lats, lons

def ground_to_image(cube_path, lat, lon):
    """
    Use Isis's campt to convert a lat lon point to line sample in
    an image

    Returns
    -------
    lines : np.array, float
            array of lines or single flaoting point line

    samples : np.array, float
              array of samples or single dloating point sample

    """

    pvlres = point_info(cube_path, lat, lon, "ground")
    lines, samples = np.asarray([[r[1]["Line"], r[1]["Sample"]] for r in pvlres]).T
    if len(lines) == 1 and len(samples) == 1:
        lines, samples = lines[0], samples[0]
    return lines, samples

+34 −7
Original line number Diff line number Diff line
@@ -11,9 +11,12 @@ from autocnet import config, Session, engine
from autocnet.cg import cg as compgeom
from autocnet.io.db.model import Images, Measures, Overlay, Points
from autocnet.matcher.subpixel import iterative_phase
from autocnet.spatial import isis

from plurmy import Slurm
import csmapi


# SQL query to decompose pairwise overlaps
compute_overlaps_sql = """
WITH intersectiongeom AS
@@ -82,7 +85,7 @@ def place_points_in_overlaps(cg, size_threshold=0.0007,

def cluster_place_points_in_overlaps(size_threshold=0.0007,
                                     iterative_phase_kwargs={'size':71},
                                     walltime='00:10:00'):
                                     walltime='00:10:00', cam_type="csm"):
    """
    Place points in all of the overlap geometries by back-projecing using
    sensor models. This method uses the cluster to process all of the overlaps
@@ -100,6 +103,10 @@ def cluster_place_points_in_overlaps(size_threshold=0.0007,

    walltime : str
        Cluster job wall time as a string HH:MM:SS

    cam_type : str
               options: {"csm", "isis"}
               Pick what kind of camera model implementation to use
    """
    if not Session:
        warnings.warn('This function requires a database connection configured via an autocnet config file.')
@@ -122,7 +129,8 @@ def cluster_place_points_in_overlaps(size_threshold=0.0007,
    for overlap in overlaps:
        msg = {'id' : overlap.id,
               'iterative_phase_kwargs' : iterative_phase_kwargs,
               'walltime' : walltime}
               'walltime' : walltime,
               'cam_type': cam_type}
        rqueue.rpush(queuename, json.dumps(msg))
    job_counter = len([*overlaps]) + 1

@@ -135,7 +143,7 @@ def cluster_place_points_in_overlaps(size_threshold=0.0007,
    submitter.submit(array='1-{}'.format(job_counter))
    return job_counter

def place_points_in_overlap(nodes, geom, dem=None,
def place_points_in_overlap(nodes, geom, dem=None, cam_type="csm",
                            iterative_phase_kwargs={'size':71}):
    """
    Place points into an overlap geometry by back-projecing using sensor models.
@@ -155,11 +163,20 @@ def place_points_in_overlap(nodes, geom, dem=None,
    iterative_phase_kwargs : dict
        Dictionary of keyword arguments for the iterative phase matcher function

    cam_type : str
               options: {"csm", "isis"}
               Pick what kind of camera model implementation to use

    Returns
    -------
    points : list of Points
        The list of points seeded in the overlap
    """
    avail_cams = {"isis", "csm"}
    cam_type = cam_type.lower()
    if cam_type not in cam_type:
        raise Exception(f'{cam_type} is not one of valid camera: {avail_cams}')

    points = []
    semi_major = config['spatial']['semimajor_rad']
    semi_minor = config['spatial']['semiminor_rad']
@@ -181,6 +198,7 @@ def place_points_in_overlap(nodes, geom, dem=None,
        point = Points(geom=geom,
                       pointtype=2) # Would be 3 or 4 for ground

        if cam_type == "csm":
            # Calculate the height, the distance (in meters) above or
            # below the aeroid (meters above or below the BCBF spheroid).
            if dem is None:
@@ -192,18 +210,26 @@ def place_points_in_overlap(nodes, geom, dem=None,
            # Get the BCEF coordinate from the lon, lat
            x, y, z = pyproj.transform(lla, ecef, lon, lat, height)
            gnd = csmapi.EcefCoord(x, y, z)

            sic = source_camera.groundToImage(gnd)
        point.measures.append(Measures(sample=sic.samp,
                                       line=sic.line,
            ssample, sline = sic.samp, sic.line
        if cam_type == "isis":
            sline, ssample = isis.ground_to_image(source["data"]["image_path"], lat ,lon)

        point.measures.append(Measures(sample=ssample,
                                       line=sline,
                                       imageid=source['node_id'],
                                       serial=source.isis_serial,
                                       measuretype=3))


        for i, dest in enumerate(nodes):
            if cam_type == "csm":
                dic = dest.camera.groundToImage(gnd)
            dx, dy, _ = iterative_phase(sic.samp, sic.line, dic.samp, dic.line,
                dline, dsample = dic.line, dic.samp
            if cam_type == "isis":
                dline, dsample = isis.groud_to_image(dest["data"]["image_path"], lat, lon)

            dx, dy, _ = iterative_phase(ssample, sline, dsample, dline,
                                        source.geodata, dest.geodata,
                                        **iterative_phase_kwargs)
            if dx is not None or dy is not None:
@@ -215,3 +241,4 @@ def place_points_in_overlap(nodes, geom, dem=None,
        if len(point.measures) >= 2:
            points.append(point)
    return points
+2 −1
Original line number Diff line number Diff line
@@ -42,8 +42,9 @@ def main(msg, config):
        gd = GeoDataset(dem)
    else:
        gd = None

    print('Placing points in overlap', id)
    points = place_points_in_overlap(nodes, overlap.geom, gd,
    points = place_points_in_overlap(nodes, overlap.geom, gd, msg["cam_type"]
                                     msg['iterative_phase_kwargs'])
    session.add_all(points)
    session.commit()
+14 −14

File changed.

Contains only whitespace changes.