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

mercoledì 10 aprile 2024

Decision Tree Tensorflow su dati Sentinel 2

 Ho ripreso il filone di questa prova per provare i Decision Tree con le firme spettrali di Sentinel 2

Per la prova ho preso l'immagine S2B_MSIL2A_20230826T100559_N0509_R022_T32TPP_20230826T134424.SAFE

del periodo estivo del Mugello (Toscana) in modo da avere suolo nudo disponibile.


Visto che volevo estrarre tutte le bande tramite SNAP ho campionato tutte le bande a 10 m (altrimenti come visto nel precedente post lo Spectral Viewer estrae solo le bande native a 10 m)...e qui c'e' un problema...ho dovuto fare il resampling spaziale di tutta l'immagine e dopo fare il subset della mia sola area di interesse altrimenti, invertendo le due operazioni, SNAP entrava continuamente in errore

Usando gli OpenData della Regione Toscana

https://dati.toscana.it/dataset/dbped

ho usato il dataset per selezionare il parametro contenuto in argilla del suolo categorizzandolo a passi del 5%. Usando i Pin e la vista sincronizzata tra la mappe del suolo e l'immagine telerilevata sono selezionati 153 punti appartenenti a 4 classi di contenuto in argilla

Classe/Nr spettri 3 44 2 41 0 34 1 34

Il contenuto in argille delle classi e'

classe 1 (amaranto) : 45-50%

classe 2 (arancione) : 30-35%

classe 3 (rosso) :40-45%

classe 4 (verde) : 20-25%




il file dati in CSV e' formato nel seguente modo

443,490,560,665,705,740,783,842,865,945,1610,2190,Classe
0.0711,0.1056,0.1548,0.2046,0.2335,0.2442,0.2617,0.2624,0.2801,0.2813,0.3556,0.2868,1
0.0777,0.1052,0.157,0.2032,0.2311,0.2415,0.2611,0.2562,0.2741,0.2841,0.3473,0.2829,1

Come si vede dall'esempio la variabilita' spettrale in ogni classe e' molto elevata (in rosso lo spettro medio)



Lo spettro medio per ogni classe di contenuto in argilla e' visualizzato negl grafico sottostante


Usando una rete neurale tradizionale l'accuratezza e ' prossima al 77%

import pandas as pd
import numpy as np
import tensorflow as tf
import seaborn as sns
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Dropout
from sklearn.preprocessing import LabelEncoder , StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, confusion_matrix

df = pd.read_csv('/content/totale2.csv')
print(df.head())

le = LabelEncoder()
df['Classe'] = le.fit_transform(df['Classe'])

X = df.drop(columns=['Classe'])
y = df['Classe']
print(y.head())
print(y.value_counts())
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.25,shuffle=True,random_state=7)

sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)

print(X_train.size)
print(y_train)
y_train = tf.keras.utils.to_categorical(y_train,num_classes=4)
def get_models():
    model = Sequential([
        Dense(units=32,input_shape=(12,),activation='relu'),
        Dense(units=32,activation='relu'),
        Dropout(0.5),
        Dense(units=4,activation='softmax')
    ])
    return model

model = get_models()
model.compile(optimizer='Adam',loss='categorical_crossentropy',metrics=['accuracy'])
model.summary()

model.fit(X_train,y_train,epochs=100, verbose=2)

prediction = model.predict(X_test)
prediction = np.argmax(prediction,axis=-1)
acury = accuracy_score(y_test,prediction)
print(acury)
cm = confusion_matrix(y_test,prediction)
print(cm)

0.7692307692307693

Con la seguente matrice di confusione

[[ 4 1 0 0] [ 4 7 0 0] [ 0 0 9 0] [ 1 2 1 10]]


Utilizzando i decision tree

!pip install -q -U tensorflow_decision_forests
!pip install -q -U dtreeviz
import tensorflow_decision_forests as tfdf

import tensorflow as tf

import os
import numpy as np
import pandas as pd
import tensorflow as tf
import math

import dtreeviz

from matplotlib import pyplot as plt
from IPython import display

import logging
logging.getLogger('matplotlib.font_manager').setLevel(level=logging.CRITICAL)

display.set_matplotlib_formats('retina') # generate hires plots

np.random.seed(1234)
def split_dataset(dataset, test_ratio=0.30, seed=1234):
  np.random.seed(seed)
  test_indices = np.random.rand(len(dataset)) < test_ratio
  return dataset[~test_indices], dataset[test_indices]
df_spettri = pd.read_csv("/content/totale2.csv")
df_spettri.head(3)
spettri_label = "Classe"   # Name of the classification target label
classes = list(df_spettri[spettri_label].unique())
df_spettri[spettri_label] = df_spettri[spettri_label].map(classes.index)

