예제 #1
0
def augment_model(model, multiplier=3, length_scales=(0, 0.1, 1), sds=(1e-5, 1.6e-4, 2.4e-4)):
    assert multiplier > 1 and multiplier % 1 == 0, 'multiplier must be integer and >1'
    from scipy.interpolate import LinearNDInterpolator
    try:
        from sklearn.gaussian_process.kernels import Matern, WhiteKernel
    except:
        print('Requires scikit-learn, install using "conda install scikit-learn"')
        sys.exit()

    points = np.array(model.vertices)
    max_rng = np.max(np.ptp(points, axis=0))

    # white noise to ensure positive definite covariance matrix
    ls = dict(zip(length_scales, sds))
    sd0 = ls.pop(0, 1e-5)
    kernel = WhiteKernel(noise_level=sd0 * max_rng)

    for l, s in ls.items():
        kernel += s ** 2 * Matern(length_scale=l * max_rng, nu=1.5)

    assert False, 'not implemented'

    # TODO: how is the covariance mx constructed again?
    y_cov = kernel(points)

    # TODO: sample gp ??? how to tie existing points and generate the new points in between?
    aug_points, L = mv_normal(points, cov=y_cov)

    # TODO: how to interpolate faces?
    pass

    # interpolate texture
    # TODO: augment texture
    interp = LinearNDInterpolator(points, model.texcoords)
    aug_texcoords = interp(aug_points)

    data = model.as_dict()
    data['faces'] = aug_faces
    data['vertices'] = aug_points
    data['texcoords'] = aug_texcoords
    from visnav.iotools import objloader
    aug_model = objloader.ShapeModel(data=data)
    aug_model.recalc_norms()

    return aug_model, L
예제 #2
0
    def loadObject(self, noisy_model=None):
        genList = self.gl.glGenLists(1)
        self.gl.glNewList(genList, self.gl.GL_COMPILE)
        self.gl.glBegin(self.gl.GL_TRIANGLES)  # GL_POLYGON?
        self.setColor(self._fgColor)
        #self.gl.glEnable(self.gl.GL_COLOR_MATERIAL);
        #self.gl.glMaterialfv(self.gl.GL_FRONT, self.gl.GL_SPECULAR, (0,0,0,1));
        #self.gl.glMaterialfv(self.gl.GL_FRONT, self.gl.GL_SHININESS, (0,));

        if self.systemModel.asteroid.real_shape_model is None:
            rsm = self.systemModel.asteroid.real_shape_model = objloader.ShapeModel(
                fname=self.systemModel.asteroid.target_model_file)
        else:
            rsm = self.systemModel.asteroid.real_shape_model

        if noisy_model is not None:
            sm = noisy_model


#        elif self._add_shape_model_noise and not BATCH_MODE:
#sup = objloader.ShapeModel(fname=SHAPE_MODEL_NOISE_SUPPORT)
#sm, noise, L = tools.apply_noise(rsm, support=np.array(sup.vertices))
#            sm, noise, L = tools.apply_noise(rsm)
        else:
            sm = rsm

        for triangle, norm, tx in sm.faces:
            self.triangle(sm.vertices[triangle[0]], sm.vertices[triangle[1]],
                          sm.vertices[triangle[2]], sm.normals[norm])

        self.gl.glEnd()
        self.gl.glEndList()

        if DEBUG:
            # assume all 32bit (4B) variables, no reuse of vertices
            # => triangle count x (3 vertices + 1 normal) x 3d vectors x bytes per variable
            mem_needed = len(sm.faces) * 4 * 3 * 4
            print('3D model mem use: %.0fx %.0fB => %.1fMB' %
                  (len(sm.faces), 4 * 3 * 4, mem_needed / 1024 / 1024))

        self._object = genList
