Beispiel #1
0
    def scene_features(self, feat, maxmem, i1, i2):
        try:
            ref_img, depth = self.render_scene(i1, i2)
        except InvalidSceneException:
            return None

        # get keypoints and descriptors
        ref_kp, ref_desc, self._latest_detector = KeypointAlgo.detect_features(ref_img, feat, maxmem=maxmem,
                                                                               max_feats=self.MAX_FEATURES, for_ref=True)

        # save only 2d image coordinates, scrap scale, orientation etc
        ref_kp_2d = np.array([p.pt for p in ref_kp], dtype='float32')

        # get 3d coordinates
        ref_kp_3d = KeypointAlgo.inverse_project(self.system_model, ref_kp_2d, depth, self.render_z, self._ref_img_sc)

        if False:
            mm_dist = self.system_model.min_med_distance
            if False:
                pos = (0, 0, -mm_dist)
                qfin = tools.ypr_to_q(sc_ast_lat, 0, sc_ast_lon)
                light_v = tools.spherical2cartesian(light_lat, light_lon, 1)
                reimg = self.render_engine.render(self.obj_idx, pos, qfin, light_v)
                reimg = cv2.cvtColor(reimg, cv2.COLOR_RGB2GRAY)
                img = np.concatenate((cv2.resize(ref_img, (self.system_model.view_width, self.system_model.view_height)), reimg), axis=1)
            else:
                ref_kp = [cv2.KeyPoint(*self._cam.calc_img_xy(x, -y, -z-mm_dist), 1) for x, y, z in ref_kp_3d]
                img = cv2.drawKeypoints(ref_img, ref_kp, ref_img.copy(), (0, 0, 255), flags=cv2.DRAW_MATCHES_FLAGS_DEFAULT)
            cv2.imshow('res', img)
            cv2.waitKey()

        return np.array(ref_desc), ref_kp_2d, ref_kp_3d
Beispiel #2
0
    def rotation_q(self, timestamp):
        theta = self.rotation_theta(timestamp)

        # TODO: use precession info

        # orient z axis correctly, rotate around it
        return tools.ypr_to_q(self.axis_latitude, self.axis_longitude, theta) \
               * self.ast2sc_q
Beispiel #3
0
    def _render_params(self, discretize_tol=False, center_model=False):
        # called at self.render, override based on hidden field values

        #qfin = tools.fdb_relrot_to_render_q(self._sc_ast_lat, self._sc_ast_lon)
        qfin = tools.ypr_to_q(self._sc_ast_lat, 0, self._sc_ast_lon)
        #light_v = tools.fdb_light_to_render_light(self._light_lat, self._light_lon)
        light_v = tools.spherical2cartesian(self._light_lat, self._light_lon, 1)

        # if qfin & light_v not reasonable, e.g. because solar elong < 45 deg:
        # seems that not needed, left here in case later notice that useful
        # raise InvalidSceneException()

        return (0, 0, self.render_z), qfin, light_v
Beispiel #4
0
    def calc_err(self, rvec, tvec, i1, j1, warn=False):
        q_res = tools.angleaxis_to_q(rvec)
        lat1, roll1 = self._fdb_sc_ast_perms[i1]
        lat2, roll2 = self._fdb_sc_ast_perms[j1]
        q_src = tools.ypr_to_q(lat1, 0, roll1)
        q_trg = tools.ypr_to_q(lat2, 0, roll2)
        q_rel = q_trg * q_src.conj()

        # q_res.x = -q_res.x
        # np.quaternion(0.707106781186547, 0, -0.707106781186547, 0)
        m = self.system_model
        q_frame = m.frm_conv_q(m.OPENGL_FRAME, m.OPENCV_FRAME)
        q_res = q_frame * q_res.conj() * q_frame.conj()

        err1 = math.degrees(tools.wrap_rads(tools.angle_between_q(q_res, q_rel)))
        err2 = np.linalg.norm(tvec - np.array((0, 0, -self.render_z)).reshape((3, 1)))
        ok = not (abs(err1) > 10 or abs(err2) > 0.10 * abs(self.render_z))

        if not ok and warn:
            print('at (%s, %s), err1: %.1fdeg, err2: %.1fkm\n\tq_real: %s\n\tq_est:  %s' % (
                i1, j1, err1, err2, q_rel, q_res))

        return ok, err1, err2