print(f"Target '{spettri_label}'' classes: {classes}")
df_spettri.head(3)
# Split into training and test sets
train_ds_pd, test_ds_pd = split_dataset(df_spettri)
print(f"{len(train_ds_pd)} examples in training, {len(test_ds_pd)} examples for testing.")

# Convert to tensorflow data sets
train_ds = tfdf.keras.pd_dataframe_to_tf_dataset(train_ds_pd, label=spettri_label)
test_ds = tfdf.keras.pd_dataframe_to_tf_dataset(test_ds_pd, label=spettri_label)
cmodel = tfdf.keras.RandomForestModel(verbose=0, random_seed=1234)
cmodel.fit(train_ds)
cmodel.compile(metrics=["accuracy"])
cmodel.evaluate(test_ds, return_dict=True, verbose=0)
# Tell dtreeviz about training data and model
spettri_features = [f.name for f in cmodel.make_inspector().features()]
viz_cmodel = dtreeviz.model(cmodel,
                           tree_index=3,
                           X_train=train_ds_pd[spettri_features],
                           y_train=train_ds_pd[spettri_label],
                           feature_names=spettri_features,
                           target_name=spettri_label,
                           class_names=classes)
viz_cmodel.view(scale=1.75)

si ha una accuracy di circa 0.7




venerdì 18 novembre 2022

Elaborazione batch con SNAP GPT headless

 E' possibile utilizzare SNAP in modalita' headless installando da remoto su un server il normale pacchetto di SNAP. A seconda del fatto che sia presente o meno una sessione di interfaccia grafica o meno viene eseguito un tipo diverso di installer

Per eseguire una catena di comandi in SNAP si puo' in maniera interattiva creare un grafico con Graph Builder e salvare il grafico in formato xml



questo e' un esempio di grafico salvato da SNAP per il calcolo NDVI tramite BandMath

=============================================================
<graph id="Graph">
  <version>1.0</version>
  <node id="Read">
    <operator>Read</operator>
    <sources/>
    <parameters class="com.bc.ceres.binding.dom.XppDomElement">
      <useAdvancedOptions>false</useAdvancedOptions>
      <file>/home/luca/transi/S2B_MSIL2A_20220811T100559_N0400_R022_T32TPP_20220811T162101.zip</file>
      <copyMetadata>true</copyMetadata>
      <bandNames/>
      <pixelRegion>0,0,10980,10980</pixelRegion>
      <maskNames/>
    </parameters>
  </node>
  <node id="BandMaths">
    <operator>BandMaths</operator>
    <sources>
      <sourceProduct refid="Read"/>
    </sources>
    <parameters class="com.bc.ceres.binding.dom.XppDomElement">
      <targetBands>
        <targetBand>
          <name>NDVI</name>
          <type>float32</type>
          <expression>(B8 - B4) / (B8 + B4)</expression>
          <description/>
          <unit/>
          <noDataValue>0.0</noDataValue>
        </targetBand>
      </targetBands>
      <variables/>
    </parameters>
  </node>
  <node id="Write">
    <operator>Write</operator>
    <sources>
      <sourceProduct refid="BandMaths"/>
    </sources>
    <parameters class="com.bc.ceres.binding.dom.XppDomElement">
      <file>/home/luca/transi/BandMath.tif</file>
      <formatName>GeoTIFF</formatName>
    </parameters>
  </node>
  <applicationData id="Presentation">
    <Description/>
    <node id="Read">
            <displayPosition x="37.0" y="134.0"/>
    </node>
    <node id="BandMaths">
      <displayPosition x="184.0" y="136.0"/>
    </node>
    <node id="Write">
            <displayPosition x="455.0" y="135.0"/>
    </node>
  </applicationData>
</graph>

=============================================================