예제 #3
0
def apply_noise(model, support=(None, None), L=(None, None), len_sc=SHAPE_MODEL_NOISE_LEN_SC,
                noise_lv=SHAPE_MODEL_NOISE_LV['lo'], only_z=False,
                tx_noise=0, tx_noise_len_sc=SHAPE_MODEL_NOISE_LEN_SC, tx_hf_noise=True):
    Sv, St = support
    Lv, Lt = L
    inplace = noise_lv == 0 and model.texfile is None

    if noise_lv > 0:
        noisy_points, avg_dev, Lv = points_with_noise(points=model.vertices, support=Sv, L=Lv,
                                                      noise_lv=noise_lv, len_sc=len_sc, only_z=only_z)
    else:
        noisy_points, avg_dev, Lv = model.vertices, 0, None

    tex = model.tex
    if tx_noise > 0:
        if inplace:
            model.tex = np.ones(model.tex.shape)
        Lt = Lv if Lt is None and tx_noise == noise_lv and tx_noise_len_sc == len_sc else Lt
        tex, tx_avg_dev, Lt = texture_noise(model, support=St, L=Lt, noise_sd=tx_noise,
                                            len_sc=tx_noise_len_sc, hf_noise=tx_hf_noise)

    if inplace:
        model.tex = tex
        noisy_model = model
    else:
        data = model.as_dict()
        data['vertices'] = noisy_points
        if tx_noise > 0:
            data['tex'] = tex
            data['texfile'] = None

        from visnav.iotools import objloader
        noisy_model = objloader.ShapeModel(data=data)
        if noise_lv > 0:
            noisy_model.recalc_norms()
        else:
            noisy_model.normals = model.normals

    return noisy_model, avg_dev, (Lv, Lt)
예제 #4
0
    def __init__(self, hi_res_shape_model=False):
        super(DidymosSecondary, self).__init__()
        self.name = 'Didymos Secondary'

        self.image_db_path = None

        # use ryugu model for this, ryugu ~162m diameter, ryugu-big ~772m diameter (Didy2 & Didy1)
        self.target_model_file = os.path.join(DATA_DIR, 'ryugu+tex-d2-16k.obj')
        self.hires_target_model_file = os.path.join(DATA_DIR,
                                                    'ryugu+tex-d2-400k.obj')

        self.constant_noise_shape_model = {
            '': os.path.join(
                DATA_DIR, 'ryugu+tex-d2-16k.nsm'
            ),  # same as target_model_file but includes error estimate
            'lo': os.path.join(DATA_DIR,
                               'ryugu+tex-d2-4k.nsm'),  # 1/4 the vertices
            'hi': os.path.join(DATA_DIR,
                               'ryugu+tex-d2-1k.nsm'),  # 1/16 the vertices
        }

        self.sample_image_file = None
        self.sample_image_meta_file = None

        self.real_shape_model = objloader.ShapeModel(
            fname=self.hires_target_model_file if hi_res_shape_model else self.
            target_model_file)
        self.render_smooth_faces = False if hi_res_shape_model else True

        self.reflmod_params = {
            1: DidymosPrimary.LUNAR_LAMBERT_PARAMS,  # REFLMOD_LUNAR_LAMBERT
            2: DidymosPrimary.HAPKE_PARAMS,  # REFLMOD_HAPKE
        }

        # for cross section, assume spherical object
        self.max_radius = 105  # in meters, maximum extent of object from asteroid frame coordinate origin
        self.mean_radius = 163 / 2  # in meters, dims = [206, 158, 132]
        self.mean_cross_section = math.pi * self.mean_radius**2

        # Distance = 1180 (1160-1220) m
        # L1, L2 = 999.3, 1354.4 m

        # epoch for orbital elements, 2019-Apr-27.0 TDB
        self.oe_epoch = Time(2458600.5, format='jd')

        # orbital elements (from https://ssd.jpl.nasa.gov/sbdb.cgi?sstr=2065803#content)
        # reference: JPL 134 (heliocentric ecliptic J2000)
        self.eccentricity = .3840204901532592
        self.semimajor_axis = 1.644267950023408 * const.au
        self.inclination = math.radians(3.408560852149408)
        self.longitude_of_ascending_node = math.radians(73.20707998527304)
        self.argument_of_periapsis = math.radians(319.3188822767833)
        self.mean_anomaly = math.radians(124.6176776030496)

        # other, not used
        self.aphelion = 2.275700534134692 * const.au
        self.perihelion = 1.012835365912124 * const.au
        self.orbital_period = 770.1180709731267 * 24 * 3600  # seconds
        # self.true_anomaly = math.radians(145.5260853202137 ??)

        # rotation period 11.92h from https://ssd.jpl.nasa.gov/sbdb.cgi?sstr=2065803#content
        self.rot_epoch = Time('J2000')
        self.rotation_velocity = 2 * math.pi / (11.92 * 3600)  # rad/s

        # asteroid rotation axis in equatorial coordinates
        ra, de, tpm = 310, -84, 0  # ra=lon, de=lat

        self.rotation_pm = math.radians(tpm)
        self.axis_latitude, self.axis_longitude = \
            tuple(map(math.radians, (de, ra) if USE_ICRS else \
                tools.equatorial_to_ecliptic(de * units.deg, ra * units.deg)))

        self.precession_cone_radius = None
        self.precession_period = None
        self.precession_pm = None

        self.set_defaults()