Beispiel #5
0
    def _set_sc_from_ast_rot_and_trans(self,
                                       rvec,
                                       tvec,
                                       discretization_err_q,
                                       rotate_sc=False):
        sm = self.system_model

        # rotate to gl frame from opencv camera frame
        gl2cv_q = sm.frm_conv_q(sm.OPENGL_FRAME, sm.OPENCV_FRAME)
        new_sc_pos = tools.q_times_v(gl2cv_q, tvec)

        # camera rotation in opencv frame
        cv_cam_delta_q = tools.angleaxis_to_q(rvec)

        # solvePnPRansac has some bug that apparently randomly gives 180deg wrong answer
        if new_sc_pos[2] > 0:
            tpos = -new_sc_pos
            tdelta_q = cv_cam_delta_q * tools.ypr_to_q(0, math.pi, 0)
            # print('Bug with solvePnPRansac, correcting:\n\t%s => %s\n\t%s => %s'%(
            #     new_sc_pos, tpos, tools.q_to_ypr(cv_cam_delta_q), tools.q_to_ypr(tdelta_q)))
            new_sc_pos = tpos
            cv_cam_delta_q = tdelta_q

        sm.spacecraft_pos = new_sc_pos

        err_q = discretization_err_q or np.quaternion(1, 0, 0, 0)
        if rotate_sc:
            sc2cv_q = sm.frm_conv_q(sm.SPACECRAFT_FRAME, sm.OPENCV_FRAME)
            sc_delta_q = err_q * sc2cv_q * cv_cam_delta_q.conj(
            ) * sc2cv_q.conj()
            sm.rotate_spacecraft(sc_delta_q)
        else:
            sc2cv_q = sm.frm_conv_q(sm.SPACECRAFT_FRAME, sm.OPENCV_FRAME)
            sc_q = sm.spacecraft_q

            frame_q = sc_q * err_q * sc2cv_q
            ast_delta_q = frame_q * cv_cam_delta_q * frame_q.conj()

            err_corr_q = sc_q * err_q.conj() * sc_q.conj()
            ast_q0 = sm.asteroid_q
            sm.rotate_asteroid(err_corr_q * ast_delta_q)

            if self.est_real_ast_orient:
                # so that can track rotation of 67P
                ast_q = sm.asteroid_q
                err_deg = math.degrees(tools.angle_between_q(ast_q0, ast_q))
                self.extra_values = list(quaternion.as_float_array(ast_q)) + [
                    sm.time.value, err_deg
                ]
    def costfun(x, debug=0, verbose=True):
        set_params(x)
        err = 0

        for phase_angle in np.radians(np.linspace(0, 150, img_n)):
            light = tools.q_times_v(tools.ypr_to_q(phase_angle, 0, 0), np.array([0, 0, -1]))
            synth1 = re.render(obj_idx, pos, np.quaternion(1,0,0,0), tools.normalize_v(light), get_depth=False, reflection=m_hapke)
            synth2 = re.render(obj_idx, pos, np.quaternion(1,0,0,0), tools.normalize_v(light), get_depth=False, reflection=m_ll)
            synth1 = cv2.cvtColor(synth1, cv2.COLOR_RGB2GRAY)
            synth2 = cv2.cvtColor(synth2, cv2.COLOR_RGB2GRAY)

            err_img = (synth1.astype('float') - synth2.astype('float'))**2
            err += np.mean(err_img)
            if debug:
                if debug%2:
                    cv2.imshow('hapke vs ll', np.concatenate((synth1.astype('uint8'), 255*np.ones((synth2.shape[0], 1), dtype='uint8'), synth2), axis=1))
                if debug>1:
                    err_img = err_img**0.2
                    cv2.imshow('err', err_img/np.max(err_img))
                cv2.waitKey()
        err /= img_n
        if verbose:
            print('%s => %f' % (', '.join(['%.4e' % i for i in np.array(x)*scales]), err))
        return err
