Beispiel #1
0
def run_ba(width,
           height,
           pp_x,
           pp_y,
           fl,
           dist_coefs,
           poses,
           pts3d,
           pts2d,
           cam_idxs,
           pt3d_idxs,
           meas_r,
           meas_aa,
           meas_idxs,
           optimize_dist=False,
           n_cam_intr=0):
    dist_coefs5 = [0.0] * 5
    for i in range(len(dist_coefs)):
        dist_coefs5[i] = dist_coefs[i]

    if optimize_dist:
        dist_coefs = dist_coefs5[:2]
    else:
        dist_coefs = None

    cam = Camera(width,
                 height,
                 cam_mx=np.array([[fl, 0, pp_x], [0, fl, pp_y], [0, 0, 1]]),
                 dist_coefs=np.array(dist_coefs5, dtype=np.float32))
    norm_pts2d = pts2d.squeeze() if optimize_dist else cam.undistort(
        pts2d).squeeze()
    new_poses, new_pts3d, dist_ba, cam_intr_ba, _, _, ba_errs = vis_gps_bundle_adj(
        poses,
        pts3d,
        norm_pts2d,
        np.zeros((0, 1)),
        cam_idxs,
        pt3d_idxs,
        cam.intrinsic_camera_mx(),
        dist_coefs,
        np.array([PX_ERR_SD]),
        meas_r,
        meas_aa,
        np.zeros((0, 1)),
        meas_idxs,
        np.array(LOC_ERR_SD),
        np.array(ORI_ERR_SD),
        px_err_weight=np.array([1]),
        n_cam_intr=n_cam_intr,
        log_writer=None,
        max_nfev=5,
        skip_pose_n=1,
        poses_only=False,
        huber_coef=(1, 5, 0.5))
    new_poses = np.concatenate((poses[:1, :], new_poses), axis=0)
    return new_poses, new_pts3d, dist_ba, cam_intr_ba, ba_errs
Beispiel #2
0
    def prepare(self, scene):
        w, h = scene.width, scene.height

        if self.target is not None:
            # change orientation so that target is on the camera bore-sight
            self._update_target()

        if self.is_dirty() or self.model.width != w or self.model.height != h:
            x_fov = math.degrees(
                2 * math.atan(self.sensor_width / 2 / self.focal_length))
            y_fov = x_fov * h / w
            params = RenderCamera.DEFAULTS.copy()
            params.update(self.extra)
            if 'aperture' in params:
                params.pop('f_stop', False)
            if 'px_saturation_e' not in self.extra:
                params['px_saturation_e'] *= ((self.sensor_width / w) /
                                              5.5e-3)**2
            if 'dark_noise_mu' not in self.extra:
                params['dark_noise_mu'] *= params[
                    'px_saturation_e'] / self.DEFAULTS['px_saturation_e']
            if 'dark_noise_sd' not in self.extra:
                params['dark_noise_sd'] = np.sqrt(params['dark_noise_mu'])

            self.model = Camera(w,
                                h,
                                x_fov,
                                y_fov,
                                focal_length=self.focal_length,
                                **params)
            self.clear_dirty()
Beispiel #3
0
def get_cam():
    common_kwargs_worst = {
        'sensor_size': (2048 * 0.0022, 1944 * 0.0022),
        'quantum_eff': 0.30,
        'px_saturation_e': 2200,  # snr_max = 20*log10(sqrt(sat_e)) dB
        'lambda_min': 350e-9, 'lambda_eff': 580e-9, 'lambda_max': 800e-9,
        'dark_noise_mu': 40, 'dark_noise_sd': 6.32, 'readout_noise_sd': 15,
        # dark_noise_sd should be sqrt(dark_noise_mu)
        'emp_coef': 1,  # dynamic range = 20*log10(sat_e/readout_noise))
        'exclusion_angle_x': 55,
        'exclusion_angle_y': 90,
    }
    common_kwargs_best = dict(common_kwargs_worst)
    common_kwargs_best.update({
        'quantum_eff': 0.4,
        'px_saturation_e': 3500,
        'dark_noise_mu': 25, 'dark_noise_sd': 5, 'readout_noise_sd': 5,
    })
    common_kwargs = common_kwargs_best

    return Camera(
        2048,  # width in pixels
        1944,  # height in pixels
        7.7,  # x fov in degrees  (could be 6 & 5.695, 5.15 & 4.89, 7.7 & 7.309)
        7.309,  # y fov in degrees
        f_stop=5,  # TODO: put better value here
        point_spread_fn=0.50,  # ratio of brightness in center pixel
        scattering_coef=2e-10,  # affects strength of haze/veil when sun shines on the lens
        **common_kwargs
    )
Beispiel #4
0
    def __init__(self,
                 hi_res_shape_model=False,
                 rosetta_batch='mtp006',
                 focused_attenuated=True,
                 res_mult=1.0):
        # gives some unnecessary warning about "dubious year" even when trying to ignore it
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            min_time = Time('2015-01-01 00:00:00', scale='utc', format='iso')

        fa = focused_attenuated  # else defocused not attenuated
        super(RosettaSystemModel, self).__init__(
            asteroid=ChuryumovGerasimenko(
                hi_res_shape_model=hi_res_shape_model,
                rosetta_batch=rosetta_batch),

            # see https://pds-smallbodies.astro.umd.edu/holdings/ro-c-navcam-2-esc4-mtp023-v1.0/document/ro-sgs-if-0001.pdf
            camera=Camera(
                int(1024 * res_mult),  # width in pixels
                int(1024 * res_mult),  # height in pixels
                5,  # x fov in degrees
                5,  # y fov in degrees
                focal_length=152.5,  # in mm
                # sensor_size=(1024*0.013, 1024*0.013),
                aperture=30 if fa else
                70,  # attenuated mode (in non-attenuated mode would be 70mm)
                # f_stop=5.1,     # attenuated mode (in non-attenuated mode would be 2.2)
                quantum_eff=
                0.80,  # from https://www.e2v.com/resources/account/download-datasheet/1427
                px_saturation_e=1e5,  # same source as above
                # gain can be 1.0 (low) or 1.7 (high)   # from https://pds-smallbodies.astro.umd.edu/holdings/ro-c-navcam-2-esc4-mtp023-v1.0/document/ro-sgs-if-0001.pdf
                lambda_min=500e-9,
                lambda_eff=650e-9,
                lambda_max=800e-9,  # for bandwidth calc
                dark_noise_mu=250,
                dark_noise_sd=60,
                readout_noise_sd=2,  # noise params (e-/s, e-)
                point_spread_fn=0.65 if fa else
                0.25,  # 0.50-0.55 for defocused, 0.65-0.70 for focused
                scattering_coef=
                5e-9,  # affects strength of haze/veil when sun shines on the lens (TODO: just a guess now)
                exclusion_angle_x=15,
                exclusion_angle_y=15,

                # 30mm aperture and attenuation filter result in an attenuation factor of ∼580 relative to 70mm aperture and no filter
                #   => if aperture is 30, need extra attenuation coef: x*(30/70)**2==1/580 => x==0.009387
                # empirical coef used to tune the synthetic images to match real brightnesses (includes attenuation filter effect)
                #  - based on star brightnesses, note that point_spread_fn affects this a lot
                emp_coef=(0.009387 * 2.3 if fa else 2.3),
            ),
            limits=(
                25,  # min_distance in km
                70,  # min_med_distance in km
                400,  # max_med_distance in km #640
                1250,  # max_distance in km
                40,  # min_elong in deg
                min_time,  # min time instant
            ))
        self.mission_id = 'rose'
Beispiel #5
0
 def cost_fn(x, Y, X, K, iK):
     dx, dy, th, *dist_coefs = x
     A = np.array([
         [math.cos(th), -math.sin(th), dx],
         [math.sin(th), math.cos(th), dy],
     ])
     Xdot = Camera.distort(X.dot(A.T), dist_coefs, K, iK)
     return tools.pseudo_huber_loss(np.linalg.norm(Y - Xdot,
                                                   axis=1),
                                    delta=3)
Beispiel #6
0
def sensed_electron_flux_star_spectrum(path,
                                       bayer,
                                       mag_v,
                                       Teff,
                                       log_g,
                                       fe_h,
                                       lam_min,
                                       lam_max,
                                       qeff_coefs,
                                       gomos_mag_v=None):
    spectrum_fn = get_star_spectrum(path, bayer, mag_v, Teff, log_g, fe_h,
                                    lam_min, lam_max, gomos_mag_v)
    electrons, _ = Camera.electron_flux_in_sensed_spectrum_fn(
        qeff_coefs, spectrum_fn, lam_min, lam_max)
    return electrons