예제 #5
0
    def __init__(self, hi_res_shape_model=False, rosetta_batch='default'):
        super(ChuryumovGerasimenko, self).__init__()
        self.name = '67P/Churyumov-Gerasimenko'

        # from http://imagearchives.esac.esa.int/index.php?/category/167/start-224
        # self._image_db_path = os.path.join(DATA_DIR, 'rosetta-mtp017')
        self.rosetta_batch = 'mtp006' if rosetta_batch == 'default' else rosetta_batch
        self.image_db_path = os.path.join(DATA_DIR,
                                          'rosetta-' + self.rosetta_batch)
        self.target_model_file = os.path.join(DATA_DIR, '67p+tex-16k.obj')

        xtra_hires = os.path.join(
            DATA_DIR,
            'original-shapemodels/67P_C-G_shape_model_MALMER_2015_11_20-in-km.obj'
        )
        if os.path.exists(xtra_hires):
            self.hires_target_model_file = xtra_hires
        else:
            self.hires_target_model_file = os.path.join(
                DATA_DIR, '67p+tex-80k.obj')
            print(('Using lower quality shape model for synthetic navcam ' +
                   'images as highest quality shape model not found: %s') %
                  xtra_hires)

        self.hires_target_model_file_textures = False

        self.render_smooth_faces = False

        self.reflmod_params = {
            1:
            ChuryumovGerasimenko.LUNAR_LAMBERT_PARAMS,  # REFLMOD_LUNAR_LAMBERT
            2: ChuryumovGerasimenko.HAPKE_PARAMS,  # REFLMOD_HAPKE
        }

        # done using `make-const-noise-shapemodel.py data/67p-83k-b.obj data/67p-17k.obj data/67p-17k.nsm`
        self.constant_noise_shape_model = {
            '': os.path.join(
                DATA_DIR, '67p+tex-16k.nsm'
            ),  # same as target_model_file but includes error estimate
            'lo': os.path.join(DATA_DIR, '67p+tex-4k.nsm'),  # 1/4 the vertices
            'hi': os.path.join(DATA_DIR,
                               '67p+tex-1k.nsm'),  # 1/16 the vertices
        }

        sample_image = {
            'mtp003': 'ROS_CAM1_20140531T114923',
            'mtp006': 'ROS_CAM1_20140808T140718',
            'mtp007':
            'ROS_CAM1_20140902T113852',  # ROS_CAM1_20140902T113852, ROS_CAM1_20140923T060854
            'mtp017':
            'ROS_CAM1_20150630T230217',  # ROS_CAM1_20150603T094509, ROS_CAM1_20150612T230217
            'mtp018':
            'ROS_CAM1_20150710T074301',  # ROS_CAM1_20150603T094509, ROS_CAM1_20150612T230217
            'mtp024':
            'ROS_CAM1_20160112T230217',  # ROS_CAM1_20151216T060218, ROS_CAM1_20160112T230217
            'mtp025':
            'ROS_CAM1_20160209T231753',  # ROS_CAM1_20160113T060218, ROS_CAM1_20160209T231753
            'mtp026':
            'ROS_CAM1_20160301T131104',  # ROS_CAM1_20160210T060423, ROS_CAM1_20160301T131104, ROS_CAM1_20160308T231754
        }[self.rosetta_batch]
        self.sample_image_file = os.path.join(self.image_db_path,
                                              sample_image + '_P.png')
        self.sample_image_meta_file = os.path.join(self.image_db_path,
                                                   sample_image + '.LBL')

        self.real_shape_model = objloader.ShapeModel(
            fname=self.hires_target_model_file if hi_res_shape_model else self.
            target_model_file)

        self.max_radius = 3000  # in meters, maximum extent of object from asteroid frame coordinate origin
        self.mean_radius = 2000

        # for cross section, assume spherical object and 2km radius
        self.mean_cross_section = math.pi * self.mean_radius**2

        # epoch for orbital elements, 2010-Oct-22.0 TDB
        self.oe_epoch = Time(2455491.5, format='jd')

        # orbital elements (from https://ssd.jpl.nasa.gov/sbdb.cgi)
        # reference: JPL K154/1 (heliocentric ecliptic J2000)
        self.eccentricity = .6405823233437267
        self.semimajor_axis = 3.464737502510219 * const.au
        self.inclination = math.radians(7.043680712713979)
        self.longitude_of_ascending_node = math.radians(50.18004588418096)
        self.argument_of_periapsis = math.radians(12.69446409956478)
        self.mean_anomaly = math.radians(91.76808585530111)

        # other
        self.aphelion = 5.684187101644357 * const.au
        self.perihelion = 1.245287903376082 * const.au
        self.orbital_period = 2355.612944885578 * 24 * 3600  # seconds
        # self.true_anomaly = math.radians(145.5260853202137 ??)

        # rotation period
        # from http://www.aanda.org/articles/aa/full_html/2015/11/aa26349-15/aa26349-15.html
        #   - 12.4043h (2014 aug-oct)
        # from http://www.sciencedirect.com/science/article/pii/S0019103516301385?via%3Dihub
        #   - 12.4304h (19 May 2015)
        #   - 12.305h (10 Aug 2015)
        self.rot_epoch = Time('J2000')

        # self.rotation_velocity = 2*math.pi/12.4043/3600 # prograde, in rad/s
        # --- above seems incorrect based on the pics, own estimate
        # based on ROS_CAM1_20150720T165249 - ROS_CAM1_20150721T075733
        if False:
            self.rotation_velocity = 2 * math.pi / 12.4043 / 3600
        else:
            # variable rotation velocity correction in degrees per day
            correction = {
                'default': -0.4 / 25,  # 2014-08-01 - 2014-09-02
                'mtp003': 0.00,  # 2014-08-01 - 2014-09-02
                'mtp006': 0.006088,  # 2014-08-01 - 2014-09-02
                'mtp007': 0.011987,  # 2014-09-02 - 2014-09-23
                'mtp017': -0.652648,  # 2015-06-03 - 2015-06-30
                'mtp018': 0.023459,  # 2015-06-30 - 2015-
                'mtp024': 19.170419,  # 2015-12-16 - 2016-01-12
                'mtp025': 19.623067,  # 2016-01-13 - 2016-02-09
                'mtp026': 19.857628,  # 2016-02-10 - 2016-03-08
            }[rosetta_batch]
            self.rotation_velocity = 2 * math.pi / 12.4043 / 3600 + math.radians(
                correction) / 24 / 3600  # 0.3754

        # for rotation phase shift, will use as equatorial longitude of
        #   asteroid zero longitude (cheops) at J2000, based on 20150720T165249
        #   papar had 114deg in it
        # for precession cone center (J2000), paper had 69.54, 64.11
        if False:
            tlat, tlon, tpm = 69.54, 64.11, 114
        else:
            # rotation phase shift in degrees for different batches
            tpm = {
                'default': -9,  # 2014-08-01 - 2014-09-02
                'mtp003': 0,  # 2014-08-01 - 2014-09-02
                'mtp006': -127.05,  # 2014-08-01 - 2014-09-02
                'mtp007': -158.68,  # 2014-09-02 - 2014-09-23
                'mtp017': -150.09,  # 2015-06-03 - 2015-06-30
                'mtp018': -9.65,  # 2015-06-30 - 2015-
                'mtp024': 83.90,  # 2015-12-16 - 2016-01-12
                'mtp025': -46.27,  # 2016-01-13 - 2016-02-09
                'mtp026': 13.40,  # 2016-02-10 - 2016-03-08
            }[rosetta_batch]
            tlat, tlon = 64.11, 69.54

        self.rotation_pm = math.radians(tpm)
        self.axis_latitude, self.axis_longitude = \
            tuple(map(math.radians, (tlat, tlon) if USE_ICRS else \
                tools.equatorial_to_ecliptic(tlat * units.deg, tlon * units.deg)))

        self.precession_cone_radius = math.radians(
            0.14)  # other paper 0.15+-0.03 deg
        self.precession_period = 10.7 * 24 * 3600  # other paper had 11.5+-0.5 days
        self.precession_pm = math.radians(0.288)

        self.set_defaults()