Beispiel #7
0
        #            break
        #synth[0] = ImageProc.equalize_brightness(synth[0], real, percentile=99.999, image_gamma=1.8)
        #synth[0] = ImageProc.adjust_gamma(synth[0], 1/4)
        #real = ImageProc.adjust_gamma(real, 1/4)

        real = cv2.resize(real, size)
        cv2.imshow(
            'real vs synthetic',
            np.concatenate(
                [real, 255 * np.ones(
                    (real.shape[0], 1), dtype='uint8')] + synth,
                axis=1))
        cv2.waitKey()
    else:
        # try different light directions a fixed angle (d) away from default
        d = 10
        for a in np.linspace(0, 360 * 2, 36 * 2, endpoint=False):
            lat, lon, r = tools.cartesian2spherical(*sm.asteroid.real_position)
            qa = tools.ypr_to_q(lat, lon, 0)
            qd = tools.ypr_to_q(0, 0, np.radians(a)) * tools.ypr_to_q(
                np.radians(d), 0, 0)
            q = qa * qd * qa.conj()
            sm.asteroid.real_position = tools.q_times_v(
                q, sm.asteroid.real_position)
            img = cv2.resize(
                ab.render(shadows=True, reflection=RenderEngine.REFLMOD_HAPKE),
                (1024, 1024))
            cv2.imshow('s', img)
            cv2.waitKey()
        quit()
Beispiel #8
0
    def generate_system_state(self, sm, i):
        # reset asteroid axis to true values
        sm.asteroid.reset_to_defaults()
        sm.asteroid_rotation_from_model()
        
        if self._state_list is not None:
            lblloader.load_image_meta(
                os.path.join(self._state_db_path, self._state_list[i]+'.LBL'), sm)

            return
        
        for i in range(100):
            ## sample params from suitable distributions
            ##
            # datetime dist: uniform, based on rotation period
            time = np.random.uniform(*sm.time.range)

            # spacecraft position relative to asteroid in ecliptic coords:
            sc_lat = np.random.uniform(-math.pi/2, math.pi/2)
            sc_lon = np.random.uniform(-math.pi, math.pi)

            # s/c distance as inverse uniform distribution
            if TestLoop.UNIFORM_DISTANCE_GENERATION:
                sc_r = np.random.uniform(self.min_r, self.max_r)
            else:
                sc_r = 1/np.random.uniform(1/self.max_r, 1/self.min_r)

            # same in cartesian coord
            sc_ex_u, sc_ey_u, sc_ez_u = spherical_to_cartesian(sc_r, sc_lat, sc_lon)
            sc_ex, sc_ey, sc_ez = sc_ex_u.value, sc_ey_u.value, sc_ez_u.value

            # s/c to asteroid vector
            sc_ast_v = -np.array([sc_ex, sc_ey, sc_ez])

            # sc orientation: uniform, center of asteroid at edge of screen
            if self._opzone_only:
                # always get at least 50% of astroid in view, 5% of the time maximum offset angle
                max_angle = rad(min(sm.cam.x_fov, sm.cam.y_fov)/2)
                da = min(max_angle, np.abs(np.random.normal(0, max_angle/2)))
                dd = np.random.uniform(0, 2*math.pi)
                sco_lat = wrap_rads(-sc_lat + da*math.sin(dd))
                sco_lon = wrap_rads(math.pi + sc_lon + da*math.cos(dd))
                sco_rot = np.random.uniform(-math.pi, math.pi)  # rotation around camera axis
            else:
                # follows the screen edges so that get more partial views, always at least 25% in view
                # TODO: add/subtract some margin
                sco_lat = wrap_rads(-sc_lat)
                sco_lon = wrap_rads(math.pi + sc_lon)
                sco_rot = np.random.uniform(-math.pi, math.pi)  # rotation around camera axis
                sco_q = ypr_to_q(sco_lat, sco_lon, sco_rot)

                ast_ang_r = math.atan(sm.asteroid.mean_radius/1000/sc_r)  # if asteroid close, allow s/c to look at limb
                dx = max(rad(sm.cam.x_fov/2), ast_ang_r)
                dy = max(rad(sm.cam.y_fov/2), ast_ang_r)
                disturbance_q = ypr_to_q(np.random.uniform(-dy, dy), np.random.uniform(-dx, dx), 0)
                sco_lat, sco_lon, sco_rot = q_to_ypr(sco_q * disturbance_q)

            sco_q = ypr_to_q(sco_lat, sco_lon, sco_rot)
            
            # sc_ast_p ecliptic => sc_ast_p open gl -z aligned view
            sc_pos = q_times_v((sco_q * sm.sc2gl_q).conj(), sc_ast_v)
            
            # get asteroid position so that know where sun is
            # *actually barycenter, not sun
            as_v = sm.asteroid.position(time)
            elong, direc = solar_elongation(as_v, sco_q)

            # limit elongation to always be more than set elong
            if elong > rad(sm.min_elong):
                break
        
        if elong <= rad(sm.min_elong):
            assert False, 'probable infinite loop'
        
        # put real values to model
        sm.time.value = time
        sm.spacecraft_pos = sc_pos
        sm.spacecraft_rot = (deg(sco_lat), deg(sco_lon), deg(sco_rot))

        # save real values so that can compare later
        sm.time.real_value = sm.time.value
        sm.real_spacecraft_pos = sm.spacecraft_pos
        sm.real_spacecraft_rot = sm.spacecraft_rot
        sm.real_asteroid_axis = sm.asteroid_axis

        # get real relative position of asteroid model vertices
        sm.asteroid.real_sc_ast_vertices = sm.sc_asteroid_vertices()