per renderlo utilizzabile in modalita' batch si devono modificarlo per inserire delle variabili
Le variabili sono nel formato ${nome_variabile}
Nel codice sottostante e' stato reso variabile il file di input
=============================================================
<graph id="Graph">
  <version>1.0</version>
  <node id="Read">
    <operator>Read</operator>
    <sources/>
    <parameters class="com.bc.ceres.binding.dom.XppDomElement">
      <useAdvancedOptions>false</useAdvancedOptions>
      <file>${ingresso}</file>
      <copyMetadata>true</copyMetadata>
      <bandNames/>
      <pixelRegion>0,0,10980,10980</pixelRegion>
      <maskNames/>
    </parameters>
  </node>
  <node id="BandMaths">
    <operator>BandMaths</operator>
    <sources>
      <sourceProduct refid="Read"/>
    </sources>
    <parameters class="com.bc.ceres.binding.dom.XppDomElement">
      <targetBands>
        <targetBand>
          <name>NDVI</name>
          <type>float32</type>
          <expression>(B8 - B4) / (B8 + B4)</expression>
          <description/>
          <unit/>
          <noDataValue>0.0</noDataValue>
        </targetBand>
      </targetBands>
      <variables/>
    </parameters>
  </node>
  <node id="Write">
    <operator>Write</operator>
    <sources>
      <sourceProduct refid="BandMaths"/>
    </sources>
    <parameters class="com.bc.ceres.binding.dom.XppDomElement">
      <file>/home/luca/transi/ndvi.tif</file>
      <formatName>GeoTIFF</formatName>
    </parameters>
  </node>
  <applicationData id="Presentation">
    <Description/>
    <node id="Read">
            <displayPosition x="37.0" y="134.0"/>
    </node>
    <node id="BandMaths">
      <displayPosition x="184.0" y="136.0"/>
    </node>
    <node id="Write">
            <displayPosition x="455.0" y="135.0"/>
    </node>
  </applicationData>
</graph>
=============================================================

da linea di comando si puo' usare lo switch -P per popolare la variabile

-Pnome_variabile=valore_variabile

per lanciare il processo per esempio si puo' usare

/home/luca/snap/bin/gpt ndvi2.xml -Pingresso=/home/luca/transi/S2B_MSIL2A_20220811T100559_N0400_R022_T32TPP_20220811T162101.zip

sabato 21 novembre 2020

Realsense SDK con D435 in Debian

Dopo un po' di esperienza con i sensori a luce strutturata ho provata il sensore Intel RealSense D435 (attenzione manca la i finale....a differenza al D435i qui non e' presenta la IMU integrata) che funziona come sensore di profondita' usando la stereoscopia di due camere

Il sensore e' nato per applicazioni di robotica ed e' molto veloce nell'acquisizione/elaborazione (circa 30 fps) ma il risultato come dato di profondita' e' molto differente da quello che si ottiene da un sensore a luce strutturata


Oltre alle due camere per la stereoscopia e' presente un illuminatore IR per migliorare il dato di profondita' ed una camera RGB

La distanza massima operativa e' di circa 4m. Come si nota dal video il dato e' molto rumoroso



Un aspetto che mi ha lasciato molto perplesso e' che non risultano essere conservati gli angoli. Per esempio nella realta' l'angolo e' di 90 gradi mentre dalla mesh risulta essere di 105 gradi. Credo che questo sia dovuto al fatto che le lenti sono quasi dei fish-eye



Per quanto rigurda le lunghezza la porta in realta' e' larga 125 cm mentre il sensore la misura circa 105 cm

Diciamo che i dati al centro dell'immagine sono coerenti ma sui bordi 

l'SDK e' nato per Windows e Ubuntu ma si puo' installare su Debian utilizzando Snap

snap install librealsense

Oltre alle librerie si installa anche realsense-viewer da cui e' possibile anche effettuare l'upgrade del firmware della camera

Gli esempi si trovano a  https://dev.intelrealsense.com/docs/code-samples

Per compilare gli esempi ho dovuto installare anche la libreria StbEasyFont (e' presente nella directory third parts ma io la ho installata con apt per semplicita')

=================================================
cmake_minimum_required(VERSION 3.5)

project(realsense LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(realsense2 REQUIRED )


add_executable(realsense main.cpp)
target_link_libraries(realsense realsense2)

=================================================

=================================================
#include <iostream>
#include <librealsense2/rs.hpp> 

using namespace std;

int main()
{
    rs2::pipeline p;
    p.start();
    rs2::frameset frames = p.wait_for_frames();
    rs2::depth_frame depth = frames.get_depth_frame();
    float width = depth.get_width();
    float height = depth.get_height();
    float dist_to_center = depth.get_distance(width / 2, height / 2);
    std::cout << "The camera is facing an object " << 
dist_to_center << " meters away" << endl << endl;
    return 0;
}
=================================================

Multicam
Nell'esempio Multicam oltre alla libreria Realsense viene usata anche OpenGL con glfw


================================================
cmake_minimum_required(VERSION 3.5)

project(multicam LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# finds OpenGL, GLU and X11
find_package(OpenGL REQUIRED)
if(NOT OPENGL_FOUND)
    message("ERROR: OpenGL not found")
endif(NOT OPENGL_FOUND)
set(GL_LIBRARY GL GLU X11)


find_package(realsense2 REQUIRED )

add_executable(multicam main.cpp)
target_link_libraries(multicam realsense2 glfw ${GL_LIBRARY} m)
================================================


Geologi

  E so anche espatriare senza praticamente toccare strada asfaltata