Visualizzazione post con etichetta Emit. Mostra tutti i post
Visualizzazione post con etichetta Emit. Mostra tutti i post

lunedì 21 settembre 2026

USGS Tetracorder Docker

Non esistono metodi banali per installare Tetracorder (versione moderna) ma una versione comoda e' costituita da un docker non ufficiale

 


git clone https://github.com/jl-0/tetracorder-lite.git

cd tetracorder-lite

 prima di fare la build si deve modificare il file Containerfile aggiungendo la riga evidenziata in giallo

RUN cd tetracorder &&\
    sed -i "398,416 s/^/#/" AAA.INSTALL.spectroscopy-os-setup-linux.sh &&\
    sed -i "231,254 s/^/#/" AAA.INSTALL.spectroscopy-os-setup-linux.sh &&\
    yes "y" | bash AAA.INSTALL.spectroscopy-os-setup-linux.sh install &&\
    cd tetracorder &&\
    chmod +x checkmultmapcompilemode &&\
    make install &&\
    sed -i "137,140 s/^/#/" multmap.h &&\
    sed -i "144,147 s/^#//" multmap.h &&\
    make installsingle 

a questo punto si fa la build

docker build --platform linux/amd64 -f Containerfile -t tetracorder-lite . 

e si creano dei folder di lavoro

mkdir -p ~/tetracorder/input ~/tetracorder/output 

per controllare che tutto sia a posto si puo' lanciare 

docker run --rm tetracorder-lite tetrapy --help
docker run --rm tetracorder-lite tetrapy run --help

a questo punto siamo pronti a lanciare una prima elaborazione.Il problema e' che  Tetracorder accetta immagini in formato Envi mentre le immagini Emit sono distribuite in formato NetCDF (si devono scarivare sia i dati RFL di riflettanza che RFLUNCERT dell'incertezza della riflettanza

Per la conversione si possono le emit utilities 

git clone https://github.com/nasa/emit-utils.git
cd emit-utils
python emit_utils/reformat.py /path/to/EMIT_L2A_RFL_xxx.nc /path/to/output_envi/ --orthorectify 

funzionano ma non sono riuscito ad installare su Debian pip install xarray netCDF4 rioxarray earthaccess ovvero i modulo per orthorectify...si puo' fare a meno per questa prova

cd ~/emit-utils
python -m emit_utils.reformat ./emit_utils/EMIT_L2A_RFL_001_20260825T085423_2623706_045.nc /home/luca/tetracorder/input/ --orthorectify

arrivati a questo punto si puo' lanciare il processing  

docker run --rm \
  -v ~/tetracorder/input:/data \
  -v ~/tetracorder/output:/output \
  tetracorder-lite \
  tetrapy run config.yml \
    --data.rfl /data/EMIT_L2A_RFL_001_20260825T085423_2623706_045_reflectance \
    --data.rfluncert /data/EMIT_L2A_RFLUNCERT_001_20260825T085423_2623706_045_reflectance_uncertainty 

 