Beispiel #9
0
 def real_spacecraft_q(self):
     return tools.ypr_to_q(*list(
         map(math.radians, (self.x_rot.real_value, self.y_rot.real_value,
                            self.z_rot.real_value))))
Beispiel #10
0
    if False:
        for i in range(36):
            image = re.render(obj_idx, [0, 0, -sm.min_med_distance*3], q**i, np.array([1, 0, 0])/math.sqrt(1), get_depth=False)
            cv2.imshow('image', image)
            cv2.waitKey()

    elif True:
        RenderEngine.REFLMOD_PARAMS[RenderEngine.REFLMOD_HAPKE] = DidymosPrimary.HAPKE_PARAMS
        RenderEngine.REFLMOD_PARAMS[RenderEngine.REFLMOD_LUNAR_LAMBERT] = DidymosPrimary.LUNAR_LAMBERT_PARAMS
        imgs = ()
        i = 1
        th = math.radians(100)
        #for i in range(4, 7):
        for th in np.linspace(math.radians(90), 0, 4):
            imgs_j = ()
            for j, hapke in enumerate((True, False)):
                model = RenderEngine.REFLMOD_HAPKE if hapke else RenderEngine.REFLMOD_LUNAR_LAMBERT
                if hapke and j == 0:
                    RenderEngine.REFLMOD_PARAMS[model][9] = 0
                if hapke and j == 1:
                    RenderEngine.REFLMOD_PARAMS[model][9] = 1
                light = tools.q_times_v(tools.ypr_to_q(th, 0, 0), np.array([0, 0, -1]))
                image = re.render(obj_idx, pos, q**i, tools.normalize_v(light), get_depth=False, reflection=model)
                image = ImageProc.adjust_gamma(image, 1.8)
                imgs_j += (image,)
            imgs += (np.vstack(imgs_j),)

        #cv2.imshow('depth', np.clip((sm.min_med_distance+sm.asteroid.mean_radius - depth)/5, 0, 1))
        cv2.imshow('images', np.hstack(imgs))
        cv2.waitKey()