예제 #6
0
        res = tools.poly_line_intersect(((0, 0, 1), (0, 1, 1), (1, 0, 1)),
                                        ((0, 0, 0), (.3, .7, 1)))
        print('%s' % res)
        quit()

    assert len(
        sys.argv
    ) == 4, 'USAGE: %s [full-res-model] [target-model] [output]' % sys.argv[0]

    full_res_model = os.path.join(BASE_DIR, sys.argv[1])
    infile = os.path.join(BASE_DIR, sys.argv[2])
    outfile = os.path.join(BASE_DIR, sys.argv[3])
    sc = 1000  # bennu in meters, ryugu & 67P in km

    # load shape models
    obj_fr = objloader.ShapeModel(fname=full_res_model)
    obj = objloader.ShapeModel(fname=infile)

    timer = tools.Stopwatch()
    timer.start()
    devs = tools.point_cloud_vs_model_err(np.array(obj_fr.vertices), obj)
    timer.stop()
    # doesnt work: tools.intersections.parallel_diagnostics(level=4)

    p50 = np.median(devs)
    p68, p95, p99 = np.percentile(np.abs(devs - p50), (68, 95, 99.7))

    idxs = np.abs(devs - p50) < p95
    clean_devs = devs[idxs]
    dev_mean = np.mean(clean_devs)
    dev_std = np.std(clean_devs)