al termine del processing avremo una serie di file tipo la seguente dove

  • group.1um, group.1.5um-broad, group.2um, group.2um-broad — minerali (argille, carbonati, solfati, ecc., a seconda della banda di assorbimento)
  • group.ree, group.ree_g21, group.ree_samar — terre rare (rare earth elements)
  • group.ch4gas-2.3um, group.co2gas-2um — gas (metano, CO2)
  • group.veg — vegetazione
  • case.ep-cal-chl — epidoto/calcite/clorite
  • case.red-edge — red edge della vegetazione
  • case.veg.type — tipologia di vegetazione
  •   

    .
    ./test
    ./test/aggregate
    ./test/aggregate/agg.nc
    ./test/aggregate/config.yml
    ./test/aggregate/agg-uncert.nc
    ./test/aggregate/tetrapy.log
    ./test/tetracorder
    ./test/tetracorder/AAAA.license.txt
    ./test/tetracorder/group.1.5um-broad
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_vbroad_br20.fit.gz
    ./test/tetracorder/group.1.5um-broad/olivine_fo89_gds70.d.depth.gz
    ./test/tetracorder/group.1.5um-broad/snow-ice-10mm+0.3water-273k.depth.gz
    ./test/tetracorder/group.1.5um-broad/vegetation1.fit.gz
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.2water-273k.depth.gz
    ./test/tetracorder/group.1.5um-broad/water.high.chlorophyll2.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo18_ki3377.fd.gz
    ./test/tetracorder/group.1.5um-broad/water-20C-100cm-path+chlrph-a.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.1water-273k.fit.gz
    ./test/tetracorder/group.1.5um-broad/water+mont300gpl.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.2water-273k.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont50gpl.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo60_ki3189.fit.gz
    ./test/tetracorder/group.1.5um-broad/water-20C-300cm-path+chlrph-g.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont0.5gpl.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow.melting16+0.5veg.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/anorthite_hs201.3b.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water-20C-100cm-path+chlrph-a.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water-20C-10cm-path-model.depth.gz
    ./test/tetracorder/group.1.5um-broad/water-20C-100cm-path-model.fit.gz
    ./test/tetracorder/group.1.5um-broad/snow.melting.8.fd.gz
    ./test/tetracorder/group.1.5um-broad/snow-ice-10mm-273k.fd.gz
    ./test/tetracorder/group.1.5um-broad/snow.slush.9.depth.gz
    ./test/tetracorder/group.1.5um-broad/water+mont0.5gpl.fd.gz
    ./test/tetracorder/group.1.5um-broad/olivine_fo66_ki3054.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo60_ki3189.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_brd.br22c_actinolite.fit.gz
    ./test/tetracorder/group.1.5um-broad/vegetation1.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont50gpl+0.5veg.fit.gz
    ./test/tetracorder/group.1.5um-broad/water-20C-30cm-path-model.fit.gz
    ./test/tetracorder/group.1.5um-broad/anorthite_hs201.3b.fd.gz
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.3water-273k.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.1water-273k.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/rutile_hs126.3b.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.1water-273k.fd.gz
    ./test/tetracorder/group.1.5um-broad/water-20C-30cm-path-model.depth.gz
    ./test/tetracorder/group.1.5um-broad/snow.melting16+0.5veg.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_nrw.cummingtonite.fd.gz
    ./test/tetracorder/group.1.5um-broad/vegetation.dry+green.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water-20C-300cm-path+chlrph-g.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo66_ki3054.depth.gz
    ./test/tetracorder/group.1.5um-broad/snow-ice-1mm-273k.fd.gz
    ./test/tetracorder/group.1.5um-broad/water+mont16.5gpl.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_chlorite.clinochlor.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm-273k.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_vbroad_br20.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water-20C-100cm-path+chlrph-g.fit.gz
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.3water-273k.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/microcline_hs103.3b.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-1mm-273k.depth.gz
    ./test/tetracorder/group.1.5um-broad/snow.slush.9.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/bytownite_hs106.3b.depth.gz
    ./test/tetracorder/group.1.5um-broad/water-20C-10cm-path+chlrph-g.depth.gz
    ./test/tetracorder/group.1.5um-broad/organic_dry_long_grass-thick.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water-20C-30cm-path-model.fd.gz
    ./test/tetracorder/group.1.5um-broad/water+mont50gpl+0.5veg.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/vegetation.dry+green.fd.gz
    ./test/tetracorder/group.1.5um-broad/water.turquoise-shallow.fd.gz
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_chlor+muscphy.fit.gz
    ./test/tetracorder/group.1.5um-broad/water-20C-100cm-path+chlrph-a.fit.gz
    ./test/tetracorder/group.1.5um-broad/water.high.chlorophyll2.fit.gz
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.1water-273k.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont50gpl.fd.gz
    ./test/tetracorder/group.1.5um-broad/bytownite_hs106.3b.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/sphalerite_s26-341_1.5um.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/anorthite_hs201.3b.fit.gz
    ./test/tetracorder/group.1.5um-broad/water+mont5.01gpl.fd.gz
    ./test/tetracorder/group.1.5um-broad/snow.melting.1a.depth.gz
    ./test/tetracorder/group.1.5um-broad/water+mont100gpl.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-10mm+0.3water-273k.fit.gz
    ./test/tetracorder/group.1.5um-broad/snow.melting.8.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo18_ki3377.depth.gz
    ./test/tetracorder/group.1.5um-broad/snow.slush.9.fit.gz
    ./test/tetracorder/group.1.5um-broad/rutile_hs126.3b.depth.gz
    ./test/tetracorder/group.1.5um-broad/vegetation.dry+green.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/sphalerite_s26-341_1.5um.fit.gz
    ./test/tetracorder/group.1.5um-broad/olivine_fo89_gds70.a.fit.gz
    ./test/tetracorder/group.1.5um-broad/anorthite_hs201.3b.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow.melting.3.depth.gz
    ./test/tetracorder/group.1.5um-broad/snow.melting.1a.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont16.5gpl.depth.gz
    ./test/tetracorder/group.1.5um-broad/snow.melting.3.fit.gz
    ./test/tetracorder/group.1.5um-broad/water+mont5.01gpl.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/organic_dry_long_grass-thick.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.3water-273k.fd.gz
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_brd.br5a_actinolite.fit.gz
    ./test/tetracorder/group.1.5um-broad/rutile_hs126.3b.fit.gz
    ./test/tetracorder/group.1.5um-broad/water.low.chlorophyll-blue1.depth.gz
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.3water-273k.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/organic_white_pvc_pipe.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_chlor+muscphy.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo91_gds71.b.fd.gz
    ./test/tetracorder/group.1.5um-broad/snow.slush.16.fit.gz
    ./test/tetracorder/group.1.5um-broad/olivine_fo89_gds70.d.fit.gz
    ./test/tetracorder/group.1.5um-broad/snow.and.ice-170k.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water-20C-100cm-path+chlrph-g.fd.gz
    ./test/tetracorder/group.1.5um-broad/water.low.chlorophyll-blue1.fd.gz
    ./test/tetracorder/group.1.5um-broad/snow.slush.16.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow.slush.16.depth.gz
    ./test/tetracorder/group.1.5um-broad/snow.melting9+0.5veg.fd.gz
    ./test/tetracorder/group.1.5um-broad/water-20C-100cm-path+chlrph-a.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo66_ki3054.fd.gz
    ./test/tetracorder/group.1.5um-broad/water+mont100gpl+0.5veg.depth.gz
    ./test/tetracorder/group.1.5um-broad/sphalerite_s26-341_1.5um.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow.melting9+0.5veg.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/organic_green_plastic_tarp.fit.gz
    ./test/tetracorder/group.1.5um-broad/vegetation.dry+green.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-10mm+0.3water-273k.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm-273k.depth.gz
    ./test/tetracorder/group.1.5um-broad/snow.and.ice-248k.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_brd.br5a_actinolite.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_brd.br5a_actinolite.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont16.5gpl.fd.gz
    ./test/tetracorder/group.1.5um-broad/water+mont100gpl.fd.gz
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_vbroad_br20.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water-20C-30cm-path-model.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo18_ki3377.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/rutile_hs126.3b.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_nrw.cummingtonite.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_vbroad_br20.depth.gz
    ./test/tetracorder/group.1.5um-broad/snow.melting.8.fit.gz
    ./test/tetracorder/group.1.5um-broad/water.low.chlorophyll.fit.gz
    ./test/tetracorder/group.1.5um-broad/water.turquoise-shallow.fit.gz
    ./test/tetracorder/group.1.5um-broad/olivine_fo80_hs285.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo89_gds70.c.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow.melting9+0.5veg.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont1.67gpl.fd.gz
    ./test/tetracorder/group.1.5um-broad/water+mont5.01gpl.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow.melting16+0.5veg.fit.gz
    ./test/tetracorder/group.1.5um-broad/water+mont1.67gpl.fit.gz
    ./test/tetracorder/group.1.5um-broad/water.red.algae.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont1.67gpl.depth.gz
    ./test/tetracorder/group.1.5um-broad/water-20C-100cm-path+chlrph-g.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.2water-273k.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo66_ki3054.fit.gz
    ./test/tetracorder/group.1.5um-broad/water.high.chlorophyll.fd.gz
    ./test/tetracorder/group.1.5um-broad/water+mont0.5gpl.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/magnetite_hs195.3b.or.olivine.fd.gz
    ./test/tetracorder/group.1.5um-broad/water-20C-300cm-path+chlrph-g.fd.gz
    ./test/tetracorder/group.1.5um-broad/water+mont100gpl.fit.gz
    ./test/tetracorder/group.1.5um-broad/snow.melting.1a.fd.gz
    ./test/tetracorder/group.1.5um-broad/water.low.chlorophyll-blue1.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo18_ki3377.fit.gz
    ./test/tetracorder/group.1.5um-broad/olivine_fo60_ki3189.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/magnetite_hs195.3b.or.olivine.fit.gz
    ./test/tetracorder/group.1.5um-broad/olivine_fo18_ki3377.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont100gpl+0.5veg.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_chlorite.clinochlor.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont100gpl.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_nrw.cummingtonite.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow.slush.16.fd.gz
    ./test/tetracorder/group.1.5um-broad/water.high.chlorophyll.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-10mm+0.3water-273k.fd.gz
    ./test/tetracorder/group.1.5um-broad/organic_green_plastic_tarp.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont0.5gpl.fit.gz
    ./test/tetracorder/group.1.5um-broad/olivine_fo91_gds71.b.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont50gpl.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow.and.ice-248k.depth.gz
    ./test/tetracorder/group.1.5um-broad/organic_green_plastic_tarp.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/bytownite_hs106.3b.fd.gz
    ./test/tetracorder/group.1.5um-broad/olivine_fo80_hs285.fit.gz
    ./test/tetracorder/group.1.5um-broad/water.high.chlorophyll2.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water-20C-300cm-path+chlrph-g.depth.gz
    ./test/tetracorder/group.1.5um-broad/vegetation1.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_nrw.cummingtonite.fit.gz
    ./test/tetracorder/group.1.5um-broad/olivine_fo80_hs285.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water.red.algae.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow.slush.9.fd.gz
    ./test/tetracorder/group.1.5um-broad/water+mont1.67gpl.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.1water-273k.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water.turquoise-shallow.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow.and.ice-170k.depth.gz
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_chlor+muscphy.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/vegetation.dry+green.fit.gz
    ./test/tetracorder/group.1.5um-broad/water+mont300gpl.fit.gz
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.2water-273k.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/sphalerite_s26-341_1.5um.fd.gz
    ./test/tetracorder/group.1.5um-broad/snow.melting.8.depth.gz
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_chlor+muscphy.fd.gz
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_brd.br22c_actinolite.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont50gpl.fit.gz
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_chlor+muscphy.depth.gz
    ./test/tetracorder/group.1.5um-broad/bytownite_hs106.3b.fit.gz
    ./test/tetracorder/group.1.5um-broad/water.low.chlorophyll.fd.gz
    ./test/tetracorder/group.1.5um-broad/magnetite_hs195.3b.or.olivine.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-10mm-273k.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water-20C-10cm-path-model.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water-20C-100cm-path-model.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water.turquoise-shallow.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water.low.chlorophyll.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-10mm-273k.fit.gz
    ./test/tetracorder/group.1.5um-broad/water-20C-100cm-path-model.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water.low.chlorophyll-turquoise.depth.gz
    ./test/tetracorder/group.1.5um-broad/water.red.algae.fd.gz
    ./test/tetracorder/group.1.5um-broad/olivine_fo89_gds70.d.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/snow-ice-3mm+0.3water-273k.depth.gz
    ./test/tetracorder/group.1.5um-broad/water+mont100gpl+0.5veg.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water.red.algae.fit.gz
    ./test/tetracorder/group.1.5um-broad/water.high.chlorophyll.depth.gz
    ./test/tetracorder/group.1.5um-broad/organic_white_pvc_pipe.fd.gz
    ./test/tetracorder/group.1.5um-broad/olivine_fo89_gds70.a.fd.gz
    ./test/tetracorder/group.1.5um-broad/water-20C-100cm-path+chlrph-a.fd.gz
    ./test/tetracorder/group.1.5um-broad/snow-ice-10mm-273k.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_vbroad_br20.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo89_gds70.c.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo89_gds70.d.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/anorthite_hs201.3b.depth.gz
    ./test/tetracorder/group.1.5um-broad/water.turquoise-shallow.depth.gz
    ./test/tetracorder/group.1.5um-broad/snow.melting.1a.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_brd.br5a_actinolite.fd.gz
    ./test/tetracorder/group.1.5um-broad/olivine_fo91_gds71.b.depth.gz
    ./test/tetracorder/group.1.5um-broad/microcline_hs103.3b.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/organic_white_pvc_pipe.depth.gz
    ./test/tetracorder/group.1.5um-broad/rutile_hs126.3b.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water-20C-100cm-path+chlrph-a.depth.gz
    ./test/tetracorder/group.1.5um-broad/snow.and.ice-170k.fd.gz
    ./test/tetracorder/group.1.5um-broad/water.turquoise-shallow.fd.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo89_gds70.d.fit.gz.hdr
    ./test/tetracorder/group.1.5um-broad/g4-fe2+generic_brd.br22c_actinolite.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/olivine_fo89_gds70.c.depth.gz
    ./test/tetracorder/group.1.5um-broad/water+mont300gpl.depth.gz.hdr
    ./test/tetracorder/group.1.5um-broad/water+mont0.5gpl.depth.gz

     

    rimane il problema della visualizzazione  

    mkdir -p ~/tetracorder_out
    python tetracorder_iron_oxides.py \
        --group-dir group.2um \
        --filter "kaolgrp_|kaol|smectite_|micagrp_illite|micagrp_vermiculite|chlorite|palygorskite|sepiolite|saponite|hectorite|dickite|nacrite|halloysite|pyroph" \
        --output ~/tetracorder_out/argille_map.png \
        --geotiff ~/tetracorder_out/argille_map.tif \
        --title "Minerali argillosi" 

     

    #!/usr/bin/env python3
    """
    tetracorder_visualize.py
    =========================

    Visualizza una mappa di classificazione prodotta da USGS Tetracorder
    (es. results.cluster, results.cluster.sorted, results.group.X, ...)
    colorando ogni classe secondo il file color.keys prodotto dallo stesso run,
    e generando una legenda con i nomi dei materiali.

    USO
    ---
    python tetracorder_visualize.py \
    --cluster /path/results.cluster.sorted \
    --colorkeys /path/color.keys \
    --output mappa_materiali.png

    Se il file .hdr (ENVI) ha lo stesso nome + ".hdr" o si chiama
    "<cluster>.hdr", viene individuato automaticamente. In alternativa
    si può passare esplicitamente con --hdr.

    DIPENDENZE
    ----------
    pip install numpy matplotlib
    # opzionale ma consigliato (lettura ENVI con georeferenziazione):
    pip install rasterio

    NOTE SUL PARSING DI color.keys
    -------------------------------
    Il formato del file color.keys di Tetracorder non è uno standard fisso:
    varia leggermente tra versioni. Questo script prova diversi pattern
    comuni (vedi funzione `parse_color_keys`). Se il parsing fallisce o i
    colori/nomi non tornano, lancia lo script con --debug-colorkeys per
    vedere riga per riga cosa viene interpretato, e poi mandami un estratto
    delle prime ~10 righe del tuo file color.keys così affino il parser.
    """

    import argparse
    import re
    import sys
    from pathlib import Path

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.colors import ListedColormap, BoundaryNorm
    from matplotlib.patches import Patch


    # --------------------------------------------------------------------------
    # Lettura immagine ENVI (results.cluster, results.group.X, ecc.)
    # --------------------------------------------------------------------------

    def find_hdr(cluster_path: Path) -> Path:
    """Cerca l'header ENVI associato al file dati."""
    candidates = [
    cluster_path.with_suffix(cluster_path.suffix + ".hdr"),
    cluster_path.with_suffix(".hdr"),
    Path(str(cluster_path) + ".hdr"),
    ]
    for c in candidates:
    if c.exists():
    return c
    raise FileNotFoundError(
    f"Nessun file .hdr trovato per {cluster_path}. "
    f"Passalo esplicitamente con --hdr."
    )


    def parse_envi_hdr(hdr_path: Path) -> dict:
    """Parser minimale di un header ENVI (testo chiave=valore)."""
    text = hdr_path.read_text(errors="ignore")
    info = {}
    for key in ("samples", "lines", "bands", "data type",
    "interleave", "byte order", "header offset"):
    m = re.search(rf"{key}\s*=\s*(\S+)", text, re.IGNORECASE)
    if m:
    info[key.replace(" ", "_")] = m.group(1)
    required = ("samples", "lines", "data_type")
    missing = [k for k in required if k not in info]
    if missing:
    raise ValueError(f"Header ENVI incompleto, mancano: {missing}")
    return info


    ENVI_DTYPES = {
    "1": np.uint8, "2": np.int16, "3": np.int32, "4": np.float32,
    "5": np.float64, "6": np.complex64, "9": np.complex128,
    "12": np.uint16, "13": np.uint32, "14": np.int64, "15": np.uint64,
    }


    def read_envi_raw(data_path: Path, hdr: dict) -> np.ndarray:
    """Legge un raster ENVI senza dipendenze esterne (fallback)."""
    samples = int(hdr["samples"])
    lines = int(hdr["lines"])
    bands = int(hdr.get("bands", 1))
    dtype = ENVI_DTYPES.get(hdr.get("data_type", "2"), np.int16)
    offset = int(hdr.get("header_offset", 0))
    byte_order = hdr.get("byte_order", "0")
    interleave = hdr.get("interleave", "bsq").lower()

    arr = np.fromfile(data_path, dtype=dtype, offset=offset)
    expected = samples * lines * bands
    arr = arr[:expected]
    if byte_order == "1": # big-endian
    arr = arr.byteswap().newbyteorder()

    if interleave == "bsq":
    arr = arr.reshape(bands, lines, samples)
    elif interleave == "bil":
    arr = arr.reshape(lines, bands, samples).transpose(1, 0, 2)
    elif interleave == "bip":
    arr = arr.reshape(lines, samples, bands).transpose(2, 0, 1)
    else:
    raise ValueError(f"Interleave ENVI non riconosciuto: {interleave}")

    return arr[0] if bands == 1 else arr


    def load_cluster_map(cluster_path: Path, hdr_path: Path | None) -> np.ndarray:
    """Carica la mappa raster, usando rasterio se disponibile."""
    try:
    import rasterio
    with rasterio.open(cluster_path) as src:
    return src.read(1)
    except Exception:
    pass # fallback manuale

    if hdr_path is None:
    hdr_path = find_hdr(cluster_path)
    hdr = parse_envi_hdr(hdr_path)
    band = read_envi_raw(cluster_path, hdr)
    if band.ndim == 3:
    band = band[0]
    return band


    # --------------------------------------------------------------------------
    # Metadati di classificazione incorporati nell'header ENVI
    # (class names / class lookup) - spesso è qui, non in un color.keys esterno
    # --------------------------------------------------------------------------

    def parse_envi_classification(hdr_path: Path) -> dict | None:
    """
    Cerca nel .hdr i campi ENVI standard:
    class names = {Unclassified, Kaolinite, Goethite, ...}
    class lookup = {0,0,0, 255,0,0, 200,120,0, ...}
    e ritorna {id: (r,g,b,nome)} se presenti, altrimenti None.
    """
    text = hdr_path.read_text(errors="ignore")

    def extract_braced(field):
    m = re.search(rf"{field}\s*=\s*\{{([^}}]*)\}}", text,
    re.IGNORECASE | re.DOTALL)
    return m.group(1) if m else None

    names_raw = extract_braced("class names")
    lookup_raw = extract_braced("class lookup")
    if not names_raw or not lookup_raw:
    return None

    names = [n.strip() for n in names_raw.split(",") if n.strip()]
    nums = [int(x) for x in re.findall(r"-?\d+", lookup_raw)]
    if len(nums) < len(names) * 3:
    return None

    result = {}
    for i, name in enumerate(names):
    r, g, b = nums[i * 3], nums[i * 3 + 1], nums[i * 3 + 2]
    result[i] = (r, g, b, name)
    return result


    # --------------------------------------------------------------------------
    # Parsing color.keys (file di testo esterno, se lo trovi separatamente)
    # --------------------------------------------------------------------------

    def parse_color_keys(path: Path, debug: bool = False) -> dict:
    """
    Ritorna {id_materiale: (r, g, b, nome)}.

    Prova più pattern, perché il formato varia tra run Tetracorder:
    1) " 12 255 128 0 Kaolinite_CM9.spc"
    2) "12 Kaolinite_CM9 R=255 G=128 B=0"
    3. CSV-like: "12,255,128,0,Kaolinite"
    """
    patterns = [
    re.compile(r"^\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\S.*)$"),
    re.compile(r"^\s*(\d+)\s+(\S+).*?R\s*=?\s*(\d+).*?G\s*=?\s*(\d+).*?B\s*=?\s*(\d+)", re.IGNORECASE),
    re.compile(r"^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\S.*)$"),
    ]

    result = {}
    unmatched = []
    for raw_line in path.read_text(errors="ignore").splitlines():
    line = raw_line.strip()
    if not line or line.startswith("#") or line.startswith(";"):
    continue

    m = patterns[0].match(line)
    if m:
    idx, r, g, b, name = m.groups()
    result[int(idx)] = (int(r), int(g), int(b), name.strip())
    continue

    m = patterns[1].match(line)
    if m:
    idx, name, r, g, b = m.groups()
    result[int(idx)] = (int(r), int(g), int(b), name.strip())
    continue

    m = patterns[2].match(line)
    if m:
    idx, r, g, b, name = m.groups()
    result[int(idx)] = (int(r), int(g), int(b), name.strip())
    continue

    unmatched.append(raw_line)

    if debug:
    print(f"[debug] {len(result)} voci interpretate, "
    f"{len(unmatched)} righe non riconosciute.")
    for u in unmatched[:15]:
    print(" ??", u)

    if not result:
    raise ValueError(
    "Nessuna riga di color.keys è stata interpretata. "
    "Rilancia con --debug-colorkeys e mandami le prime righe del file "
    "cosi' adatto il parser al formato esatto."
    )
    return result


    # --------------------------------------------------------------------------
    # Plot
    # --------------------------------------------------------------------------

    def plot_classification(class_map: np.ndarray, color_keys: dict,
    output: Path, title: str, max_legend_items: int = 40):
    present_ids = sorted(i for i in np.unique(class_map) if i != 0 and i in color_keys)

    if not present_ids:
    print("Attenzione: nessun ID presente nella mappa ha una corrispondenza "
    "in color.keys. Controlla che i due file provengano dallo stesso run.")

    # id 0 = nessun match -> sfondo grigio chiaro
    ids = [0] + present_ids
    colors = [(0.92, 0.92, 0.92)]
    labels = ["(nessun match)"]
    for i in present_ids:
    r, g, b, name = color_keys[i]
    colors.append((r / 255, g / 255, b / 255))
    labels.append(f"{i}: {name}")

    cmap = ListedColormap(colors)
    bounds = ids + [ids[-1] + 1]
    norm = BoundaryNorm(bounds, cmap.N)

    remap = np.zeros_like(class_map, dtype=np.int32)
    for new_i, orig_i in enumerate(ids):
    remap[class_map == orig_i] = new_i

    fig, ax = plt.subplots(figsize=(10, 8))
    ax.imshow(remap, cmap=ListedColormap(colors), interpolation="nearest")
    ax.set_title(title)
    ax.set_xticks([])
    ax.set_yticks([])

    legend_ids = present_ids[:max_legend_items]
    handles = [Patch(facecolor=(color_keys[i][0] / 255,
    color_keys[i][1] / 255,
    color_keys[i][2] / 255),
    label=f"{color_keys[i][3]}")
    for i in legend_ids]
    if len(present_ids) > max_legend_items:
    handles.append(Patch(facecolor="white",
    label=f"... +{len(present_ids) - max_legend_items} altri"))

    ax.legend(handles=handles, bbox_to_anchor=(1.02, 1), loc="upper left",
    fontsize=7, frameon=False, ncol=1)

    fig.tight_layout()
    fig.savefig(output, dpi=200, bbox_inches="tight")
    print(f"Salvato: {output} ({len(present_ids)} materiali distinti trovati)")


    # --------------------------------------------------------------------------
    # Main
    # --------------------------------------------------------------------------

    def main():
    p = argparse.ArgumentParser(description=__doc__,
    formatter_class=argparse.RawDescriptionHelpFormatter)
    p.add_argument("--cluster", required=True, type=Path,
    help="File risultati (es. results.cluster.sorted)")
    p.add_argument("--hdr", type=Path, default=None,
    help="Header ENVI (.hdr), se non individuabile automaticamente")
    p.add_argument("--colorkeys", required=False, type=Path, default=None,
    help="File color.keys testuale (opzionale: se assente, "
    "lo script cerca 'class names'/'class lookup' "
    "direttamente nell'header ENVI del raster)")
    p.add_argument("--output", type=Path, default=Path("tetracorder_map.png"),
    help="File immagine di output (default: tetracorder_map.png)")
    p.add_argument("--title", default="Classificazione Tetracorder")
    p.add_argument("--debug-colorkeys", action="store_true",
    help="Stampa il dettaglio del parsing di color.keys")
    args = p.parse_args()

    class_map = load_cluster_map(args.cluster, args.hdr)

    color_keys = None
    hdr_path = args.hdr or find_hdr(args.cluster)
    if hdr_path.exists():
    color_keys = parse_envi_classification(hdr_path)
    if color_keys:
    print(f"Trovate {len(color_keys)} classi nei metadati ENVI "
    f"dell'header ({hdr_path.name}).")

    if color_keys is None:
    if args.colorkeys is None:
    print("Nessuna classificazione trovata nell'header ENVI e "
    "nessun --colorkeys fornito. Passa un file color.keys "
    "testuale con --colorkeys, oppure mandami un estratto "
    "del .hdr per capire dove sta l'informazione colore/nome.",
    file=sys.stderr)
    sys.exit(1)
    color_keys = parse_color_keys(args.colorkeys, debug=args.debug_colorkeys)

    plot_classification(class_map, color_keys, args.output, args.title)


    if __name__ == "__main__":
    sys.exit(main())


     

     

     

    domenica 1 marzo 2026

    Emit L3 ASA

    Il prodotto Emit L3 ASA (scaricabile da qui) corrisponde all'unmixing mineralogico dei dati ipespettrali di Emit. La copertura e' a livello mondiale tra le latitudini 55N/-54.5S ed una risoluzione spaziale di mezzo grado decimale (circa 55 km) con specializzazione su suoli aridi (i dati sono mascherati per la vegetazione)

    Vengono calcolate 10 categorie mineralogiche  

    Il prodotto e' nato per polveri e non per suoli. Per indagini mineralogiche di suoli e' piu' affidale il prodotto L2B a cui pero' si deve effettuare in proprio l'unmixing spettrale 

      


     

    sabato 28 febbraio 2026

    Conversione Emit L2A in Envi

    Attenzione : la struttura dei file netcdf ha subito una variazione intorno al 2025 

    Da EarthData si possono scaricare i dati  

    https://search.earthdata.nasa.gov/search/granules?p=C2408750690-LPCLOUD

    https://earth.jpl.nasa.gov/emit/data/data-portal/coverage-and-forecasts/ 

    Piccola nota: bande Emit per true color

    Red: ~650 nm → Band 29
    Green: ~550 nm → Band 19
    Blue: ~460 nm → Band 11


    i dati sono in formato netcfd ma non risulta georiferito , si apre tranquillamente in Esa Snap ma la cosa migliore e' trasformarlo in formato Envi per avere tutte le informazioni spettrali

     

    In fondo alla pagina lo script per effettuare l'operazione..attenzione che a seconda che l'orbita sia discendente od ascendente si deve ruotare la matrice di 90 grafi  

    Il file viene georiferito nel senso che ogni pixel ha le sue coordinate ma l'immagine non e' ruotata come dovrebbe essere


     

    https://github.com/nasa/EMIT-Data-Resources 

    import xarray as xr
    import numpy as np
    import rasterio
    from rasterio.transform import from_origin

    ds = xr.open_dataset('grosseto2.nc', engine='netcdf4')
    ds_bands = xr.open_dataset('grosseto2.nc', engine='netcdf4', group='sensor_band_parameters')
    wavelengths = ds_bands['wavelengths'].values
    fwhm = ds_bands['fwhm'].values

    gt = ds.attrs['geotransform']
    reflectance = ds['reflectance'].values
    data = np.transpose(reflectance, (2, 0, 1))
    data = np.rot90(data, k=1, axes=(1, 2))

    nrows, ncols = data.shape[1], data.shape[2]
    nbands = data.shape[0]

    transform = from_origin(gt[0], gt[3], gt[1], abs(gt[5]))

    with rasterio.open(
    'grosseto2.envi', 'w',
    driver='ENVI',
    height=nrows, width=ncols,
    count=nbands,
    dtype=data.dtype,
    crs='EPSG:4326',
    transform=transform,
    ) as dst:
    dst.write(data)

    # Rewrite the entire .hdr cleanly
    with open('grosseto2.hdr', 'w') as hdr:
    hdr.write('ENVI\n')
    hdr.write('description = { EMIT L2A Reflectance - Grosseto }\n')
    hdr.write(f'samples = {ncols}\n')
    hdr.write(f'lines = {nrows}\n')
    hdr.write(f'bands = {nbands}\n')
    hdr.write('header offset = 0\n')
    hdr.write('file type = ENVI Standard\n')
    hdr.write('data type = 4\n')
    hdr.write('interleave = bsq\n')
    hdr.write('byte order = 0\n')
    hdr.write(f'map info = {{Geographic Lat/Lon, 1, 1, {gt[0]}, {gt[3]}, {gt[1]}, {abs(gt[5])}, WGS-84}}\n')
    hdr.write('wavelength units = Nanometers\n')
    hdr.write('wavelength = {\n')
    hdr.write(',\n'.join(f' {w:.6f}' for w in wavelengths))
    hdr.write('}\n')
    hdr.write('fwhm = {\n')
    hdr.write(',\n'.join(f' {f:.6f}' for f in fwhm))
    hdr.write('}\n')
    hdr.write('band names = {\n')
    hdr.write(',\n'.join(f' Band_{i+1}_{w:.2f}nm' for i, w in enumerate(wavelengths)))
    hdr.write('}\n')

    print(f"Done! {nbands} bands, {wavelengths[0]:.2f}-{wavelengths[-1]:.2f} nm")



     

     

    Microsoft office a dischetti

     Una nuova acquisizione per il mio piccolo museo dell'informatica. Microsoft Office ed Acces con installazione a dischetti