Beispiel #11
0
def load_image_meta(src, sm):
    # params given in equatorial J2000 coordinates, details:
    # https://pds.nasa.gov/ds-view/pds/viewProfile.jsp
    #                                   ?dsid=RO-C-NAVCAM-2-ESC3-MTP021-V1.0

    with open(src, 'r') as f:
        config_data = f.read()

    config_data = '[meta]\n' + config_data
    config_data = re.sub(r'^/\*', '#', config_data, flags=re.M)
    config_data = re.sub(r'^\^', '', config_data, flags=re.M)
    config_data = re.sub(r'^(\w+):(\w+)', r'\1__\2', config_data, flags=re.M)
    config_data = re.sub(r'^END\s*$', '', config_data, flags=re.M)
    config_data = re.sub(r'^NOTE\s*=\s*"[^"]*"', '', config_data, flags=re.M)
    config_data = re.sub(r' <(deg|km)>', '', config_data)

    config = ConfigParser(converters={'tuple': literal_eval})
    config.read_string(config_data)

    image_time = config.get('meta', 'IMAGE_TIME')

    # from sun to spacecraft, equatorial J2000
    sun_sc_eq_x, sun_sc_eq_y, sun_sc_eq_z = \
            -np.array(config.gettuple('meta', 'SC_SUN_POSITION_VECTOR'))

    if USE_ICRS:
        sun_sc_ec_p = np.array([sun_sc_eq_x, sun_sc_eq_y, sun_sc_eq_z])
    else:
        sc = SkyCoord(x=sun_sc_eq_x, y=sun_sc_eq_y, z=sun_sc_eq_z, unit='km',
                frame='icrs', representation_type='cartesian', obstime='J2000')\
                .transform_to('heliocentrictrueecliptic')\
                .represent_as('cartesian')
        sun_sc_ec_p = np.array([sc.x.value, sc.y.value, sc.z.value])
    sun_sc_dist = np.sqrt(np.sum(sun_sc_ec_p**2))

    # from spacecraft to asteroid, equatorial J2000
    sc_ast_x, sc_ast_y, sc_ast_z = \
            config.gettuple('meta', 'SC_TARGET_POSITION_VECTOR')

    # from asteroid to spacecraft, asteroid fixed body coordinates
    ast_sc_r = config.getfloat('meta', 'TARGET_CENTER_DISTANCE')
    ast_sc_lat = config.getfloat('meta', 'SUB_SPACECRAFT_LATITUDE')
    ast_sc_lon = config.getfloat('meta', 'SUB_SPACECRAFT_LONGITUDE')

    # spacecraft orientation, equatorial J2000
    sc_rot_ra = config.getfloat('meta', 'RIGHT_ASCENSION')
    sc_rot_dec = config.getfloat('meta', 'DECLINATION')
    sc_rot_cnca = config.getfloat('meta', 'CELESTIAL_NORTH_CLOCK_ANGLE')

    solar_elongation = config.getfloat('meta', 'SOLAR_ELONGATION')

    ## set time
    ##
    half_range = sm.asteroid.rotation_period / 2
    timestamp = Time(image_time, scale='utc', format='isot').unix
    sm.time.range = (timestamp - half_range, timestamp + half_range)
    sm.time.value = timestamp
    sm.time.real_value = timestamp

    ## set spacecraft orientation
    ##
    xc, yc, zc = 0, 0, 0
    #xc, yc, zc = -0.283, -0.127, 0     # ROS_CAM1_20150720T113057
    #xc, yc, zc = 0.2699, -0.09, 0  # ROS_CAM1_20150720T165249
    #xc, yc, zc = 0.09, -0.02, 0    # ROS_CAM1_20150720T064939

    if USE_ICRS:
        assert sc_rot_dec + xc < 90 and sc_rot_dec + xc > -90, 'bad correction'
        sm.spacecraft_rot = (
            sc_rot_dec + xc,  # axis lat
            (sc_rot_ra + yc + 180) % 360 - 180,  # axis lon
            (360 - sc_rot_cnca + zc) % 360 - 180,  # rotation
        )
    else:
        sc = SkyCoord(ra=sc_rot_ra * units.deg,
                      dec=sc_rot_dec * units.deg,
                      frame='icrs',
                      obstime='J2000')
        sc = sc.transform_to('barycentrictrueecliptic')
        assert sc.lat.value + xc < 90 and sc.lat.value + xc > -90, 'bad correction'
        sm.spacecraft_rot = (
            sc.lat.value + xc,  # axis lat
            (sc.lon.value + yc + 180) % 360 - 180,  # axis lon
            (sc_rot_cnca + zc + 180) % 360 - 180,  # rotation
        )

    sm.real_spacecraft_rot = sm.spacecraft_rot

    ## set spacecraft position
    ##
    if USE_ICRS:
        sc_ast_ec_p = np.array([sc_ast_x, sc_ast_y, sc_ast_z])
    else:
        sc = SkyCoord(x=sc_ast_x, y=sc_ast_y, z=sc_ast_z, unit='km', frame='icrs',
                representation_type='cartesian', obstime='J2000')\
                .transform_to('barycentrictrueecliptic')\
                .represent_as('cartesian')
        sc_ast_ec_p = np.array([sc.x.value, sc.y.value, sc.z.value])

    sm.asteroid.real_position = sun_sc_ec_p + sc_ast_ec_p

    # s/c orientation
    sco = list(map(math.radians, sm.spacecraft_rot))
    scoq = tools.ypr_to_q(*sco)

    # project old position to new base vectors
    sc2gl_q = sm.frm_conv_q(sm.SPACECRAFT_FRAME, sm.OPENGL_FRAME)
    scub = tools.q_to_unitbase(scoq * sc2gl_q)
    scub_o = tools.q_to_unitbase(scoq)
    sc_ast_p = scub.dot(sc_ast_ec_p.transpose())

    sm.real_spacecraft_pos = sc_ast_p
    # if USE_IMG_LABEL_FOR_SC_POS:
    #    sm.spacecraft_pos = sc_ast_p
    ##
    ## done setting spacecraft position

    # use calculated asteroid axis as real axis
    sm.asteroid_rotation_from_model()
    sm.real_asteroid_axis = sm.asteroid_axis

    sm.asteroid.real_sc_ast_vertices = sm.sc_asteroid_vertices(real=True)

    if not np.isclose(
            float(Decimal(sm.time.value) - Decimal(sm.time.real_value)), 0):
        sm.time.real_value = sm.time.value
        if DEBUG:
            print(
                'Strange Python problem where float memory values get corrupted a little in random places of code'
            )

    if False:
        print(
            ('' + '\nsco:\n%s\n' + '\nscoq:\n%s\n' + '\nscub_o:\n%s\n' +
             '\nscub:\n%s\n' + '\nast_sc_ec_p:\n%s\n' + '\nast_sc_p:\n%s\n') %
            (
                sm.spacecraft_rot,
                scoq,
                scub,
                scub_o,
                sc_ast_ec_p,
                sc_ast_p,
            ))

    if DEBUG:
        lbl_sun_ast_v = (sun_sc_ec_p + sc_ast_ec_p) * 1e3
        lbl_se, lbl_dir = tools.solar_elongation(lbl_sun_ast_v, scoq)

        m_elong, m_dir = sm.solar_elongation()
        mastp = sm.asteroid.position(sm.time.value)
        print(('solar elongation (deg), file: %.1f (%.1f), model: %.1f\n' +
               'light direction (deg), file: %s, model: %s\n' +
               'sun-asteroid loc (Gm), file: %s, model: %s\n') % (
                   solar_elongation,
                   math.degrees(lbl_se),
                   math.degrees(m_elong),
                   math.degrees(lbl_dir),
                   math.degrees(m_dir),
                   lbl_sun_ast_v * 1e-9,
                   (mastp) * 1e-9,
               ))

        sm.save_state('none', printout=True)