예제 #7
0
        re = RenderEngine(sm.cam.width, sm.cam.height, antialias_samples=16)
        #obj_idx = re.load_object(sm.asteroid.target_model_file, smooth=False)
        obj_idx = re.load_object(sm.asteroid.hires_target_model_file,
                                 smooth=False)
        quit()
        #obj_idx = re.load_object(os.path.join(DATA_DIR, 'original-shapemodels/CSHP_DV_130_01_HIRES_00200.obj'), smooth=False)
        #obj_idx = re.load_object(os.path.join(DATA_DIR, 'original-shapemodels/dissolved_5deg_1.obj'), smooth=False)
        #obj_idx = re.load_object(os.path.join(DATA_DIR, 'original-shapemodels/67P_C-G_shape_model_MALMER_2015_11_20-in-km.obj'), smooth=False)
        textures = False
    else:
        re = RenderEngine(sm.cam.width, sm.cam.height, antialias_samples=0)
        fname = sm.asteroid.constant_noise_shape_model[
            '']  # ''=>17k, 'lo'=>4k, 'hi'=>1k
        with open(fname, 'rb') as fh:
            noisy_model, sm_noise = pickle.load(fh)
        obj_idx = re.load_object(objloader.ShapeModel(data=noisy_model),
                                 smooth=sm.asteroid.render_smooth_faces)
        #obj_idx = re.load_object(sm.asteroid.target_model_file, smooth=False)
        textures = False

    ab = AlgorithmBase(sm, re, obj_idx)

    hapke = True
    model = RenderEngine.REFLMOD_HAPKE if hapke else RenderEngine.REFLMOD_LUNAR_LAMBERT
    size = (1024, 1024)  # (256, 256)

    real = cv2.imread(os.path.join(sm.asteroid.image_db_path, img + '_P.png'),
                      cv2.IMREAD_GRAYSCALE)

    if 1:
        img, dist = ab.render(shadows=True,
예제 #8
0
    def __init__(self, hi_res_shape_model=False):
        super(Bennu, self).__init__()
        self.name = 'Bennu'

        # xtra_hires = os.path.join(DATA_DIR, 'original-shapemodels/bennu.orex.obj')
        xtra_hires = os.path.join(DATA_DIR, 'bennu+tex-98k-v3.obj')
        if os.path.exists(xtra_hires):
            self.hires_target_model_file = xtra_hires
        else:
            raise FileNotFoundError('cant find shape model file %s' %
                                    xtra_hires)

        self.image_db_path = os.path.join(DATA_DIR, 'bennu')
        self.target_model_file = xtra_hires
        self.hires_target_model_file_textures = False
        self.render_smooth_faces = False

        self.reflmod_params = {
            1: Bennu.LUNAR_LAMBERT_PARAMS,  # REFLMOD_LUNAR_LAMBERT
            2: Bennu.HAPKE_PARAMS,  # REFLMOD_HAPKE
        }

        # done using `make-const-noise-shapemodel.py data/bennu-98k.obj data/bennu-16k.obj data/bennu-16k.nsm`
        self.constant_noise_shape_model = {
            '': os.path.join(
                DATA_DIR, 'bennu+tex-16k.nsm'
            ),  # same as target_model_file but includes error estimate
            'lo': os.path.join(DATA_DIR,
                               'bennu+tex-4k.nsm'),  # 1/4 the vertices
            'hi': os.path.join(DATA_DIR,
                               'bennu+tex-1k.nsm'),  # 1/16 the vertices
        }

        sample_image = 'placeholder'
        self.sample_image_file = os.path.join(self.image_db_path,
                                              sample_image + '_P.png')
        self.sample_image_meta_file = os.path.join(self.image_db_path,
                                                   sample_image + '.LBL')

        self.real_shape_model = objloader.ShapeModel(
            fname=self.hires_target_model_file if hi_res_shape_model else self.
            target_model_file)

        self.max_radius = 285  # in meters, maximum extent of object from asteroid frame coordinate origin
        self.mean_radius = 245

        # for cross section, assume spherical object and 2km radius
        self.mean_cross_section = math.pi * self.mean_radius**2

        # epoch for orbital elements, 2011-Jan-01.0 TDB
        self.oe_epoch = Time(2455562.5, format='jd')

        # orbital elements (from https://ssd.jpl.nasa.gov/sbdb.cgi)
        # reference: JPL K154/1 (heliocentric ecliptic J2000)
        self.eccentricity = .203745108478542
        self.semimajor_axis = 1.126391025934071 * const.au
        self.inclination = math.radians(6.034939533607825)
        self.longitude_of_ascending_node = math.radians(2.060867329373625)
        self.argument_of_periapsis = math.radians(66.22306846088361)
        self.mean_anomaly = math.radians(101.7039479473255)

        # other
        self.aphelion = 1.355887687702265 * const.au
        self.perihelion = .8968943641658774 * const.au
        self.orbital_period = 436.6487281348487 * 24 * 3600  # seconds
        # self.true_anomaly = math.radians(145.5260853202137 ??)

        # rotation period from https://en.wikipedia.org/wiki/101955_Bennu
        self.rot_epoch = Time('J2000')
        self.rotation_velocity = 2 * math.pi / 4.296057 / 3600

        # rotation axis dec, ra, unknown offset
        tlat, tlon, tpm = -60.17, 85.65, 0

        self.rotation_pm = math.radians(tpm)
        self.axis_latitude, self.axis_longitude = \
            tuple(map(math.radians, (tlat, tlon) if USE_ICRS else \
                tools.equatorial_to_ecliptic(tlat * units.deg, tlon * units.deg)))

        # unknown and unused for now
        self.precession_cone_radius = math.radians(0)
        self.precession_period = 1 * 24 * 3600
        self.precession_pm = math.radians(0)

        self.set_defaults()
예제 #9
0
 def render(fname):
     with open(fname, 'rb') as fh:
         noisy_model, _loaded_sm_noise = pickle.load(fh)
     render_engine.load_object(objloader.ShapeModel(data=noisy_model), obj_idx, smooth=sm.asteroid.render_smooth_faces)
     return cv2.resize(ab.render(shadows=True, reflection=RenderEngine.REFLMOD_LUNAR_LAMBERT), size)