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
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
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)
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()
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()
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)
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,
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()
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)