Beispiel #7
0
    def init_cam(self):
        w, h = 1280, 960
        common_kwargs_worst = {
            'sensor_size': (w * 0.00375, h * 0.00375),
            'quantum_eff': 0.30,
            'px_saturation_e': 2200,  # snr_max = 20*log10(sqrt(sat_e)) dB
            'lambda_min': 350e-9,
            'lambda_eff': 580e-9,
            'lambda_max': 800e-9,
            'dark_noise_mu': 40,
            'dark_noise_sd': 6.32,
            'readout_noise_sd': 15,
            # dark_noise_sd should be sqrt(dark_noise_mu)
            'emp_coef': 1,  # dynamic range = 20*log10(sat_e/readout_noise))
            'exclusion_angle_x': 55,
            'exclusion_angle_y': 90,
        }
        common_kwargs_best = dict(common_kwargs_worst)
        common_kwargs_best.update({
            'quantum_eff': 0.4,
            'px_saturation_e': 3500,
            'dark_noise_mu': 25,
            'dark_noise_sd': 5,
            'readout_noise_sd': 5,
        })
        common_kwargs = common_kwargs_best

        cam = Camera(
            w,  # width in pixels
            h,  # height in pixels
            43.6,  # x fov in degrees  (could be 6 & 5.695, 5.15 & 4.89, 7.7 & 7.309)
            33.4,  # y fov in degrees
            f_stop=5,  # TODO: put better value here
            point_spread_fn=0.50,  # ratio of brightness in center pixel
            scattering_coef=
            2e-10,  # affects strength of haze/veil when sun shines on the lens
            dist_coefs=[
                -3.79489919e-01, 2.55784821e-01, 9.52433459e-04,
                1.27543923e-04, -2.74301340e-01
            ],  # by using calibrate.py
            cam_mx=np.array([[1.60665503e+03, 0.00000000e+00, 6.12522544e+02],
                             [0.00000000e+00, 1.60572265e+03, 4.57510418e+02],
                             [0.00000000e+00, 0.00000000e+00,
                              1.00000000e+00]]),
            **common_kwargs)

        return cam
Beispiel #8
0
    def init_cam(self):
        w, h, p = 1920, 1080, 0.00375
        common_kwargs_worst = {
            'sensor_size': (w * p, h * p),
            'quantum_eff': 0.30,
            'px_saturation_e': 2200,  # snr_max = 20*log10(sqrt(sat_e)) dB
            'lambda_min': 350e-9,
            'lambda_eff': 580e-9,
            'lambda_max': 800e-9,
            'dark_noise_mu': 40,
            'dark_noise_sd': 6.32,
            'readout_noise_sd': 15,
            # dark_noise_sd should be sqrt(dark_noise_mu)
            'emp_coef': 1,  # dynamic range = 20*log10(sat_e/readout_noise))
            'exclusion_angle_x': 55,
            'exclusion_angle_y': 90,
        }
        common_kwargs_best = dict(common_kwargs_worst)
        common_kwargs_best.update({
            'quantum_eff': 0.4,
            'px_saturation_e': 3500,
            'dark_noise_mu': 25,
            'dark_noise_sd': 5,
            'readout_noise_sd': 5,
        })
        common_kwargs = common_kwargs_best

        cam = Camera(
            w,  # width in pixels
            h,  # height in pixels
            62.554,  # x fov in degrees  (could be 6 & 5.695, 5.15 & 4.89, 7.7 & 7.309)
            37.726,  # y fov in degrees
            f_stop=5,  # TODO: put better value here
            point_spread_fn=0.50,  # ratio of brightness in center pixel
            scattering_coef=
            2e-10,  # affects strength of haze/veil when sun shines on the lens
            dist_coefs=None if 0 else
            [-0.11250615, 0.14296794, -0.00175085, 0.00057391, -0.11678778],
            cam_mx=np.array([[1.58174667e+03, 0.00000000e+00, 9.97176182e+02],
                             [0.00000000e+00, 1.58154569e+03, 5.15553843e+02],
                             [0.00000000e+00, 0.00000000e+00,
                              1.00000000e+00]]),
            **common_kwargs)

        return cam
Beispiel #9
0
    def __init__(self, hi_res_shape_model=False, res_mult=1.0):
        # gives some unnecessary warning about "dubious year" even when trying to ignore it
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            min_time = Time('2019-03-01 00:00:00', scale='utc', format='iso')

        super(BennuSystemModel, self).__init__(
            asteroid=Bennu(hi_res_shape_model=hi_res_shape_model),

            # see https://sbnarchive.psi.edu/pds4/orex/orex.tagcams/document/tagcams_inst_desc.pdf
            # sensor datasheet: https://www.onsemi.com/pdf/datasheet/mt9p031-d.pdf
            # lens reference: http://www.msss.com/brochures/xfov.pdf
            camera=Camera(
                int(2592 * res_mult),  # width in pixels
                int(1944 * res_mult),  # height in pixels
                44,  # x fov in degrees
                32,  # y fov in degrees
                focal_length=7.7,  # in mm
                f_stop=3.5,
                quantum_eff=0.65,
                px_saturation_e=
                6456,  # SNR_MAX = 20*log10(sqrt(sat_e)), if SNR_MAX=38.1 dB, then sat_e=6456 e-
                lambda_min=400e-9,
                lambda_eff=580e-9,
                lambda_max=700e-9,  # for bandwidth calc
                dark_noise_mu=250,
                dark_noise_sd=60,
                readout_noise_sd=6.7,  # noise params (e-/s, e-)
                point_spread_fn=0.4,
                scattering_coef=
                5e-9,  # affects strength of haze/veil when sun shines on the lens (TODO: just a guess now)
                exclusion_angle_x=60,
                exclusion_angle_y=50,
                emp_coef=1.0,
            ),
            limits=(
                0.7,  # min_distance in km
                1.1,  # min_med_distance in km
                3.5,  # max_med_distance in km #640
                30,  # max_distance in km
                180 - 130,  # min_elong in deg (180 - phase angle)
                min_time,  # min time instant
            ))
        self.mission_id = 'orex'
Beispiel #10
0
    def calc_source_kernel(cams, spectrum_fn, patch_size, points=None):
        # detect source
        kernel = ImageProc.bsphkern(
            tuple(map(int, patch_size)) if '__iter__' in
            dir(patch_size) else int(patch_size))

        expected_bgr = np.zeros(3)
        for i, cam in enumerate(cams):
            ef, _ = Camera.electron_flux_in_sensed_spectrum_fn(cam.qeff_coefs,
                                                               spectrum_fn,
                                                               cam.lambda_min,
                                                               cam.lambda_max,
                                                               fast=False,
                                                               points=points)
            expected_bgr[i] = cam.gain * cam.aperture_area * cam.emp_coef * ef

        kernel = np.repeat(np.expand_dims(kernel, axis=2), 3,
                           axis=2) * expected_bgr
        return kernel
Beispiel #11
0
import cv2
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D  # noqa: F401 unused import

from visnav.algo import tools
from visnav.algo.model import Camera, SystemModel
from visnav.algo.odometry import VisualOdometry, Pose
from visnav.missions.didymos import DidymosSystemModel
from visnav.render.render import RenderEngine
from visnav.settings import *

