def test_actually_produces_stars(self): cmd = scopesim.UserCommands(use_instrument="WFC3", properties={"!OBS.dit": 100, "!OBS.ndit": 10}) cmd.ignore_effects += ["detector_linearity"] opt = scopesim.OpticalTrain(cmd) src = scopesim.source.source_templates.star_field(10000, 5, 15, 440) opt.observe(src) hdu = opt.readout()[0] implane_av = np.average(opt.image_planes[0].data) hdu_av = np.average(hdu[1].data) exptime = cmd["!OBS.ndit"] * cmd["!OBS.dit"] assert hdu_av == approx(implane_av * exptime, rel=0.01) if PLOTS: plt.subplot(1, 2, 1) plt.imshow(opt.image_planes[0].image[128:2048, 128:2048].T, norm=LogNorm()) plt.colorbar() plt.subplot(1, 2, 2) plt.imshow(hdu[1].data[128:2048, 128:2048].T, norm=LogNorm(), vmax=3e7) plt.colorbar() plt.show()
def test_integrated_vega_flux_is_what_is_expected(self): cmds = sim.UserCommands(use_instrument="METIS", set_modes=["lss_l"]) metis = sim.OpticalTrain(cmds) toggle_effects = [ "skycalc_atmosphere", "telescope_reflection", "common_fore_optics", # "metis_img_lm_mirror_list", # "quantum_efficiency", # "psf" ] for eff in toggle_effects: metis[eff].include = False src = star(flux=1 * u.Jy) metis.observe(src) img = metis.image_planes[0].data metis_phs = img.sum() sys_trans = metis.optics_manager.system_transmission one_jy_phs = hmbp.in_one_jansky(sys_trans).value * 978 if PLOTS: plt.imshow(img, origin="lower", norm=LogNorm(), vmin=1e-8) plt.show() assert metis_phs == approx(one_jy_phs, rel=0.1)
def test_works(self): src = star(flux=0, x=0, y=0) + \ star(flux=2, x=-2, y=0) + \ star(flux=4, x=2, y=0) # src = empty_sky() cmds = sim.UserCommands(use_instrument="METIS", set_modes=["lss_m"]) cmds["!OBS.dit"] = 1 metis = sim.OpticalTrain(cmds) metis["psf"].include = False metis.observe(src) hdus = metis.readout() implane = metis.image_planes[0].data det_img = hdus[0][1].data assert 0 < np.sum(implane) < np.sum(det_img) if PLOTS: plt.subplot(122) plt.imshow(hdus[0][1].data, origin="lower", norm=LogNorm(), vmin=1) plt.title("Detctor Plane (with noise)") plt.colorbar() plt.subplot(121) plt.imshow(metis.image_planes[0].data, origin="lower", norm=LogNorm(), vmin=1) plt.title("Image Plane (noiseless)") plt.colorbar() plt.show()
def test_actually_produces_stars(self): cmd = scopesim.UserCommands(use_instrument="HAWKI", properties={"!OBS.dit": 360, "!OBS.ndit": 10}) cmd.ignore_effects += ["detector_linearity"] opt = scopesim.OpticalTrain(cmd) src = scopesim.source.source_templates.star_field(10000, 5, 15, 440) # ETC gives 2700 e-/DIT for a 1s DET at airmass=1.2, pwv=2.5 # background should therefore be ~ 8.300.000 opt.observe(src) hdu = opt.readout()[0] implane_av = np.average(opt.image_planes[0].data) hdu_av = np.average([hdu[i].data for i in range(1, 5)]) exptime = cmd["!OBS.ndit"] * cmd["!OBS.dit"] assert hdu_av == approx(implane_av * exptime, rel=0.01) if PLOTS: plt.subplot(1, 2, 1) plt.imshow(opt.image_planes[0].image[128:2048, 128:2048].T, norm=LogNorm()) plt.colorbar() plt.subplot(1, 2, 2) plt.imshow(hdu[1].data[128:2048, 128:2048].T, norm=LogNorm(), vmax=3e7) plt.colorbar() plt.show()
def calculate_background(self, mode_names, filt_name, etc_flux_values, mag_diff, xtimes): """ Comparison of the scopesim MICADO package against the ESO ETC Notes ----- - mag_diff the discrepancy between the ETC and the skycalc BG mags - The ETC uses 1100m2 area and 5mas pixel size - ETC sky BG mags can be found on the ETC website, skycalc BG mags are given when getting a spectrum on the skycalc website """ cmd = scopesim.UserCommands(use_instrument="MICADO", set_modes=mode_names, properties={"!OBS.filter_name": filt_name}) opt = scopesim.OpticalTrain(cmd) src = scopesim.source.source_templates.empty_sky() opt.observe(src) av_sim_bg = np.average(opt.image_planes[0].hdu.data) sim_pix_scale = cmd["!INST.pixel_scale"] sim_area = cmd["!TEL.area"].value etc_pix_scale = 0.005 etc_area = 1100 scale_factor = sim_pix_scale**2 / etc_pix_scale**2 * sim_area / etc_area scale_factor *= 2.512**-mag_diff scaled_etc_bg = etc_flux_values * scale_factor assert 1 / xtimes < scaled_etc_bg / av_sim_bg < xtimes print(filt_name, scaled_etc_bg, av_sim_bg)
def run_metis_lss(): # src = sim.source.source_templates.empty_sky() spec = source_templates.ab_spectrum() src = sim.Source(x=[-1, 0, 1], y=[0, 0, 0], ref=[0, 0, 0], weight=[1, 1, 1], spectra=[spec]) cmds = sim.UserCommands(use_instrument="METIS", set_modes=["lss_m"]) metis = sim.OpticalTrain(cmds) metis["metis_psf_img"].include = False pr = cProfile.Profile() pr.enable() metis.observe(src) pr.disable() pr.print_stats(sort="cumulative") hdus = metis.readout() plt.subplot(122) plt.imshow(hdus[0][1].data, origin="lower", norm=LogNorm()) plt.title("Detctor Plane (with noise)") plt.colorbar() plt.subplot(121) plt.imshow(metis.image_planes[0].data, origin="lower", norm=LogNorm()) plt.title("Image Plane (noiseless)") plt.colorbar() plt.show()
def test_spec_for_a_specific_wavelength_range_works(self): n = 11 src = sim.source.source_templates.star_field(n, 15, 25, 3, use_grid=False) src.fields[0]["x"] = np.linspace(-1.5, 1.5, n) src.fields[0]["y"] = [0] * n # src needs to be shifted to prevent an error from astropy.units: # "TypeError: None is not a valid Unit src.shift() cmd = sim.UserCommands(use_instrument="MICADO_Sci", set_modes=["SCAO", "SPEC"]) cmd["!OBS.dit"] = 3600 # sec cmd["!SIM.spectral.wave_mid"] = 1.95 # um cmd["!INST.aperture.width"] = 3 # arcsec cmd["!INST.aperture.height"] = 0.05 # arcsec cmd["!DET.width"] = int( (cmd["!INST.aperture.width"] / 0.004) * 1.1) # pixel cmd["!DET.height"] = 128 # pixel opt = sim.OpticalTrain(cmd) opt.observe(src) hdu = opt.readout()[0] # hdu.writeto("spec_scao_massive.TEST.fits", overwrite=True) if PLOTS: plt.imshow(hdu[1].data, norm=LogNorm()) plt.show()
def test_one_jansky_flux_is_as_expected(self, mode_name): """ hmbp.in_one_jansky(metis.system_transmission) --> 2.35e6 ph / (m2 s) in metis (*978m2) --> 2300e6 ph / s """ cmd = sim.UserCommands(use_instrument="METIS", set_modes=[mode_name]) metis = sim.OpticalTrain(cmd) for eff in ["skycalc_atmosphere", # Adds ~58000 ph/s/pix "telescope_reflection", # Adds ~20 ph/s/pix "common_fore_optics", # EntrWindow alone adds ~14700 ph/s/pix #"metis_img_lm_mirror_list", # Adds ~0 ph/s/pix "quantum_efficiency", "psf" ]: metis[eff].include = False src = star(flux=1*u.Jy) metis.observe(src) n = 32 img = metis.image_planes[0].data img_sum = np.sum(img[1024-n:1024+n, 1024-n:1024+n]) img_med = np.median(img[n:3*n, n:3*n]) print(f"Sum star: {img_sum}, Median top-left: {img_med}") sys_trans = metis.optics_manager.system_transmission one_jy_phs = hmbp.in_one_jansky(sys_trans).value * 978 if PLOTS: plt.imshow(img[1024-n:1024+n, 1024-n:1024+n], norm=LogNorm()) plt.show() assert img_sum == approx(one_jy_phs, rel=0.05)
def make_micado_rst_files(): all_modes = [ "SCAO", "MCAO", "IMG_4mas", "IMG_1.5mas", # "IMG_HCI", "SPEC_3000x50" ] cmd = sim.UserCommands(use_instrument="MICADO", set_modes=all_modes) rc.__currsys__ = cmd opt_els = [] for yaml in cmd.yaml_dicts: if yaml["alias"] != "OBS": opt_el = sim.optics.OpticalElement(yaml_dict=yaml) opt_els += [opt_el] fname = pth.join(rc.__config__["!SIM.reports.rst_path"], "pipe_{}.rst".format(opt_el.meta["name"])) opt_el.report(filename=fname) opt_man = sim.optics.OpticsManager(None) opt_man.optical_elements = opt_els summary_effects(opt_man, filename="pipe_summary.rst")
def test_something_comes_out_img_n(self): """Basic test for N imaging""" src = star_field(100, 0, 10, width=10, use_grid=True) cmds = scopesim.UserCommands(use_instrument="METIS", set_modes=["img_n"]) metis = scopesim.OpticalTrain(cmds) metis['chop_nod'].include = False #metis['detector_linearity'].include = False metis.observe(src) hdus = metis.readout() im = metis.image_planes[0].data mx, med, std = np.max(im), np.median(im), np.std(im) if PLOTS: for i, img in enumerate([metis.image_planes[0].data, hdus[0][1].data]): plt.subplot(1, 2, i+1) med = np.median(img) plt.imshow(img, vmin=0.7*med, vmax=1.3*med, norm=LogNorm()) plt.title("LM Imaging Test") plt.colorbar() plt.show() assert mx > med + 3 * std
def test_image_is_visible(self): cmd = sim.UserCommands(use_instrument="METIS", set_modes=["img_n"]) metis = sim.OpticalTrain(cmd) for eff in ["skycalc_atmosphere", # Adds ~58000 ph/s/pix "telescope_reflection", # Adds ~20 ph/s/pix "common_fore_optics", # EntrWindow alone adds ~14700 ph/s/pix "chop_nod", # "metis_img_lm_mirror_list", # Adds ~0 ph/s/pix # "quantum_efficiency", "psf" ]: metis[eff].include = False hdu = fits.open(r"F:\temp\scopesim_metis_workshop\data\sd0490_image_l12_i090_p000.fits") hdu[0].header["CDELT1"] *= 10 hdu[0].header["CDELT2"] *= 10 hdu[0].header["CUNIT1"] = "deg" hdu[0].header["CUNIT2"] = "deg" hdu[0].header["CRVAL1"] = 0 hdu[0].header["CRVAL2"] = 0 src = sim.Source(image_hdu=hdu[0], flux=1*u.Jy) # src = empty_sky() metis.observe(src) img = metis.image_planes[0].data if PLOTS: plt.imshow(img) plt.show()
def test_system_transmission_is_similar_to_eso_etc(self): """ A ~20% discrepency between the ESO and ScopeSim system throughputs """ for filt_name in ["Y", "J", "H", "Ks", "BrGamma", "CH4"]: cmd = scopesim.UserCommands(use_instrument="HAWKI") cmd["!OBS.filter_name"] = filt_name opt = scopesim.OpticalTrain(cmd) opt["paranal_atmo_default_ter_curve"].include = False src = _single_table_source(n=1000) opt.observe(src) if PLOTS: fname = "hawki_eso_etc/TER_system_{}.dat".format(filt_name) dname = os.path.dirname(__file__) etc_tbl = ascii.read(os.path.join(dname, fname)) etc_wave = etc_tbl["wavelength"] * 1e-3 * u.um etc_thru = etc_tbl["transmission"] * 1e-2 # plt.plot(etc_wave, etc_thru, c="b", label="ESO/ETC") flux_init = src.spectra[0](etc_wave) flux_final = opt._last_source.spectra[0](etc_wave) ss_thru = flux_final / flux_init # plt.plot(etc_wave, ss_thru, c="r", label="ScopeSim/HAWKI") plt.plot(etc_wave, ss_thru / etc_thru - 1) plt.ylim(0, 0.5) plt.show()
def test_background_is_similar_to_online_etc(self): cmd = scopesim.UserCommands(use_instrument="HAWKI") opt = scopesim.OpticalTrain(cmd) src = scopesim.source.source_templates.empty_sky() # ETC gives 2700 e-/DIT for a 1s DET at airmass=1.2, pwv=2.5 opt.observe(src) assert np.average(opt.image_planes[0].data) == approx(2700, rel=0.2)
def test_scopesim_loads_package(self, themode): """Load the configuration for all supported modes""" cmd = scopesim.UserCommands(use_instrument="METIS", set_modes=[themode]) assert isinstance(cmd, scopesim.UserCommands) metis = scopesim.OpticalTrain(cmd) assert isinstance(metis, scopesim.OpticalTrain)
def test_user_commands_loads_without_throwing_errors(self, capsys): cmd = scopesim.UserCommands(use_instrument="MICADO") assert isinstance(cmd, scopesim.UserCommands) for key in ["SIM", "OBS", "ATMO", "TEL", "INST", "DET"]: assert key in cmd and len(cmd[key]) > 0 stdout = capsys.readouterr() assert len(stdout.out) == 0
def test_background_is_similar_to_online_etc(self): cmd = scopesim.UserCommands(use_instrument="WFC3") opt = scopesim.OpticalTrain(cmd) src = scopesim.source.source_templates.empty_sky() # ..todo:: Don't know what the real HST background is opt.observe(src) print("HELLO", np.average(opt.image_planes[0].data)) assert np.average(opt.image_planes[0].data) == approx(0.22, rel=0.2)
def test_instrument_throughput_without_atmospheric_bg(self): cmd = sim.UserCommands(use_instrument="METIS", set_modes=["img_lm"]) metis = sim.OpticalTrain(cmd) metis["skycalc_atmosphere"].include = True src = empty_sky() metis.observe(src) img = metis.image_planes[0].data plt.imshow(img) plt.show()
def test_background_level_is_around_roys_level(self, filter_name, expected_phs): src = empty_sky() cmd = sim.UserCommands(use_instrument="METIS", set_modes=["img_lm"]) cmd["!OBS.filter_name"] = filter_name metis = sim.OpticalTrain(cmd) metis['detector_linearity'].include = False metis.observe(src) img = metis.image_planes[0].data assert np.median(img) == approx(expected_phs, rel=0.1)
def test_get_lim_mags_for_micado(self): dit, ndit = 3.6, 5000 filter_name = "Ks" bg_mag = 13.6 from scopesim.source.source_templates import star_field src = star_field(8 * 8, 26, 33, 3, use_grid=True) cmd = scopesim.UserCommands(use_instrument="MICADO", properties={ "!OBS.filter_name": filter_name, "!OBS.dit": dit, "!OBS.ndit": ndit }) opt = scopesim.OpticalTrain(cmd) opt["armazones_atmo_dispersion"].include = False opt["micado_adc_3D_shift"].include = False opt["detector_linearity"].include = False opt["detector_window"].include = True opt["full_detector_array"].include = False new_kwargs = { "rescale_emission": { "filter_name": filter_name, "filename_format": "filters/TC_filter_{}.dat", "value": bg_mag, "unit": "mag" } } opt["armazones_atmo_default_ter_curve"] = new_kwargs opt.observe(src) hdus = opt.readout() # hdus = opt.readout(filename=f"test_{dit}s.fits") print(opt.effects) image = hdus[0][1].data pixel_scale = opt.cmds["!INST.pixel_scale"] xs = src.fields[0]["x"] / pixel_scale + image.shape[1] / 2 ys = src.fields[0]["y"] / pixel_scale + image.shape[1] / 2 if PLOTS: plt.imshow(image, norm=LogNorm()) # plt.plot(xs, ys, "r.") plt.show() snr = get_snr(xs=xs, ys=ys, image=hdus[0][1].data, inner=5, outer=10) plt.plot(src.fields[0]["weight"], snr) plt.show()
def test_works_seamlessly_for_micado_wide_mode(self): cmd = scopesim.UserCommands(use_instrument="MICADO", properties={"!OBS.filter_name": "Ks"}) opt = scopesim.OpticalTrain(cmd) assert isinstance(opt, scopesim.OpticalTrain) # src = scopesim.source.source_templates.star_field(10000, 10, 25, 20) src = scopesim.source.source_templates.empty_sky() opt.observe(src) hdu_list = opt.readout()[0] assert isinstance(hdu_list, fits.HDUList)
def test_integrated_spec_bg_equals_img_bg(self): src = empty_sky() toggle_effects = [ # "skycalc_atmosphere", # "telescope_reflection", # "common_fore_optics", # "metis_img_lm_mirror_list", # "quantum_efficiency", # "psf", ] cmds_img = sim.UserCommands(use_instrument="METIS", set_modes=["img_lm"]) cmds_img["!SIM.spectral.wave_min"] = 3.5 cmds_img["!SIM.spectral.wave_max"] = 4.0 metis_img = sim.OpticalTrain(cmds_img) for eff in toggle_effects: metis_img[eff].include = False metis_img.observe(src) img = metis_img.image_planes[0].data cmds_lss = sim.UserCommands(use_instrument="METIS", set_modes=["lss_l"]) cmds_lss["!SIM.spectral.wave_min"] = 3.5 cmds_lss["!SIM.spectral.wave_max"] = 4.0 metis_lss = sim.OpticalTrain(cmds_lss) for eff in toggle_effects: metis_lss[eff].include = False metis_lss.observe(src) lss = metis_lss.image_planes[0].data img_med = np.median(img) lss_med = np.median(np.sum(lss, axis=0)) # 7x because we need to sum up the overlapping slice images # and the slit is 7 pixels wide assert 7 * img_med == approx(lss_med, rel=0.05)
def test_get_lim_mags_for_micado(self): dit, ndit = 60, 60 * 5 filter_name = "J" bg_mag = 16.5 from scopesim.source.source_templates import star_field src = star_field(10**2, 20, 30, 1.8, use_grid=True) cmd = scopesim.UserCommands(use_instrument="MICADO", properties={ "!OBS.filter_name": filter_name, "!OBS.dit": dit, "!OBS.ndit": ndit, "!ATMO.background.magnitude": bg_mag, "!ATMO.background.filter_name": filter_name }) opt = scopesim.OpticalTrain(cmd) for el in opt["micado_detector_array"]["detector_linearity"]: el.include = False for el in opt["micado_detector_array"]["full_detector_array"]: el.include = False # "armazones_atmo_dispersion" # not enabled anyway # "micado_adc_3D_shift" opt["detector_window"].include = True opt.update() # new_kwargs = {"rescale_emission": {"filter_name": filter_name, # "filename_format": "filters/TC_filter_{}.dat", # "value": bg_mag, # "unit": "mag"}} # opt["armazones_atmo_default_ter_curve"] = new_kwargs # TODO: is the below the same as the above? opt["armazones"].properties["background"]["filter_name"] = "J" opt.observe(src) hdus = opt.readout() # hdus[0][1].data = hdus[0][1].data[256:-256, 256:-256] # hdus[0].writeto(f"TEST_{filter_name}.fits", overwrite=True) image = hdus[0][1].data #[350:700, 300:700] pixel_scale = opt.cmds["!INST.pixel_scale"] xs = src.fields[0]["x"] / pixel_scale + image.shape[1] / 2 ys = src.fields[0]["y"] / pixel_scale + image.shape[1] / 2 if PLOTS: plt.imshow( image, #norm=LogNorm(), vmin=0.9999 * np.median(image), vmax=1.01 * np.median(image)) plt.show()
def test_star_field_with_spec(self): cmd = sim.UserCommands(use_instrument="MICADO_Sci", set_modes=["MCAO", "SPEC"]) opt = sim.OpticalTrain(cmd) src = sim.source.source_templates.star_field(100, 20, 30, 3, use_grid=True) opt.observe(src) if PLOTS: plt.imshow(opt.image_planes[0].image, norm=LogNorm()) plt.show()
def test_flux_scales_with_pixel_scale(self, filter_name, bg_level): yaml_text = YAML_TEXT % (WAVE_MIN, WAVE_MAX, PIXEL_SCALE, PIXEL_SCALE, filter_name) yamls = [yml for yml in yaml.full_load_all(yaml_text)] cmd = sim.UserCommands(yamls=yamls) opt = sim.OpticalTrain(cmd) opt.cmds["!TEL.area"] = 1 * u.m**2 src = empty_sky() opt.observe(src) img = opt.image_planes[0].data # Ks band photon flux is 1026 ph/s/m2/arcsec2 assert np.median(img) == pytest.approx(bg_level, rel=0.01)
def test_instrument_throughput_level_is_around_50_percent(self): cmd = sim.UserCommands(use_instrument="METIS", set_modes=["img_lm"]) metis = sim.OpticalTrain(cmd) for filter_name in ["Lp", "Mp"]: metis.cmds["!OBS.filter_name"] = filter_name wave = np.arange(3.4, 5.3, 0.001) * u.um sys_trans = metis.optics_manager.system_transmission(wave) print(np.average(sys_trans)) assert 0.4 < np.max(sys_trans) < 0.5 if PLOTS: plt.plot(wave, sys_trans) plt.show()
def test_sky_phs_with_full_system_transmission(self, filter_name, expected_phs): cmd = sim.UserCommands(use_instrument="METIS", set_modes=["img_lm"]) cmd["!OBS.filter_name"] = filter_name cmd["!ATMO.pwv"] = 1.0 cmd["!ATMO.airmass"] = 1.0 cmd["!ATMO.temperature"] = 258 metis = sim.OpticalTrain(cmd) metis['detector_linearity'].include = False sys_trans = metis.optics_manager.system_transmission phs = hmbp.in_skycalc_background(sys_trans) # ph/s/m2/[arcsec2] phs *= metis.cmds["!TEL.area"] * u.m**2 * \ metis.cmds["!INST.pixel_scale"] ** 2 assert phs.value == approx(expected_phs, rel=0.1) # ph/s/pixel
def test_print_background_contributions(self): cmd = sim.UserCommands(use_instrument="METIS", set_modes=["img_lm"]) metis = sim.OpticalTrain(cmd) metis["psf"].include = False metis.observe(empty_sky()) if PLOTS: plt.figure(figsize=(10, 5)) fov = metis.fov_manager.fovs[0] for field in fov.fields[1:]: spec = fov.spectra[field.header["SPEC_REF"]] wave = spec.waveset plt.plot(wave, spec(wave), label=field.header["BG_SURF"]) plt.legend() plt.show()
def inner_scao_zoom_bg_levels_are_similar_to_ETC(self, filt, bg, ph, rel): cmd = sim.UserCommands(use_instrument="MICADO_Sci", set_modes=["SCAO", "IMG_1.5mas"]) cmd["!OBS.dit"] = 1 cmd["!OBS.ndit"] = 1 cmd["!DET.width"] = 128 cmd["!DET.height"] = 128 cmd["!ATMO.background.value"] = bg cmd["!OBS.filter_name"] = filt cmd["!INST.psf.strehl"] = 0.6 opt = sim.OpticalTrain(cmd) src = sim.source.source_templates.empty_sky() opt.observe(src) sim_ph = np.average(opt.image_planes[0].image) print("Sim", sim_ph, "ETC", ph) assert sim_ph == approx(ph, rel=rel)
def test_basic_run_makes_image(self): src = star(flux=0) src = star_field(100, 0, 20, 10, use_grid=True) cmd = sim.UserCommands(use_instrument="METIS", set_modes=["img_lm"]) metis = sim.OpticalTrain(cmd) metis['detector_linearity'].include = False # metis['metis_psf_img'].include = False metis.observe(src) img = metis.image_planes[0].data hdus = metis.readout() img = hdus[0][1].data assert np.median(img) > 0 if not PLOTS: plt.imshow(img, norm=LogNorm()) plt.show()
def test_flux_scales_with_pixel_scale(self, pixel_scale): yaml_text = YAML_TEXT % (wave_min, wave_max, pixel_scale, pixel_scale, filter_name) yamls = [yml for yml in yaml.full_load_all(yaml_text)] cmd = sim.UserCommands(yamls=yamls) opt = sim.OpticalTrain(cmd) opt.cmds["!TEL.area"] = 1 * u.m**2 src = empty_sky() opt.observe(src) img = opt.image_planes[0].data # Ks band photon flux is 1014 ph/s/m2/arcsec2 assert np.median(img) == pytest.approx(1014 * pixel_scale**2, rel=0.01) if PLOTS: plt.imshow(img) plt.show()