Un breve riassunto degli indici utilizzati in Ensomap all'interno del plugin Enmap toolbox di QGis
Carbonate
1) assorbimento dopo rimozione del continuo a 2300-2400 nm
Clay
Iron
Materia Organica
Soil Moisture
Gesso
1) (R1690-R1750)/(R1690+R1750)
Un breve riassunto degli indici utilizzati in Ensomap all'interno del plugin Enmap toolbox di QGis
Carbonate
1) assorbimento dopo rimozione del continuo a 2300-2400 nm
Clay
Iron
Materia Organica
Soil Moisture
Gesso
1) (R1690-R1750)/(R1690+R1750)
Ultimamente ho incasinato la Debian box e mi compare questo errore aprendo QGis...dopo funziona ma non disponibili i plugin
la soluzione e' settare in modo esplicito la PythoPath
PYTHONPATH=/usr/lib/python3/dist-packages:$PYTHONPATH
qgis
Un tentativo di quantificare rifiuti su una spiaggia toscana
L'idea e'
1) fotografare
2) incollare le immagini (possibilmente georiferite)
3) tagliare in quadrati di 1mx1m
4) istruire una rete neurale con Yolo 8 su un sottoinsieme dei quadrati al punto 3
Le immagini di partenza sono di questo tipo (si avrei dovuto portarmi uno stick per non fotografarmi di continuo i piedi), in sequenza scattate in automatico ogni secondo
Il primo dataset sono immagini da drone
Le immagini sono state incollate (stitching) con WebOdm
Come si legge il GCD e' di 0.92..io voglio tagliare il geotiff in quadrati di 1x1 tramite GDAL...per ottenere il valore del parametro ps calcolo 100 cm /0.92 cm (GCD) ed ottendo 109 (non vengono accettati valori float)gdal_retile.py -ps 109 109 -targetDir ./ritagli_drone/ ortophoto_drone.tif
Usando invece foto fatte a mano dal cellulare (quindi altezza indicativa di 140 cm) si ha un GCD di 0.12
gdal_retile.py -ps 833 833 -targetDir ./ritagli_samsung/ ortophoto_samsung.tif
una volta effettuato il taglio si hanno immagini di questo tipo (la distorsione e' derivante dall'algoritmo di ODM)
che devono essere classificate per istruire la rete neurale
Di solito uso labelImg ma ho visto che nella versione nuova di Debian crasha a causa delle Qt6...intanto trasformiamo i tiff in jpg perche' labelimg non supporta tiff
mogrify -format jpg -quality 90 -colorspace sRGB -flatten *.tif
e poi lanciamo questo docker container per non impazzire con l'installazione
docker run -ti --rm -e DISPLAY=$DISPLAY --device=/dev/video0:/dev/video0 -v /tmp/.X11-unix:/tmp/.X11-unix -v /home/luca/:/home/luca -w /home/luca ludwigprager/labelimg:1
dopo aver definito le classi e gli oggetti all'interno delle immagini si passa ad addestrare il modello facendo un retrain di Yolo
i dati sono nel folder /home/luca/images/1, al di sotto ci sono i folders ./train/images,./train/labels,./val/images,./val/labels
il file data.yaml deve essere in /home/luca/images/1
--------------------
train: /ultralytics/my_data/train/images
val: /ultralytics/my_data/val/images
nc: 3
names: ['waste', 'alga', 'wood']
--------------------
ancora la cosa piu' semplice e' un docker per addestrare la rete (size 833 e' la dimensione in pixels di ogni mattonella di 1 m)
docker run -it --rm \
--ipc=host \
-v "/home/luca/images/1":/ultralytics/my_data \
ultralytics/ultralytics:latest-cpu \
yolo train \
model=yolov8n.pt \
data=/ultralytics/my_data/data.yaml \
epochs=50 \
imgsz=833 \
device=cpu \
project=/ultralytics/my_data/runs
i risultati sono pessimi principalmente a causa del dataset ristretto ma dal punto di vista software tutto ha funzionato
se, dopo aver fatto il modello, si vuole fare inferenza questo e' il comando
docker run -it --rm \
-v "/home/luca/images/1":/ultralytics/my_data \
ultralytics/ultralytics:latest-cpu \
yolo predict \
model=/ultralytics/my_data/runs/train/weights/best.pt \
source=/ultralytics/my_data/train/images/ortophoto_samsung_04_03.jpg \
project=/ultralytics/my_data/predictions \
save=True
Questa e' una estensione di questo post usando come parametro indice NRDE al posto di NDVI. Questo indice puo'essere calcolato per Sentinel 2 ma non per Landsat e per questo motivo la serie storica e' ridotta ad un decennio
NRDE = (NIR-RedEdge)/(Nir+RedEdge)
// 1. Coordinate e Geometria
var lon = 10.926468160041452;
var lat = 43.01919548868449;
var poi = ee.Geometry.Point([lon, lat]);
// 2. Funzione di pre-elaborazione per Sentinel-2
function preprocessSentinel2(image) {
var qa = image.select('QA60');
// Maschera per nuvole e cirri
var cloudBitMask = 1 << 10;
var cirrusBitMask = 1 << 11;
var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
.and(qa.bitwiseAnd(cirrusBitMask).eq(0));
// Scaling (Sentinel-2 Surface Reflectance)
var opticalBands = image.divide(10000);
// Calcolo NDRE
// NIR = B8, Red Edge = B5 (prima banda red-edge di Sentinel-2)
var ndre = opticalBands.normalizedDifference(['B8', 'B5']).rename('NDRE');
return image.addBands(ndre).updateMask(mask);
}
// 3. Caricamento Collezione Sentinel-2 (Disponibile dal 2015/2017)
var s2Col = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED")
.filterBounds(poi)
.filterDate('2017-01-01', '2026-01-01') // Sentinel-2 SR data standard
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))
.map(preprocessSentinel2);
// 4. Creazione del Grafico Temporale
var chart = ui.Chart.image.series({
imageCollection: s2Col.select('NDRE'),
region: poi,
reducer: ee.Reducer.mean(),
scale: 20, // Sentinel-2 Red Edge è a 20m
xProperty: 'system:time_start'
})
.setOptions({
title: 'Serie Storica NDRE: Sentinel-2 (2017-2026)',
vAxis: {title: 'NDRE', viewWindow: {min: -0.1, max: 1}},
hAxis: {title: 'Anno', format: 'YYYY'},
lineWidth: 1,
pointSize: 2,
trendlines: {0: {color: 'blue', lineWidth: 1, opacity: 0.7}},
series: {
0: {color: '006400'} // Verde scuro
}
});
// 5. Visualizzazione
print(chart);
Map.centerObject(poi, 13);
Map.addLayer(poi, {color: 'red'}, 'Sito di analisi');
In "Fundamental of geological and environmental remote sensing R.K.Vincent, Prentice Hall (1997)" cap 7 viene indicato che lo spostamento del Red Edge della vegetazione puo' essere un indicatore diagnostico per il tipo di mineralogia del suolo quando questo non possa essere visibile a causa della copertura vegetale
![]() |
| pag 197 del libro |
Questo spostamento e' indicativamente verso il blu per zone a maggiore mineralizzazione (anche se puo' accadere l'opposto)
![]() |
| Gavorrano |
Ho provato con lo script sottostante a verificare cosa accadeva nei dintorni dei depositi minerari della Toscana Meridionale
Questi sono gli spettri di alcuni punti nell'intorno
se si effettua la normalizzazione fondamentalmente non si vede nessun spostamento del red edg
plottando la posizione del red edge con come semplice spettro ma come mappa di ogni singolo pixel con lo script sottostante (per fare un lavoro completo avrei dovuto mascherare i punti che non sono vegetazione) si conferma che non ci sono particolari indicazion di variazioni del red edge attorno al sito minerario
Non ho mai lavorato in termico..tempo di studiarlo
Il telerilevamento termico permette di distinguere tra i vari minerali silicati lavorando sulla posizione spettrale del legame Si-O...piu' ci sono legami Si-O maggiore e' lo spostamento della firma verso il blu
Il problema con i dati termici e' che la correzione atmosferica deve essere rigorosa. Inoltre la radianza e' data da due contributi ovvero dall'emissivita' e dalla funzione di Planck relativa alla temperatura..per il telerilevamento e' di interesse solo la
Il dato completamente preprocessato e gia' pronto per le elaborazioni e' il livello AST05I dati scaricati Eartdata sono distribuiti in geotiff separati per banda. Per fare lo stacking su Esa Snap tramite Raster/Geometric/Collocation
I nomi dei geotiff sono del tipo AST_05_00410242025195203_20251124071745_SRE_TIR_B10
Si devono poi aggiustare le wavelength che sono
I dati sono quindi pronti per calcolare SI (indice siliceo)
SI = (B11xB11)/(B10xB12)
Per processare le immagini Sentinel 2 su acqua per la rimozione atmosferica si puo' usare, oltre a sen2water, anche C2RCC (Case 2 Regional CoastColour)
Si parte da un prodotto L1C ed in modo preliminare si deve otterenere la stessa risoluzione spaziale tra tutte le bande con Raster/Geometric/Resampling
Successivamente si usa Optical/Thematic Water Processing/C2RCC Processor/S2-MSI
La risposta del modello sono numerose bande
| RTOA | Radiometrico | Riflettanza top-of-atmosphere |
| RHOW | Radiometrico | Riflettanza emergente dall’acqua |
| RHOWN | Radiometrico | Riflettanza normalizzata |
| CONC | Biochimico | Concentrazioni (clorofilla, TSM materia sospesa totale, CDOM materia organica disciolta) |
| IOP | Fisico | Proprietà ottiche intrinseche |
| KD | Fisico | Attenuazione verticale della luce |
| UNC | Qualità | Incertezza del modello |
Per gli indici spettrali e' conveniente usare RHOWN
Forse il pezzo piu' esotico del mio piccolo museo dell'informatica. Casio E-SF400 in versione giapponese, un PDA a cavallo tra gli anni 80 e gli anni 90
Ci sono poche informazioni a giro su internet tra cui questo manuale
https://www.manualshelf.com/manual/casio/e-sf400/user-manual-e-sf99-200-300-400-wc-part-1-simplified-chinese/page-1.html
di fatto e' un vocabolario inglese/cinese/giapponese
In tanti anni ho visto qualche kernel panic, ma in questo formato non mi era mai successo
Per processare le immagini Emit ed ottenere il prodotto L2B e' stato utilizzato il software di spectral unmixing SpectralUnmixing.jl
Il software usa il linguaggio Julia che si installa tramite
curl -fsSL https://install.julialang.org | shDopo si clona il repository
git clone https://github.com/emit-sds/SpectralUnmixing.jl
julia
si preme il tasto parentesi quadrata chiusa il prompt si modifica da julia in pkg
addSpectralUnmixing
si esce con CTRL+C
using SpectralUnmixingsi esce con CTRL+D
Nella cartella data sono presenti dati di test per il software
nel file csv ci sono le firme spettrali degli endmeber (nome classe e riflettanza), ed una immagine in formato Envi
Per lanciare l'unmixing si usa
cd data
julia --project=/home/luca/SpectralUnmixing.jl /home/luca/.julia/bin/unmix.jl emit20250324t221005_jpl_unmix_ex basic_endmember_library.csv Class output_test --mode sma-best --n_mc 30
n_mc indica il numero di boostraping con il metodo Montecarlo
gli endmember sono Soil, PV (vegetazione fotosintetica),NPV (vegetazione non fotosintetica)
Questo l'output
┌ Info: Unmixing was processed on: HW27747
└ @ Main /home/luca/.julia/bin/unmix.jl:177
┌ Info: Reflectance file processed: emit20250324t221005_jpl_unmix_ex
└ @ Main /home/luca/.julia/bin/unmix.jl:178
┌ Info: Arguments: Dict{String, Any}("optimizer" => "bvls", "write_complete_fractions" => true, "mode" => "sma-best", "reflectance_uncertainty_file" => "", "combination_type" => "class-even", "log_file" => nothing, "normalization" => "none", "spectral_starting_column" => 2, "endmember_file" => "basic_endmember_library.csv", "truncate_end_columns" => 0, "refl_scale" => 1.0, "reflectance_file" => "emit20250324t221005_jpl_unmix_ex", "endmember_class_header" => "Class", "n_mc" => 30, "endmember_classes" => [""], "refl_nodata" => -9999.0, "output_file_base" => "output_test", "num_endmembers" => [3], "start_line" => 1, "end_line" => -1, "wavelength_ignore_regions" => [0.0, 440.0, 1310.0, 1490.0, 1770.0, 2050.0, 2440.0, 2880.0], "max_combinations" => -1)
└ @ Main /home/luca/.julia/bin/unmix.jl:179
┌ Info: Ignoring wavelength regions: Any[[0.0, 440.0], [1310.0, 1490.0], [1770.0, 2050.0], [2440.0, 2880.0]]
└ @ SpectralUnmixing /home/luca/SpectralUnmixing.jl/src/EndmemberLibrary.jl:191
┌ Info: Running from lines: 1 - 10
└ @ Main /home/luca/.julia/bin/unmix.jl:211
AbstractString[InlineStrings.String7("SOIL"), InlineStrings.String7("PV"), InlineStrings.String7("NPV")]
AbstractString[InlineStrings.String7("SOIL"), InlineStrings.String7("PV"), InlineStrings.String7("NPV"), "Brightness"]
┌ Info: Output Image Size (x,y,b): 10, 10, [4, 4, 6].
│ Creating output fractional cover dataset.
└ @ SpectralUnmixing /home/luca/SpectralUnmixing.jl/src/Datasets.jl:77
┌ Info: Output Image Size (x,y,b): 10, 10, [4, 4, 6].
│ Creating output fractional cover dataset.
└ @ SpectralUnmixing /home/luca/SpectralUnmixing.jl/src/Datasets.jl:77
┌ Info: Output Image Size (x,y,b): 10, 10, [4, 4, 6].
│ Creating output fractional cover dataset.
└ @ SpectralUnmixing /home/luca/SpectralUnmixing.jl/src/Datasets.jl:77
┌ Info: Unmix output files: ["output_test_fractional_cover", "output_test_fractional_cover_uncertainty", "output_test_complete_fractions"]
└ @ Main /home/luca/.julia/bin/unmix.jl:267
┌ Info: total number of workers available: 1
└ @ Main /home/luca/.julia/bin/unmix.jl:268
┌ Info: Line 2 run in 0.0142 seconds
└ @ SpectralUnmixing /home/luca/SpectralUnmixing.jl/src/SpectralUnmixing.jl:542
┌ Info: Line 3 run in 0.0138 seconds
└ @ SpectralUnmixing /home/luca/SpectralUnmixing.jl/src/SpectralUnmixing.jl:542
┌ Info: Line 4 run in 0.0138 seconds
└ @ SpectralUnmixing /home/luca/SpectralUnmixing.jl/src/SpectralUnmixing.jl:542
┌ Info: Line 5 run in 0.0138 seconds
└ @ SpectralUnmixing /home/luca/SpectralUnmixing.jl/src/SpectralUnmixing.jl:542
┌ Info: Line 6 run in 0.0155 seconds
└ @ SpectralUnmixing /home/luca/SpectralUnmixing.jl/src/SpectralUnmixing.jl:542
┌ Info: Line 7 run in 0.0144 seconds
└ @ SpectralUnmixing /home/luca/SpectralUnmixing.jl/src/SpectralUnmixing.jl:542
┌ Info: Line 8 run in 0.0207 seconds
└ @ SpectralUnmixing /home/luca/SpectralUnmixing.jl/src/SpectralUnmixing.jl:542
┌ Info: Line 9 run in 0.0181 seconds
└ @ SpectralUnmixing /home/luca/SpectralUnmixing.jl/src/SpectralUnmixing.jl:542
┌ Info: Line 10 run in 0.0137 seconds
└ @ SpectralUnmixing /home/luca/SpectralUnmixing.jl/src/SpectralUnmixing.jl:542
17.617387 seconds (18.76 M allocations: 1.104 GiB, 32.59% gc time, 66.76% compilation time)
i file di output saranno file hdr (complete_fractions, fractional_cover, fractional_cover_uncertainty)
complete_fractions: indica la percentuale della classe contenuta nel pixel
fractional_cover : se complete_fraction indica tipo il 60%, fractional_cover indica la divisione percentuale delle frazioni mineralogiche (Ematite, Goethite....). Se la complete_fractions della categoria Soil e' inferiore al 20% e' inutile questo successivo raffinamento
Le bande in fractional_cover individuano
fractional_cover_uncertainty: indica la qualita' del dato...valori bassi unmixing migliore
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
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
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
Leggendo la documentazione delle libreria HyperCoast ho trovato riferimento a Moe Vae. Si tratta di una rete neurale complessa basato su
Mixture-of-Experts Variational Autoencoder for Clustering and Generating from Similarity-Based Representations on Single Cell Data
Andreas Kopf, Vincent Fortuin, Vignesh Ram Somnath, Manfred Claassen
https://arxiv.org/abs/1910.07763
che ha il vantaggio di lavorare su una moltitudine di dati come quelli iperspettrali
Ho provato tramite AI, con i dati di Indian Pines
![]() |
| A sinistra verita'a terra A destra risultato del modello |
Un breve riassunto degli indici utilizzati in Ensomap all'interno del plugin Enmap toolbox di QGis Carbonate 1) assorbimento dopo rim...