if __name__ == '__main__':
    sm = DidymosSystemModel(use_narrow_cam=False,
                            target_primary=False,
                            hi_res_shape_model=False)
    sm.cam = Camera(1024, 1024, 20, 20)

    re = RenderEngine(sm.cam.width, sm.cam.height, antialias_samples=0)
    re.set_frustum(sm.cam.x_fov, sm.cam.y_fov, 0.002, 2)
    ast_v = np.array([0, 0, -0.3])
    #q = tools.angleaxis_to_q((math.radians(2), 0, 1, 0))
    #q = tools.angleaxis_to_q((math.radians(1), 1, 0, 0))
    #q = tools.rand_q(math.radians(2))
    #lowq_obj = sm.asteroid.load_noisy_shape_model(Asteroid.SM_NOISE_HIGH)
    obj = sm.asteroid.real_shape_model
    obj_idx = re.load_object(obj)
    # obj_idx = re.load_object(sm.asteroid.hires_target_model_file)
    t0 = datetime.now().timestamp()

    odo = VisualOdometry(
        sm,
Beispiel #12
0
def render_itokawa(show=False):
    cam = Camera(4096,
                 4096,
                 aperture=1.5,
                 focal_length=120.8,
                 sensor_size=[12.288] * 2,
                 px_saturation_e=30e3)
    shape_model_file = [
        r'C:\projects\sispo\data\models\itokawa_16k.obj',
        r'C:\projects\sispo\data\models\itokawa_f3145728.obj',
    ][0]

    RenderEngine.REFLMOD_PARAMS[RenderEngine.REFLMOD_HAPKE] = [
        553.38,  # J         0
        26,  # th_p      26
        0.31,  # w         0.31
        -0.35,  # b         -0.35
        0,  # c         0
        0.86,  # B_SH0     0.86
        0.00021,  # hs        0.00021
        0,  # B_CB0     0
        0.005,  # hc        0.005
        1,  # K         1
    ]

    re = RenderEngine(cam.width, cam.height,
                      antialias_samples=0)  #, enable_extra_data=True)
    re.set_frustum(cam.x_fov, cam.y_fov, 0.05, 12)
    obj_idx = re.load_object(shape_model_file)

    if 1:
        g_sc_q = tools.angleaxis_to_q(
            [1.847799, -0.929873, 0.266931, -0.253146])
        #x, y, z = -13.182141, -64.694813, 116.263134
        x, y, z = 93.818, -8.695, 1.263
        g_ast_q = get_ast_q(x, y, z)
        g_sol_ast_v = np.array([146226194732.0, -68812326932.0, -477863381.0
                                ]) * 1e-3
        g_sol_sc_v = np.array([146226188132.0, -68812322442.0, -477863711.0
                               ]) * 1e-3
        g_sc_ast_v = g_sol_ast_v - g_sol_sc_v
        l_ast_sc_v = tools.q_times_v(
            SystemModel.sc2gl_q.conj() * g_sc_q.conj(), g_sc_ast_v)
        l_ast_q = SystemModel.sc2gl_q.conj() * g_sc_q.conj(
        ) * g_ast_q * SystemModel.sc2gl_q
        l_light_v = tools.q_times_v(SystemModel.sc2gl_q.conj() * g_sc_q.conj(),
                                    g_sol_ast_v / np.linalg.norm(g_sol_ast_v))
    else:
        l_ast_sc_v = np.array([0, 0, -7.990 * 1])
        l_ast_q = tools.angleaxis_to_q((math.radians(20), 0, 1, 0))
        l_light_v = np.array([1, 0, -1]) / math.sqrt(2)

    sc_mode = 0
    a, b, c = [0] * 3
    ds, dq = 0.135, tools.ypr_to_q(math.radians(1.154), 0,
                                   math.radians(-5.643))
    #    ds, dq = 0.535, quaternion.one     # itokawa centered

    while True:
        img = re.render(obj_idx,
                        tools.q_times_v(dq, l_ast_sc_v * ds),
                        l_ast_q,
                        l_light_v,
                        flux_density=1.0,
                        gamma=1.0,
                        get_depth=False,
                        shadows=True,
                        textures=True,
                        reflection=RenderEngine.REFLMOD_HAPKE)

        #        data = re.render_extra_data(obj_idx, tools.q_times_v(dq, l_ast_sc_v*ds), l_ast_q, l_light_v)
        #        import matplotlib.pyplot as plt
        #        plt.imshow(data[:, :, 0])

        k = output(img, show, maxval=0.90)

        if k is None or k == 27:
            break

        tmp = 1 if k in (ord('a'), ord('s'), ord('q')) else -1
        if k in (ord('a'), ord('d')):
            if sc_mode:
                dq = tools.ypr_to_q(math.radians(tmp * 0.033), 0, 0) * dq
            else:
                b += tmp
        if k in (ord('w'), ord('s')):
            if sc_mode:
                dq = tools.ypr_to_q(0, 0, math.radians(tmp * 0.033)) * dq
            else:
                a += tmp
        if k in (ord('q'), ord('e')):
            if sc_mode:
                ds *= 0.9**tmp
            else:
                c += tmp
        if k == ord('i'):
            y, p, r = tools.q_to_ypr(dq)
            print('+c: %.3f, %.3f, %.3f' % (x + a, y + b, z + c))
            print('ds, h, v: %.3f, %.3f, %.3f' %
                  (ds, math.degrees(y), math.degrees(r)))

        g_ast_q = get_ast_q(x + a, y + b, z + c)
        l_ast_q = SystemModel.sc2gl_q.conj() * g_sc_q.conj(
        ) * g_ast_q * SystemModel.sc2gl_q
Beispiel #13
0
def get_bgr_cam(thumbnail=False, estimated=False, final=False):
    if 0:
        bgr = (
            {
                'qeff_coefs': [.05] * 2 + [0.4] + [.05] * 10,
                'lambda_min': 350e-9,
                'lambda_eff': 465e-9,
                'lambda_max': 1000e-9
            },
            {
                'qeff_coefs': [.05] * 4 + [0.4] + [.05] * 8,
                'lambda_min': 350e-9,
                'lambda_eff': 540e-9,
                'lambda_max': 1000e-9
            },
            {
                'qeff_coefs': [.05] * 6 + [0.4] + [.05] * 6,
                'lambda_min': 350e-9,
                'lambda_eff': 650e-9,
                'lambda_max': 1000e-9
            },
        )
    elif estimated:
        array = tuple
        if final:
            # CURR RESULT
            tmp = [
                array([
                    0.04597736, 0.18328294, 0.35886904, 0.20962509, 0.07183794,
                    0.06324343, 0.06437495, 0.09206215, 0.07814311, 0.07806824,
                    0.06221573, 0.06078359, 0.01155586, 0.00993577
                ]),
                array([
                    0.0365881, 0.07068747, 0.07992755, 0.24703731, 0.32896325,
                    0.14336659, 0.04652175, 0.08300058, 0.12259696, 0.04717292,
                    0.06284823, 0.06651458, 0.06912351, 0.06644719
                ]),
                array([
                    4.09008330e-02, 6.04753849e-02, 1.09132383e-04,
                    9.39146573e-03, 4.33269662e-02, 3.12552300e-01,
                    3.00956896e-01, 2.20188491e-01, 1.88448761e-01,
                    1.38525314e-01, 9.33445846e-02, 5.93350748e-02,
                    2.43120789e-02, 3.52109874e-02
                ])
            ]

        else:
            # CURR RESULT
            tmp = [
                array([
                    0.04597736, 0.18328294, 0.35886904, 0.20962509, 0.07183794,
                    0.06324343, 0.06437495, 0.09206215, 0.07814311, 0.07806824,
                    0.06221573, 0.06078359, 0.01155586, 0.00993577
                ]),
                array([
                    0.0365881, 0.07068747, 0.07992755, 0.24703731, 0.32896325,
                    0.14336659, 0.04652175, 0.08300058, 0.12259696, 0.04717292,
                    0.06284823, 0.06651458, 0.06912351, 0.06644719
                ]),
                array([
                    4.09008330e-02, 6.04753849e-02, 1.09132383e-04,
                    9.39146573e-03, 4.33269662e-02, 3.12552300e-01,
                    3.00956896e-01, 2.20188491e-01, 1.88448761e-01,
                    1.38525314e-01, 9.33445846e-02, 5.93350748e-02,
                    2.43120789e-02, 3.52109874e-02
                ])
            ]

        bgr = (
            {
                'qeff_coefs': tmp[0],
                'lambda_min': 350e-9,
                'lambda_eff': 465e-9,
                'lambda_max': 1000e-9
            },
            {
                'qeff_coefs': tmp[1],
                'lambda_min': 350e-9,
                'lambda_eff': 540e-9,
                'lambda_max': 1000e-9
            },
            {
                'qeff_coefs': tmp[2],
                'lambda_min': 350e-9,
                'lambda_eff': 650e-9,
                'lambda_max': 1000e-9
            },
        )
    elif 0:
        bgr = (
            {
                'qeff_coefs':
                list(
                    reversed([
                        .05 * .9, .15 * .9, .33 * .95, .22 * .95, .07 * .95,
                        .05 * .95, .05 * .95, .05 * .95, .05 * .95
                    ])),
                'lambda_min':
                350e-9,
                'lambda_eff':
                465e-9,
                'lambda_max':
                750e-9
            },
            {
                'qeff_coefs':
                list(
                    reversed([
                        .05 * .9, .05 * .95, .23 * .95, .35 * .95, .17 * .95,
                        .07 * .95, .11 * .95, .12 * .95, .05 * .95
                    ])),
                'lambda_min':
                400e-9,
                'lambda_eff':
                540e-9,
                'lambda_max':
                800e-9
            },
            {
                'qeff_coefs':
                list(
                    reversed([
                        .05 * .95, .05 * .95, .35 * .95, .35 * .95, .27 * .95,
                        .23 * .95, .18 * .925, .13 * .9, .09 * .9, .05 * .875
                    ])),
                'lambda_min':
                500e-9,
                'lambda_eff':
                650e-9,
                'lambda_max':
                950e-9
            },
        )
    elif 1:
        # DEFAULT
        bgr = (
            {
                'qeff_coefs':
                np.array([
                    .05 * .05, .15 * .9, .33 * .95, .22 * .95, .07 * .95,
                    .05 * .95, .04 * .95, .05 * .95, .05 * .95, .05 * .925,
                    .05 * .9, .05 * .9, .05 * .875, .05 * .85
                ]) * INIT_QEFF_ADJ[0],
                'lambda_min':
                350e-9,
                'lambda_eff':
                465e-9,
                'lambda_max':
                1000e-9
            },
            {
                'qeff_coefs':
                np.array([
                    .03 * .05, .03 * .9, .05 * .95, .23 * .95, .35 * .95,
                    .17 * .95, .07 * .95, .11 * .95, .12 * .95, .05 * .925,
                    .05 * .9, .05 * .9, .05 * .875, .05 * .85
                ]) * INIT_QEFF_ADJ[1],
                'lambda_min':
                350e-9,
                'lambda_eff':
                540e-9,
                'lambda_max':
                1000e-9
            },
            {
                'qeff_coefs':
                np.array([
                    .05 * .05, .05 * .9, .01 * .95, .03 * .95, .05 * .95,
                    .35 * .95, .35 * .95, .27 * .95, .23 * .95, .18 * .925,
                    .13 * .9, .09 * .9, .05 * .875, .05 * .85
                ]) * INIT_QEFF_ADJ[2],
                'lambda_min':
                350e-9,
                'lambda_eff':
                650e-9,
                'lambda_max':
                1000e-9
            },
        )
    elif 0:
        bgr = (
            {
                'qeff_coefs':
                np.array([
                    .05 * .05, .05 * .05, .15 * .9, .33 * .95, .22 * .95,
                    .07 * .95, .05 * .95, .04 * .95, .05 * .95, .05 * .95,
                    .05 * .925, .05 * .9, .05 * .9, .05 * .875
                ]) * INIT_QEFF_ADJ[0],
                'lambda_min':
                300e-9,
                'lambda_eff':
                465e-9,
                'lambda_max':
                950e-9
            },
            {
                'qeff_coefs':
                np.array([
                    .03 * .05, .03 * .05, .03 * .9, .05 * .95, .23 * .95,
                    .35 * .95, .17 * .95, .07 * .95, .11 * .95, .12 * .95,
                    .05 * .925, .05 * .9, .05 * .9, .05 * .85
                ]) * INIT_QEFF_ADJ[1],
                'lambda_min':
                300e-9,
                'lambda_eff':
                540e-9,
                'lambda_max':
                950e-9
            },
            {
                'qeff_coefs':
                np.array([
                    .05 * .05, .05 * .05, .05 * .9, .01 * .95, .03 * .95,
                    .05 * .95, .35 * .95, .35 * .95, .27 * .95, .23 * .95,
                    .18 * .925, .13 * .9, .09 * .9, .05 * .85
                ]) * INIT_QEFF_ADJ[2],
                'lambda_min':
                300e-9,
                'lambda_eff':
                650e-9,
                'lambda_max':
                950e-9
            },
        )
    else:
        bgr = (
            {
                'qeff_coefs':
                list(
                    reversed([
                        .05 * .9, .15 * .9, .33 * .95, .22 * .95, .07 * .95,
                        .05 * .95, .04 * .95, .05 * .95, .05 * .95, .05 * .925,
                        .05 * .9, .05 * .9
                    ])),
                'lambda_min':
                350e-9,
                'lambda_eff':
                465e-9,
                'lambda_max':
                900e-9
            },
            {
                'qeff_coefs':
                list(
                    reversed([
                        .05 * .9, .05 * .9, .05 * .95, .23 * .95, .35 * .95,
                        .17 * .95, .07 * .95, .11 * .95, .12 * .95, .05 * .925,
                        .05 * .9, .05 * .9
                    ])),
                'lambda_min':
                350e-9,
                'lambda_eff':
                540e-9,
                'lambda_max':
                900e-9
            },
            {
                'qeff_coefs':
                list(
                    reversed([
                        .01 * .9, .01 * .9, .01 * .95, .03 * .95, .05 * .95,
                        .35 * .95, .35 * .95, .27 * .95, .23 * .95, .18 * .925,
                        .13 * .9, .09 * .9
                    ])),
                'lambda_min':
                350e-9,
                'lambda_eff':
                650e-9,
                'lambda_max':
                900e-9
            },
        )

    bgr_cam = []
    for i in range(3):
        # snr_max = 20*log10(sqrt(sat_e))
        # sat_e = (10**(43/20))**2 => 19952
        bgr_cam.append(
            Camera(2048,
                   1536,
                   None,
                   None,
                   sensor_size=(2048 * 3.2e-3, 1536 * 3.2e-3),
                   focal_length=8.2,
                   f_stop=1.4,
                   px_saturation_e=20000,
                   emp_coef=1 / 16**2 if thumbnail else 1,
                   dark_noise_mu=500,
                   readout_noise_sd=15,
                   point_spread_fn=0.5,
                   scattering_coef=5e-9,
                   **bgr[i]))

    if PLOT_INITIAL_QEFF_FN:
        plot_bgr_qeff(bgr_cam)

    return bgr_cam
Beispiel #14
0
    def expected_du(self,
                    pre_sat_gain=1,
                    post_sat_gain=1,
                    qeff_coefs=None,
                    psf_coef=(1, 1, 1),
                    plot=False):
        f, c = self.frame, self.frame.cam[self.cam_i]
        g, clat, clon, slon = f.phase_angle, f.cam_moon_lat, f.cam_moon_lon, f.sun_moon_lon
        smd, cmd = f.sun_moon_dist, f.cam_moon_dist
        spectrum_fn = MoonMeasure.lunar_disk_irr_fn(
            MoonMeasure.lunar_disk_refl_fn(g, clat, clon, slon), smd, cmd)

        if plot and self.cam_i == 0:
            lam = np.linspace(c.lambda_min, c.lambda_max, 1000)
            albedo_fn = MoonMeasure.lunar_disk_refl_fn(g, clat, clon, slon)
            moon_sr = 6.4177e-5 * (384.4e6 / cmd)**2
            ssi_fn = lambda lam: spectrum_fn(lam) / albedo_fn(
                lam) / moon_sr * np.pi

            one_fig = False
            plt.rcParams.update({'font.size': 16})

            for i in range(1 if one_fig else 2):
                fig = plt.figure(figsize=[6.4, 4.8])
                if one_fig:
                    axs = fig.subplots(1, 2)
                else:
                    axs = [None] * 2
                    axs[i] = fig.subplots(1, 1)

                if i == 0 or one_fig:
                    ax_da = axs[0].twinx()
                    ax_da.plot(lam * 1e9, albedo_fn(lam), color='orange')
                    ax_da.set_ylabel('Disk equivalent albedo', color='orange')
                    ax_da.tick_params(axis='y', labelcolor='orange')
                    #            ax_da.title('ROLO-model 2018-12-14 19:00 UTC')

                    axs[0].plot(lam * 1e9,
                                ssi_fn(lam) * 1e-9,
                                color='tab:blue')  # [W/m2/nm]
                    axs[0].set_xlabel('Wavelength [nm]')
                    axs[0].set_ylabel(
                        r'Spectral Irradiance [$\mathregular{W/m^{2}/nm}$]',
                        color='tab:blue')
                    axs[0].tick_params(axis='y', labelcolor='tab:blue')
        #            axs[0].title('Sunlight SI on 2018-12-14')

                if i == 1 or one_fig:
                    ax_qe = axs[1].twinx()
                    ax_qe.set_ylim([None, 45])
                    ax_qe.set_ylabel('Quantum efficiency [%]')
                    plot_bgr_qeff(self.frame.cam,
                                  ax=ax_qe,
                                  color=('lightblue', 'lightgreen', 'pink'),
                                  linestyle='dashed',
                                  linewidth=1,
                                  marker="")
                    axs[1].plot(lam * 1e9,
                                spectrum_fn(lam) * 1e-9,
                                color='tab:blue')  # [W/m2/nm]
                    axs[1].set_xlabel('Wavelength [nm]')
                    axs[1].set_ylabel(
                        r'Spectral Irradiance [$\mathregular{W/m^{2}/nm}$]',
                        color='tab:blue')
                    axs[1].tick_params(axis='y', labelcolor='tab:blue')
        #            axs[1].title('Moonlight SI on 2018-12-14 19:00 UTC, ROLO-model + SSI')

                plt.tight_layout()
                plt.show()

        cgain = c.gain * c.aperture_area * c.emp_coef
        fgain = f.gain * f.exposure
        queff_coefs = tuple(
            c.qeff_coefs if qeff_coefs is None else qeff_coefs[self.cam_i])
        electrons, _ = Camera.electron_flux_in_sensed_spectrum_fn(
            queff_coefs, spectrum_fn, c.lambda_min, c.lambda_max)
        du = pre_sat_gain * RAW_IMG_MAX_VALUE * post_sat_gain * fgain * cgain * electrons
        self.c_expected_du = du
        return du
Beispiel #15
0
    def expected_du(self,
                    pre_sat_gain=1,
                    post_sat_gain=1,
                    qeff_coefs=None,
                    psf_coef=(1, 1, 1)):
        cam = self.frame.cam[self.cam_i]
        cgain = cam.gain * cam.aperture_area * cam.emp_coef
        fgain = self.frame.gain * self.frame.exposure
        queff_coefs = tuple(
            cam.qeff_coefs if qeff_coefs is None else qeff_coefs[self.cam_i])

        if 0:
            p_elec, _ = Camera.electron_flux_in_sensed_spectrum(
                queff_coefs, self.t_eff, self.fe_h, self.log_g, self.mag_v,
                cam.lambda_min, cam.lambda_max)
        if 1:
            gomos_mag_v = self.mag_v  # if self.bayer == 'alp_ori' else None
            electrons = sensed_electron_flux_star_spectrum(
                STAR_SPECTRA_PATH, self.bayer, self.mag_v, self.t_eff,
                self.log_g, self.fe_h, cam.lambda_min, cam.lambda_max,
                queff_coefs, gomos_mag_v)

        if 0:  #self.bayer == 'alp_ori':
            spectrum_fn0 = Stars.synthetic_radiation_fn(self.t_eff,
                                                        self.fe_h,
                                                        self.log_g,
                                                        mag_v=self.mag_v)
            spectrum_fn0b = Stars.synthetic_radiation_fn(
                self.t_eff,
                self.fe_h,
                self.log_g,
                mag_v=self.mag_v,
                model='ck04models',
                lam_min=cam.lambda_min - 10e-9,
                lam_max=cam.lambda_max + 10e-9)
            spectrum_fn1 = get_star_spectrum(STAR_SPECTRA_PATH, self.bayer,
                                             self.mag_v, self.t_eff,
                                             self.log_g, self.fe_h,
                                             cam.lambda_min, cam.lambda_max,
                                             gomos_mag_v)
            lams = np.linspace(cam.lambda_min, cam.lambda_max, 3000)
            plt.plot(lams, spectrum_fn0(lams))
            plt.plot(lams, spectrum_fn0b(lams))
            plt.plot(lams, spectrum_fn1(lams))
            plt.title(self.bayer)
            plt.show()

        du = pre_sat_gain * RAW_IMG_MAX_VALUE * fgain * cgain * electrons
        self.c_unsat_du = du

        if StarFrame.STAR_SATURATION_MODELING == StarFrame.STAR_SATURATION_MODEL_MOTION:
            psf_coef = tuple(psf_coef) if StarFrame.STAR_SATURATION_MULTI_KERNEL else \
                ((psf_coef[self.cam_i],) if len(psf_coef) == 3 else tuple(psf_coef))
            du, self.c_px_du_sat = self._motion_kernel_psf_saturation(
                du, psf_coef, True)
        elif StarFrame.STAR_SATURATION_MODELING == StarFrame.STAR_SATURATION_MODEL_ANALYTICAL:
            du = self._analytical_psf_saturation(du, psf_coef[self.cam_i])
        else:
            assert StarFrame.STAR_SATURATION_MODELING == StarFrame.STAR_SATURATION_MODEL_IDEAL
            # do nothing

        du *= post_sat_gain
        self.c_expected_du = du
        return du
Beispiel #16
0
    def _match_stars(self,
                     stars,
                     max_dist=0.05,
                     max_mag_diff=2.0,
                     mag_cutoff=3.0,
                     plot=False):
        """ match stars based on proximity """
        merge_lim = 4
        all_stars, cols = Stars.flux_density(self.q,
                                             self.cam[0],
                                             array=True,
                                             undistorted=True,
                                             mag_cutoff=mag_cutoff + merge_lim,
                                             order_by='mag_v')
        if self.debug:
            db_img = np.sqrt(
                Stars.flux_density(self.q, self.cam[0], mag_cutoff=10.0))

        # override some star data, change None => nan
        for i, st in enumerate(all_stars):
            for j in range(len(st)):
                st[j] = np.nan if st[j] is None else st[j]
            if st[cols['id']] in self.override_star_data:
                for f in ('mag_v', 'mag_b', 't_eff', 'log_g', 'fe_h'):
                    od = self.override_star_data[st[cols['id']]]
                    if f in od:
                        all_stars[i][cols[f]] = od[f]

        # merge close stars
        all_stars = np.array(all_stars)
        points = np.array([(s[cols['ix']], s[cols['iy']]) for s in all_stars])
        D = tools.distance_mx(points, points)
        radius = 10 if self.cam[0].width > 300 else 2
        db_stars = []
        added = set()
        for i, s in enumerate(all_stars):
            if i in added:
                continue
            I = tuple(
                set(
                    np.where(
                        np.logical_and(
                            D[i, :] < radius, all_stars[:, cols['mag_v']] -
                            merge_lim < s[cols['mag_v']]))[0]) - added)
            cluster = [None] * (max(cols.values()) + 1)
            cluster[cols['id']] = tuple(all_stars[I,
                                                  cols['id']].astype(np.int))
            amag_v = 10**(-all_stars[I, cols['mag_v']] / 2.5)
            amag_b = 10**(-all_stars[I, cols['mag_b']] / 2.5)
            cluster[cols['mag_v']] = -2.5 * np.log10(np.sum(amag_v))
            cluster[cols['mag_b']] = -2.5 * np.log10(np.sum(amag_b))
            for c in ('ix', 'iy', 'dec', 'ra', 't_eff', 'fe_h', 'log_g'):
                E = np.where(all_stars[I, cols[c]] != None)[0]
                cluster[cols[c]] = np.sum(amag_v[E] *
                                          all_stars[I, cols[c]][E]) / np.sum(
                                              amag_v[E]) if len(E) else None
            if cluster[cols['mag_v']] < mag_cutoff:
                added.update(I)
                db_stars.append(cluster)

        img_st = np.array([(s['x'], s['y'], s['mag'], s['size'])
                           for s in stars])
        db_st = np.array([(s[cols['ix']], s[cols['iy']], s[cols['mag_v']])
                          for s in db_stars])

        # adjust mags to match, not easy to make match directly as unknown variable black level removed in image sensor
        #b0, b1 = np.min(img_st[:, 2]), np.min(db_st[:, 2])
        #d0, d1 = np.max(img_st[:, 2]), np.max(db_st[:, 2])
        #img_st[:, 2] = (img_st[:, 2] - b0) * (d1-b1)/(d0-b0) + b1
        #img_st[:, 2] = np.log10((10**img_st[:, 2] - 10**b0) * (10**d1-10**b1)/(10**d0-10**b0) + 10**b1)
        img_st[:, 2] = img_st[:, 2] - np.median(img_st[:, 2]) + np.median(
            db_st[:, 2])

        if self.cam[0].dist_coefs is not None:
            db_st[:, :2] = Camera.distort(
                db_st[:, :2], self.cam[0].dist_coefs,
                self.cam[0].intrinsic_camera_mx(legacy=False),
                self.cam[0].inv_intrinsic_camera_mx(legacy=False))

        M = (np.abs(
            np.repeat(
                np.expand_dims(img_st[:, 2:3], axis=0), len(db_st), axis=0) -
            np.repeat(
                np.expand_dims(db_st[:, 2:3], axis=1), len(img_st), axis=1))
             ).squeeze()
        D = np.repeat(np.expand_dims(img_st[:, :2], axis=0), len(db_st), axis=0) \
            - np.repeat(np.expand_dims(db_st[:, :2], axis=1), len(img_st), axis=1)
        D = np.sum(D**2, axis=2)
        D = D.flatten()
        D[M.flatten() > max_mag_diff] = np.inf
        D = D.reshape(M.shape)
        idxs = np.argmin(D, axis=0)
        max_dist = (self.image.shape[1] * max_dist)**2

        m_idxs = {}
        for i1, j in enumerate(idxs):
            dist = D[j, i1]
            if dist > max_dist or j in m_idxs and dist > D[j, m_idxs[j]]:
                # discard match if distance too high or better match for same db star available
                continue
            m_idxs[j] = i1

        matches = [None] * len(idxs)
        for j, i in m_idxs.items():
            matches[i] = db_stars[j]

        if self.debug and DEBUG_MATCHING or plot:
            if plot:
                norm = ImageNormalize(stretch=SqrtStretch())
                size = np.median(img_st[:, 3].astype('int'))
                data = np.mean(self.image.astype(np.float64) /
                               (2**self.bits - 1),
                               axis=2)

                ud_I = set(range(len(db_st))) - set(m_idxs.keys())
                d_I = set(range(len(img_st))) - set(m_idxs.values())
                # detected_pos = img_st[tuple(d_I), :2].astype('int')
                # matched_pos = img_st[tuple(m_idxs.values()), :2].astype('int')
                # undetected_pos = db_st[tuple(ud_I), :2].astype('int')

                plt.imshow(data, cmap='Greys', norm=norm)
                for i in d_I:  # detected
                    CircularAperture(img_st[i, :2].astype('int'),
                                     r=img_st[i, 3].astype('int')).plot(
                                         color='blue', lw=1.5, alpha=0.5)
                for i in m_idxs.values():  # matched
                    CircularAperture(img_st[i, :2].astype('int'),
                                     r=img_st[i, 3].astype('int')).plot(
                                         color='green', lw=1.5, alpha=0.5)
                for i in ud_I:  # undetected
                    CircularAperture(db_st[i, :2].astype('int'),
                                     r=size).plot(color='red',
                                                  lw=1.5,
                                                  alpha=0.5)
                plt.show()

            else:
                dec, ra, pa = map(math.degrees, tools.q_to_ypr(self.q))
                print('ra: %.1f, dec: %.1f, pa: %.1f' % (ra, dec, pa))

                sc, isc = 1, (1024 if 0 else 2800) / (self.image.shape[1] * 2)
                img = np.sqrt(self.image)
                img = ((img / np.max(img)) * 255).astype('uint8')
                img = cv2.resize(img,
                                 None,
                                 fx=isc,
                                 fy=isc,
                                 interpolation=cv2.INTER_AREA)
                cv2.drawKeypoints(img, [
                    cv2.KeyPoint(x * isc, y * isc, 60 * sc)
                    for x, y in db_st[:, :2]
                ], img, [0, 255, 0],
                                  cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
                cv2.drawKeypoints(img, [
                    cv2.KeyPoint(x * isc, y * isc, 60 * sc)
                    for x, y in img_st[:, :2]
                ], img, [255, 0, 0],
                                  cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
                for j, i in m_idxs.items():
                    cv2.line(
                        img,
                        tuple(np.round(img_st[i, :2] * isc).astype('int')),
                        tuple(np.round(db_st[j, :2] * isc).astype('int')),
                        [0, 255, 0])
                if DEBUG_MATCHING != 3:
                    for j, pt in enumerate(db_st[:, :2]):
                        cv2.putText(img, str(j),
                                    tuple(np.round(pt * isc).astype('int')),
                                    cv2.FONT_HERSHEY_SIMPLEX, 3 * sc,
                                    [0, 255, 0])
                else:
                    for i, pt in enumerate(img_st[:, :2]):
                        text = '%.2f' % img_st[i, 2]
                        #text = str(i)
                        cv2.putText(img, text,
                                    tuple(np.round(pt * isc).astype('int')),
                                    cv2.FONT_HERSHEY_SIMPLEX, 1.6 * sc,
                                    [0, 0, 255])

                db_img = np.repeat(np.expand_dims(db_img, axis=2),
                                   self.image.shape[2],
                                   axis=2)
                db_img = ((db_img / np.max(db_img)) * 255).astype('uint8')
                db_img = cv2.resize(db_img,
                                    None,
                                    fx=isc,
                                    fy=isc,
                                    interpolation=cv2.INTER_AREA)

                for j, pt in enumerate(db_st[:, :2]):
                    if DEBUG_MATCHING == 1:
                        text = '&'.join([
                            Stars.get_catalog_id(id)
                            for id in db_stars[j][cols['id']]
                        ])
                    elif DEBUG_MATCHING == 2:
                        t_eff = db_stars[j][cols['t_eff']]
                        t_eff2 = Stars.effective_temp(
                            db_stars[j][cols['mag_b']] -
                            db_stars[j][cols['mag_v']])
                        #if 1:
                        #    print('%s Teff: %s (%.1f)' % (Stars.get_catalog_id(db_stars[j][cols['id']]), t_eff, t_eff2))
                        text = ('%dK' % t_eff) if t_eff else ('(%dK)' % t_eff2)
                    elif DEBUG_MATCHING == 3:
                        text = '%.2f' % db_stars[j][cols['mag_v']]
                    cv2.putText(
                        db_img, text,
                        tuple(
                            np.round(pt * isc +
                                     np.array([5, -5])).astype('int')),
                        cv2.FONT_HERSHEY_SIMPLEX, 1.6 * sc, [255, 0, 0])

                cv2.drawKeypoints(db_img, [
                    cv2.KeyPoint(x * isc, y * isc, 60 * sc)
                    for x, y in db_st[:, :2]
                ], db_img, [0, 255, 0],
                                  cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

                img = np.hstack(
                    (db_img,
                     np.ones(
                         (img.shape[0], 1, img.shape[2]), dtype='uint8') * 255,
                     img))
                cv2.imshow('test', img)
                cv2.waitKey()

    #            plt.figure(1, (16, 12))
    #            plt.imshow(np.flip(img, axis=2))
    #            plt.tight_layout()
    #            plt.show()

        return matches, cols
Beispiel #17
0
def analyze_aurora_img(img_file, get_bgr_cam):
    debug = 1
    n = 0
    Frame.MISSING_BG_REMOVE_STRIPES = 0

    bgr_cam = get_bgr_cam(thumbnail=False, estimated=1, final=1)
    f = Frame.from_file(bgr_cam, img_file, img_file[:-4]+'.lbl', bg_offset=False, debug=debug)

    if 0:
        f.show_image(processed=True, save_as='C:/projects/s100imgs/processed-aurora.png')

    img = f.image.astype('float')

    if 0:
        img = img - np.percentile(img, 5, axis=1).reshape((-1, 1, 3))

    bg1 = (830, 1070), (1180, 1400)
#    bg1 = (0, 900), (660, 1280)
#    bg2 = (1560, 1050), (2048, 1350)
    mean_bg = np.mean(img[bg1[0][1]:bg1[1][1], bg1[0][0]:bg1[1][0], :].reshape((-1, 3)), axis=0)
#    mean_bg = np.mean(np.vstack((img[bg1[0][1]:bg1[1][1], bg1[0][0]:bg1[1][0], :].reshape((-1, 3)),
#                                 img[bg2[0][1]:bg2[1][1], bg2[0][0]:bg2[1][0], :].reshape((-1, 3)))), axis=0)
    img = img - mean_bg
    # img = ImageProc.apply_point_spread_fn(img - mean_bg, 0.01)
    # img = np.clip(img, 0, 1023).astype('uint16')
    # img = cv2.medianBlur(img, 31)
    # img = np.clip(img, 0, RAW_IMG_MAX_VALUE) / RAW_IMG_MAX_VALUE

    n += 1
    plt.figure(n)
    imsh = (np.clip(img * 2 + RAW_IMG_MAX_VALUE * 0.3, 0, RAW_IMG_MAX_VALUE) / RAW_IMG_MAX_VALUE * 255).astype('uint8')
    rd_y = (720, 700), (890, 720)
    rd_r1 = (720, 830), (890, 870)
    rd_r2 = (1080, 820), (1250, 860)
    gr_r = (1280, 770), (1450, 795)
    cv2.rectangle(imsh, bg1[0], bg1[1], (255, 0, 0), 2)       # bg1
#    cv2.rectangle(imsh, bg2[0], bg2[1], (255, 0, 0), 2)       # bg2
    cv2.rectangle(imsh, rd_y[0], rd_y[1], (0, 200, 200), 2)       # yellow
    cv2.rectangle(imsh, rd_r1[0], rd_r1[1], (0, 0, 255), 2)     # red1
    cv2.rectangle(imsh, rd_r2[0], rd_r2[1], (0, 0, 255), 2)     # red2
    cv2.rectangle(imsh, gr_r[0], gr_r[1], (0, 255, 0), 2)     # green
    plt.imshow(np.flip(imsh, axis=2))
    plt.show()

    def electrons(lam):
        h = 6.626e-34  # planck constant (m2kg/s)
        c = 3e8  # speed of light
        return h * c / lam  # energy per photon

    blue = 427.8e-9
    green = 557.7e-9
    yellow = 589.3e-9
    red = 630.0e-9
    colors = (blue, green, yellow, red)
    dus_per_rad = dict(zip(colors, ([], [], [], [])))   # DUs per 1 W/m2/sr of radiance
    coef = f.exposure * f.gain * RAW_IMG_MAX_VALUE

    for wl in dus_per_rad.keys():
        for cam in bgr_cam:
            cgain = cam.gain * cam.emp_coef * cam.aperture_area
            fn, _ = Camera.qeff_fn(tuple(cam.qeff_coefs), 350e-9, 1000e-9)

            # W/m2/sr => phot/s/m2/sr => elec/s/m2/sr => DUs/sr
            dus_per_rad[wl].append(1/electrons(wl) * fn(wl) * coef * cgain)
    for wl in dus_per_rad.keys():
        dus_per_rad[wl] = np.array(dus_per_rad[wl])

    class Patch:
        def __init__(self, name, rect, bands, mean=None, rad=None):
            self.name, self.rect, self.bands, self.mean, self.rad = name, rect, bands, mean, rad
    nt = lambda n, r, b: Patch(name=n, rect=r, bands=b)

    patches = [
        nt('Clean Red', rd_r1, (blue, green, red)),
        nt('Strong Red', rd_r2, (blue, green, red)),
        nt('Green', gr_r, (blue, green, red)),
        nt('Sodium', rd_y, (blue, green, yellow)),
    ]

    # pseudo inverse
    for p in patches:
        p.mean = np.mean(img[p.rect[0][1]:p.rect[1][1], p.rect[0][0]:p.rect[1][0], :].reshape((-1, 3)), axis=0)
        px_sr = cam.pixel_solid_angle((p.rect[0][0]+p.rect[1][0])//2, (p.rect[0][1]+p.rect[1][1])//2)
        E = np.hstack((dus_per_rad[p.bands[0]], dus_per_rad[p.bands[1]], dus_per_rad[p.bands[2]])) * px_sr
        invE = np.linalg.inv(E.T.dot(E)).dot(E.T)
        rad = invE.dot(p.mean)    # radiance in W/m2/sr
        # e = E.dot(rad)
        # diff = (p.mean - e) * 100 / np.linalg.norm(p.mean)
        p.rad = [''] * len(colors)
        for i, b in enumerate(p.bands):
            idx = colors.index(b)
            p.rad[idx] = rad[i]

    sep = '\t' if 1 else ' & '
    le = '\n' if 1 else ' \\\\\n'
    if 0:
        print(sep.join(('Patch', 'Emission at', '', '', 'Red', 'Green', 'Blue')), end=le)
        for name, irr, mean, model, diff in patches:
            print(sep.join((name, '428 nm', ('%.3e' % irr[0]) if irr[0] else 'n/a', 'Mean',
                            *('%.1f' % m for m in np.flip(mean.flatten())))), end=le)
            print(sep.join(('', '557.7 nm', ('%.3e' % irr[1]) if irr[1] else 'n/a', 'Modeled',
                            *('%.1f' % m for m in np.flip(model.flatten())))), end=le)
            print(sep.join(('', '589 nm', ('%.3e' % irr[2]) if irr[2] else 'n/a', 'Diff. [%]',
                            *('%.1f' % m for m in np.flip(diff.flatten())))), end=le)
            print(sep.join(('', '630 nm', ('%.3e' % irr[3]) if irr[3] else 'n/a', *(['']*4))), end=le)
    else:
        print(sep.join(('Patch', 'Red', 'Green', 'Blue', '428 nm', '557.7 nm', '589 nm', '630 nm')), end=le)
        for p in patches:
            # in kilo Rayleigh (kR) == 6330*1e9*lambda * W/m2/sr    or  4*pi*10^(-10)*10^(-3) * photon flux
            print(sep.join((p.name, *('%.1f' % m for m in np.flip(p.mean.flatten())),
                                    *(tools.fixed_precision(r*4*np.pi*1e-13/electrons(colors[i]), 3, True) if r else ''  # r*1e-13*4*np.pi
                                      for i, r in enumerate(p.rad)))), end=le)
    quit()

    aurora = np.zeros_like(img)
    for i, color in enumerate(colors):
        # d/dx[(r-aw)'*(r-aw)] == 0
        #  => w == (r'*a)/(a'*a)
        a = emission[color]
        w = np.sum(img.reshape((-1, 3)) * a.T, axis=1) / sum(a**2)
        e = (w*a).T
        r = img.reshape((-1, 3)) - e
        x = w / np.linalg.norm(r, axis=1)

        # plt.figure(2)
        # plt.imshow(w.reshape(img.shape[:2])/np.max(w))
        # plt.title('weight (max=%f)' % np.max(w))

        # plt.figure(3)
        # plt.imshow(x.reshape(img.shape[:2])/np.max(x))
        # plt.title('x (max=%f)' % np.max(x))

        n += 1
        plt.figure(n)
        x[x < {red: 10, green: 6, yellow: 16}[color]] = 0
        x[w < 100] = 0
        xf = ImageProc.apply_point_spread_fn(x.reshape(img.shape[:2]), 0.03)
        xf = cv2.medianBlur(xf.astype('uint16'), 11)
        plt.imshow(xf / np.max(xf))
        plt.title('Emission detection @ %.1fnm' % (color * 1e9))

        e[xf.flatten() == 0, :] = (0, 0, 0)
        aurora += e.reshape(img.shape)

        # plt.figure(6)
        # plt.imshow(np.flip(e.reshape(img.shape) / np.max(e), axis=2))
        # plt.title('modeled aurora')

        # plt.figure(7)
        # plt.imshow(np.flip(r.reshape(img.shape)/np.max(r), axis=2))
        # plt.title('residual')
        # plt.show()

    plt.figure(8)
    plt.imshow(np.flip(aurora / np.max(aurora), axis=2))
    plt.title('modeled aurora')
    plt.show()

    # TODO: translate rgb values to aurora (ir)radiance
    #  - following uses W/m2/sr for "in-band radiance"
    #  - https://www.osapublishing.org/DirectPDFAccess/A2F3D832-975A-1850-088634AAFCF21258_186134/ETOP-2009-ESB4.pdf?da=1&id=186134&uri=ETOP-2009-ESB4&seq=0&mobile=no
    #  - use pixel sr?

    print('done')
Beispiel #18
0
        def cost_fun(x, measures, prior_x, return_details=False, plot=False):
            c_qeff_coefs, f_gains, gain_adj, psf_coef = decode(x)

            band = []
            obj_ids = []
            measured_du = []
            expected_du = []
            weights = []
            for m in measures:
                if FRAME_GAINS == FRAME_GAIN_SAME:
                    pre_sat_gain = f_gains[0]
                elif FRAME_GAINS == FRAME_GAIN_INDIVIDUAL:
                    pre_sat_gain = f_gains[m.frame.id]
                elif FRAME_GAINS == FRAME_GAIN_STATIC:
                    if m.obj_id[0] == 'moon':
                        pre_sat_gain = MOON_GAIN_ADJ
                    else:
                        pre_sat_gain = STAR_GAIN_ADJUSTMENT if m.frame.cam[
                            0].emp_coef >= 1 else STAR_GAIN_ADJUSTMENT_TN
                else:
                    pre_sat_gain = 1

                edu = m.expected_du(pre_sat_gain=pre_sat_gain,
                                    post_sat_gain=gain_adj,
                                    qeff_coefs=c_qeff_coefs,
                                    psf_coef=psf_coef)

                if return_details or (m.obj_id[0],
                                      m.cam_i) not in IGNORE_MEASURES:
                    expected_du.append(edu)
                    measured_du.append(m.du_count)
                    weights.append(m.weight)
                    band.append(m.cam_i)
                    obj_ids.append(m.obj_id)

            measured_du, expected_du, band = map(
                np.array, (measured_du, expected_du, band))

            if plot:
                plt.rcParams.update({'font.size': 16})
                fig, ax = plt.subplots(1, 1, figsize=[6.4, 4.8])
                sb, = ax.plot(expected_du[band == 0] * 1e-3,
                              measured_du[band == 0] * 1e-3, 'bx')
                sg, = ax.plot(expected_du[band == 1] * 1e-3,
                              measured_du[band == 1] * 1e-3, 'gx')
                sr, = ax.plot(expected_du[band == 2] * 1e-3,
                              measured_du[band == 2] * 1e-3, 'rx')
                line = np.linspace(0, np.max(expected_du))
                ax.plot(line * 1e-3, line * 1e-3, 'k--', linewidth=0.5)
                ax.set_xlabel('Expected [1000 DNs]')
                ax.set_ylabel('Measured [1000 DNs]')
                names = Stars.get_catalog_id(
                    np.unique(list(s[0] for s in obj_ids if s[0] != 'moon')),
                    'simbad')
                names['moon'] = 'Moon'
                labels = np.array([names[id[0]] for id in obj_ids])
                tools.hover_annotate(fig, ax, sb, labels[band == 0])
                tools.hover_annotate(fig, ax, sg, labels[band == 1])
                tools.hover_annotate(fig, ax, sr, labels[band == 2])
                plt.tight_layout()
                plt.show()

            _, _, gain_adj0, _ = decode(prior_x)
            #            err = tuple(tools.pseudo_huber_loss(STAR_CALIB_HUBER_COEF, (measured_du - expected_du) * 2 / (expected_du + measured_du)) * np.array(weights))
            err = tuple(
                tools.pseudo_huber_loss(
                    STAR_CALIB_HUBER_COEF,
                    np.log10(expected_du) - np.log10(measured_du)) *
                np.array(weights))

            n = 3 * len(c_qeff_coefs[0])

            lab_dp = tuple()
            if STAR_LAB_DATAPOINT_WEIGHT > 0:
                c, lam = m.frame.cam, 557.7e-9
                g = Camera.sample_qeff(c_qeff_coefs[1], c[1].lambda_min,
                                       c[1].lambda_max, lam)
                eps = 1e-10
                r_g = (Camera.sample_qeff(c_qeff_coefs[2], c[2].lambda_min,
                                          c[2].lambda_max, lam) + eps) / (g +
                                                                          eps)
                b_g = (Camera.sample_qeff(c_qeff_coefs[0], c[0].lambda_min,
                                          c[0].lambda_max, lam) + eps) / (g +
                                                                          eps)
                lab_dp = tuple(STAR_LAB_DATAPOINT_WEIGHT * (np.log10(r_g) - np.log10(np.array((0.26, 0.25, 0.24, 0.24))))**2) \
                        +tuple(STAR_LAB_DATAPOINT_WEIGHT * (np.log10(b_g) - np.log10(np.array((0.23, 0.24, 0.21, 0.22))))**2)

            prior = tuple(STAR_CALIB_PRIOR_WEIGHT ** 2 * (np.array(x[:n]) - np.array(prior_x[:n])) ** 2) \
                if STAR_CALIB_PRIOR_WEIGHT > 0 else tuple()

            err_tuple = lab_dp + err + prior
            return (err_tuple, measured_du, expected_du) if return_details else \
                    err_tuple if opt_method == 'leastsq' else \
                    np.sum(err_tuple)
Beispiel #19
0
    def __init__(self,
                 target_primary=True,
                 hi_res_shape_model=False,
                 use_narrow_cam=True,
                 res_mult=1.0):
        # gives some unnecessary warning about "dubious year" even when trying to ignore it
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            min_time = Time('2023-01-01 00:00:00', scale='utc', format='iso')

        common_kwargs_worst = {
            'sensor_size': (2048 * 0.0022, 1944 * 0.0022),  # diagonal: 6.2mm
            'quantum_eff': 0.30,
            'px_saturation_e': 2200,  # snr_max = 20*log10(sqrt(sat_e)) dB
            'lambda_min': 350e-9,
            'lambda_eff': 580e-9,
            'lambda_max': 800e-9,
            'dark_noise_mu': 40,
            'dark_noise_sd': 6.32,
            'readout_noise_sd':
            15,  # dark_noise_sd should be sqrt(dark_noise_mu)
            'emp_coef': 1,  # dynamic range = 20*log10(sat_e/readout_noise))
            'exclusion_angle_x': 55,
            'exclusion_angle_y': 90,
        }
        common_kwargs_best = dict(common_kwargs_worst)
        common_kwargs_best.update({
            'quantum_eff': 0.4,
            'px_saturation_e': 3500,
            'dark_noise_mu': 25,
            'dark_noise_sd': 5,
            'readout_noise_sd': 5,
        })
        common_kwargs = common_kwargs_best

        narrow_cam = Camera(
            2048 * res_mult,  # width in pixels
            1944 * res_mult,  # height in pixels
            7.7,  # x fov in degrees  (could be 6 & 5.695, 5.15 & 4.89, 7.7 & 7.309)
            7.309,  # y fov in degrees
            f_stop=5,  # TODO: put better value here
            point_spread_fn=0.50,  # ratio of brightness in center pixel
            scattering_coef=
            2e-10,  # affects strength of haze/veil when sun shines on the lens
            **common_kwargs)
        wide_cam = Camera(
            2048 * res_mult,  # width in pixels
            1944 * res_mult,  # height in pixels
            61.5,  # x fov in degrees
            58.38,  # y fov in degrees
            f_stop=5,  # TODO: put better value here
            point_spread_fn=0.35,  # ratio of brightness in center pixel
            scattering_coef=
            2e-10,  # affects strength of haze/veil when sun shines on the lens
            **common_kwargs)

        if target_primary:
            if use_narrow_cam:
                mission_id = 'didy1n'
                limits = (
                    3.5,  # min_distance in km
                    6.5,  # min_med_distance in km
                    10.5,  # max_med_distance in km
                    10.5,  # max_distance in km
                    45,  # min_elong in deg
                    min_time,  # min time instant
                )
            else:
                mission_id = 'didy1w'
                limits = (
                    1.0,  # min_distance in km
                    1.1,  # min_med_distance in km
                    6.0,  # max_med_distance in km
                    10.5,  # max_distance in km
                    45,  # min_elong in deg
                    min_time,  # min time instant
                )
        else:
            if use_narrow_cam:
                mission_id = 'didy2n'
                limits = (
                    1.0,  # min_distance in km
                    1.65,  # min_med_distance in km
                    5.3,  # max_med_distance in km
                    7.0,  # max_distance in km
                    45,  # min_elong in deg
                    min_time,  # min time instant
                )
            else:
                mission_id = 'didy2w'
                limits = (
                    0.135,  # min_distance in km
                    0.28,  # min_med_distance in km
                    1.3,  # max_med_distance in km
                    1.3,  # max_distance in km
                    45,  # min_elong in deg
                    min_time,  # min time instant
                )

        super(DidymosSystemModel, self).__init__(
            asteroid=DidymosPrimary(hi_res_shape_model=hi_res_shape_model)
            if target_primary else DidymosSecondary(
                hi_res_shape_model=hi_res_shape_model),
            camera=narrow_cam if use_narrow_cam else wide_cam,
            limits=limits,
        )
        self.mission_id = mission_id
        self.sc_model_file = os.path.join(DATA_DIR, 'apex-x1-2019-05-28.obj')
Beispiel #20
0
def replay_keyframes(cam: Camera,
                     keyframes: List[Frame] = None,
                     map3d: List[Keypoint] = None,
                     file: str = 'results.pickle'):
    import cv2

    if keyframes is None:
        with open(file, 'rb') as fh:
            keyframes, map3d, frame_names, meta_names, ground_truth, *ba_errs = pickle.load(
                fh)
            ba_errs = ba_errs[0] if len(ba_errs) else None

    if isinstance(keyframes[0], Frame):
        keyframes = [
            dict(pose=kf.pose,
                 meas=kf.measure,
                 time=kf.time,
                 id=kf.id,
                 kps_uv=kf.kps_uv,
                 image=kf.image) for kf in keyframes
        ]

    kp_size, kp_color = 5, (200, 0, 0)
    kp_ids = set(kf.id for kf in map3d
                 if not kf.bad_qlt and kf.inlier_count > 2
                 and kf.inlier_count / kf.total_count > 0.2)
    map3d = {kf.id: kf for kf in map3d}
    img_scale = 0.5

    for kf in keyframes:
        if kf['pose'] is None or kf['pose'].post is None:
            continue

        obs_ids = list(kp_ids.intersection(kf['kps_uv'].keys()))
        if len(obs_ids) == 0:
            continue

        image = kf['image'].copy() if 'image' in kf else np.zeros(
            (int(cam.height * img_scale), int(cam.width * img_scale), 3),
            dtype=np.uint8)
        if len(image.shape) == 2 or image.shape[2] == 1:
            image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)

        p_pts2d = (np.array([kf['kps_uv'][id]
                             for id in obs_ids]) + 0.5).astype(int).squeeze()
        p_pts3d = np.array([map3d[id].pt3d for id in obs_ids])

        pts3d_cf = tools.q_times_mx(kf['pose'].post.quat,
                                    p_pts3d) + kf['pose'].post.loc
        pts2d_proj = (cam.project(pts3d_cf.astype(np.float32)) * img_scale +
                      0.5).astype(int)

        for (x, y), (xp, yp) in zip(p_pts2d, pts2d_proj):
            image = cv2.circle(image, (x, y), kp_size, kp_color,
                               1)  # negative thickness => filled circle
            image = cv2.rectangle(image, (xp - 2, yp - 2), (xp + 2, yp + 2),
                                  kp_color, 1)
            image = cv2.line(image, (xp, yp), (x, y), kp_color, 1)

        cv2.imshow('keypoint reprojection', image)
        cv2.waitKey()