venerdì 14 gennaio 2022

Nebulosa di Orione con telescopio

 Nuovo tentativo della Nebulosa di Orione stavolta con il telescopio

Il mio telescopio non e' idoneo a fare fotografie di spazio profondo ed anche il motore di inseguimento lascia molto a desiderare

Ho provato quindi a non fare stacking facendo scatti molto brevi....nonostante tutto anche a 0.6 si osserva iniziare star trailing. Immagini riprocessate con Gimp. Scatti a 1600 e 3200 iso





questa e' l'immagine presa da Stellarium come riferimento


mercoledì 12 gennaio 2022

Nebulosa di Orione con DSLR

 Foto della nebulosa di Orione M42 ripresa dal centro di Firenze con una DSLR Canon Eos 500d e tele...condizioni peggiori e' difficile immaginarsele. 1600 ISO 2 secondi per scatto

Immagine singola


Stack processato con DeepSkyStacker

Questo il disegno della nebulosa di Orione contenuto nel Sidereus Nuncius di Galileo (fonte progetto Manunzio)


venerdì 7 gennaio 2022

Ambiente di sviluppo Golang senza permessi di amministratore

 Per impostare un ambiente di lavoro Golang su Windows senza avere i permessi di amministrazione si inizia scaricando GO non in versione installer ma in versione archive del tipo  go1.17.6.windows-amd64.zip




Si decomprime la cartella nella propria home

A questo punto si impostano le variabili di ambiente per l'account aggiungendo alla PATH la directory appena scompattata puntando alla directory /bin

Dopo di cio' si crea una nuova variabile di nome GOPATH e la si fa puntare alla directory dove si intende effettuare lo sviluppo

Se si e' dietro ad un proxy si puo' settare la variabile GOPROXY



sabato 1 gennaio 2022

UI per Golang

 Go non ha una UI di default. Si possono utilizzare dei bindings con GTK3 o delle UI native 



go mod init luca.innocenti.gtk3test

si caricano i moduli

go get github.com/gotk3/gotk3/glib

go get github.com/gotk3/gotk3/gtk

si apre quindi Glade per creare la pgina (una semplice textbox Entry nel linguaggio di GTK, una label ed un pulsante)

---- completo.glade -----------------------------------------

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkWindow" id="main_window">
    <property name="can_focus">False</property>
    <child>
      <placeholder/>
    </child>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="margin_top">4</property>
        <property name="margin_bottom">4</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkEntry" id="txt1">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel" id="lbl1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">Etichetta</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="btn1">
            <property name="label" translatable="yes">Ok</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="halign">center</property>
            <property name="valign">center</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

---------------------------------------------

nel codice go si carica il file completo.glade

Si tratta di una piccola modifica del codice degli esempi che si trovano su GitHub 

Gli eventi possono essere creati (connessi) sia nel codice sia all;'interno dei segnali di Glade...in questo caso sono tutti contenuti nel codice applicazione. In ogni caso se si puo' associare in Glade un segnnale di nome "pressione" all'evento di click del pulsante

package main

import (
"errors"
"fmt"
"log"
"os"

"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk"
)

const appId = "com.github.gotk3.gotk3-examples.glade"

func main() {
// Create a new application.
application, err := gtk.ApplicationNew(appId, glib.APPLICATION_FLAGS_NONE)
errorCheck(err)

// Connect function to application startup event, this is not required.
application.Connect("startup", func() {
log.Println("application startup")
})

// Connect function to application activate event
application.Connect("activate", func() {
log.Println("application activate")

// Get the GtkBuilder UI definition in the glade file.
// builder, err := gtk.BuilderNewFromFile("ui/example.glade")
builder, err := gtk.BuilderNewFromFile("/home/luca/glade/completo.glade")
errorCheck(err)

obj, _ := builder.GetObject("txt1")
entry1 := obj.(*gtk.Entry)

obj2, _ := builder.GetObject("btn1")
button1 := obj2.(*gtk.Button)

obj3, _ := builder.GetObject("lbl1")
label1 := obj3.(*gtk.Label)

button1.Connect("clicked", func() {
text, err := entry1.GetText()
if err == nil {
label1.SetText(text)
}
})

// Map the handlers to callback functions, and connect the signals
// to the Builder.
signals := map[string]interface{}{
"on_main_window_destroy": onMainWindowDestroy,
//"pressione": clickedTestButton,
}
builder.ConnectSignals(signals)

// Get the object with the id of "main_window".
obj4, err := builder.GetObject("main_window")
errorCheck(err)

// Verify that the object is a pointer to a gtk.ApplicationWindow.
win, err := isWindow(obj4)
errorCheck(err)

// Show the Window and all of its components.
win.Show()
application.AddWindow(win)
})

// Connect function to application shutdown event, this is not required.
application.Connect("shutdown", func() {
log.Println("application shutdown")
})

// Connect function to application shutdown event, this is not required.
application.Connect("pressione", func() {
log.Println("pressione")
fmt.Println("pressione")
})

// Launch the application
os.Exit(application.Run(os.Args))
}

func isWindow(obj glib.IObject) (*gtk.Window, error) {
// Make type assertion (as per gtk.go).
if win, ok := obj.(*gtk.Window); ok {
return win, nil
}
return nil, errors.New("not a *gtk.Window")
}

func errorCheck(e error) {
if e != nil {
// panic for any errors.
log.Panic(e)
}
}

/*
func clickedTestButton() {
fmt.Println("Testclick")
//headerBar.SetTitle("New Title!!")
}*/

// onMainWindowDestory is the callback that is linked to the
// on_main_window_destroy handler. It is not required to map this,
// and is here to simply demo how to hook-up custom callbacks.
func onMainWindowDestroy() {
log.Println("onMainWindowDestroy")
}

per eseguire il programma 

go run -tags pango_1_42,gtk_3_22 .


con la libreria nativa il codice e' piu' pulito. L'unico problema e' che si tratta di una libreria dichiarata ancora in alpha e che non risulta aggiornata da due anni

package main

import (
"github.com/andlabs/ui"
)

func main() {
err := ui.Main(func() {
input := ui.NewEntry()
button := ui.NewButton("Ok")
greeting := ui.NewLabel("")
box := ui.NewVerticalBox()
box.Append(ui.NewLabel("Label"), false)
box.Append(input, false)
box.Append(button, false)
box.Append(greeting, false)
window := ui.NewWindow("UI", 200, 100, false)
window.SetMargined(true)
window.SetChild(box)
button.OnClicked(func(*ui.Button) {
greeting.SetText(input.Text())
})
window.OnClosing(func(*ui.Window) bool {
ui.Quit()
return true
})
window.Show()
})
if err != nil {
panic(err)
}
}


martedì 28 dicembre 2021

Realsense

Stavo cercando un metodo per aveere un set di training per Monocular Depth Estimation ed ho ritirato fuori la RealSense  D415 per scoprire che ad Agosto 2021 la Intel ha dichiarato la dismissione di questi sensori robotici (ad esclusione di quelli stereoscopici).... mi ricorda tanto la storia di Intel Edison ed Intel Stick...progetti interessanti morti 



Questo piccolo programmino (che modifica uno degli esempi dell'SDK di Realsense) salva la mappa di profondita' in formato NumPy ed la corrispondente immagine JPG premendo il tasto S

Per compilare in binario l'eseguibile

pyinstaller main.py --onefile


requirements.txt

altgraph==0.17.2
importlib-metadata==4.8.3
numpy==1.19.5
opencv-python==4.1.2.30
Pillow==8.4.0
pyinstaller==4.7
pyinstaller-hooks-contrib==2021.4
pyrealsense2==2.50.0.3812
typing_extensions==4.0.1
zipp==3.6.0

main.py

import sys,getopt
import pyrealsense2 as rs
import numpy as np
import cv2
from PIL import Image
import os.path

def completo(argv):
outputdir = ''
if len(sys.argv) < 2:
print('test.py -o <output_directory>')
sys.exit()
try:
opts, args = getopt.getopt(argv, "hi:o:", ["odir="])
except getopt.GetoptError:
print('test.py -o <output_directory>')
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print('test.py -o <output_directory>')
sys.exit()
elif opt in ("-o", "--odir"):
outputdir = arg
if (os.path.isdir(outputdir)) == False:
print('Errore nome directory output')
sys.exit()
print('Output file is ' + outputdir)
## License: Apache 2.0. See LICENSE file in root directory.
## Copyright(c) 2015-2017 Intel Corporation. All Rights Reserved.

###############################################
## Open CV and Numpy integration ##
###############################################



# Configure depth and color streams
pipeline = rs.pipeline()
config = rs.config()

# Get device product line for setting a supporting resolution
pipeline_wrapper = rs.pipeline_wrapper(pipeline)
pipeline_profile = config.resolve(pipeline_wrapper)
device = pipeline_profile.get_device()
device_product_line = str(device.get_info(rs.camera_info.product_line))

found_rgb = False
for s in device.sensors:
if s.get_info(rs.camera_info.name) == 'RGB Camera':
found_rgb = True
break
if not found_rgb:
print("The demo requires Depth camera with Color sensor")
exit(0)

contatore = 0

config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)

if device_product_line == 'L500':
config.enable_stream(rs.stream.color, 960, 540, rs.format.bgr8, 30)
else:
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)

# Start streaming
pipeline.start(config)

try:
while True:

# Wait for a coherent pair of frames: depth and color
frames = pipeline.wait_for_frames()
depth_frame = frames.get_depth_frame()
color_frame = frames.get_color_frame()
if not depth_frame or not color_frame:
continue

# Convert images to numpy arrays
depth_image = np.asanyarray(depth_frame.get_data())
color_image = np.asanyarray(color_frame.get_data())

# Apply colormap on depth image (image must be converted to 8-bit per pixel first)
depth_colormap = cv2.applyColorMap(cv2.convertScaleAbs(depth_image, alpha=0.03), cv2.COLORMAP_JET)

depth_colormap_dim = depth_colormap.shape
color_colormap_dim = color_image.shape


# If depth and color resolutions are different, resize color image to match depth image for display
if depth_colormap_dim != color_colormap_dim:
resized_color_image = cv2.resize(color_image, dsize=(depth_colormap_dim[1], depth_colormap_dim[0]),
interpolation=cv2.INTER_AREA)
images = np.hstack((resized_color_image, depth_colormap))
else:
images = np.hstack((color_image, depth_colormap))

# Show images
cv2.namedWindow('Immagine', cv2.WINDOW_AUTOSIZE)

cv2.imshow('Immagine' , images)
tasto = cv2.waitKey(1000)
#print(str(tasto))
if (tasto == 115): #S
#salva su file
contatore = contatore + 1
str_conta = str(contatore)
try:
np.save(str_conta.zfill(3)+'_depth.npy', depth_image)
im = Image.fromarray(color_image)
im.save(str_conta.zfill(3)+"_color.jpg")
print('Immagine ' + str(contatore) + 'acquisita')
except:
print('Errore acquisizione')
exit()
if (tasto == 113): #Q
exit()

finally:
# Stop streaming
pipeline.stop()

if __name__ == '__main__':
completo(sys.argv[1:])

giovedì 23 dicembre 2021

Correlazione tra serie tempo

 Un semplice script che calcola la correlazione tra due serie tempo (due estensimetri) facendo scorrere una finestra mobilew    


Come si vede il versante si muove con costanza in modo uniforme (i due estensimetri hanno dati correlabili)...quando c'e' una accelerazione questa e' locale e fa decorrelare i due punti di misura. In seguito si reinstaura il movimento generale

I dati meteo sono sostanzialmente inutili perche' in inverno le precipitazioni sono unicamente nevose. Nel resto dell'anno le precipitazioni non sembrano avere una particolare stagionalita'


import datetime as dt
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt

from sklearn.preprocessing import PolynomialFeatures

from scipy import signal

## tutti i dati sono ricampionamti su base giornaliera
## i dati sono campionati ogni 20 oppure ogni 15 minuti
## i dati radar sono campionati ogni 70 minuti

################### METEO ################################
## dal 24/7/2019 00;00 al 1/12/2021 23:59
parser = lambda date: dt.datetime.strptime(date, '%d/%m/%Y %H:%M')
meteo = pd.read_csv('meteo/meteo.csv', sep=';', parse_dates=['Data'], index_col=['Data'], infer_datetime_format=True)

#effettua il resampling sui 180 minuti
meteo_d = meteo.resample('180T').sum()
meteo_d.to_csv("meteo_180.csv")

print(meteo_d.shape)

#################### RADAR ###############################
parser = lambda date: dt.datetime.strptime(date, '%d/%m/%Y %H:%M:%S.%f')
# legge il csv e lo mette in un dataframe
dati_s1 = pd.read_csv('disp_raw_PTS_P2.csv', sep=',', parse_dates=['Tempo'], index_col=['Tempo'], date_parser=parser)
dati_s2 = pd.read_csv('disp_raw_PTS_P30.csv', sep=',', parse_dates=['Tempo'], index_col=['Tempo'], date_parser=parser)
# ricampiona in base giornaliera
dati_s1_d = dati_s1.resample('180T').mean()
dati_s2_d = dati_s2.resample('180T').mean()
#estrae solo i dati per i quali c'e' anche il dato meteo
#dati_s1_d_f = dati_s1_d[246:1107]
#dati_s2_d_f = dati_s1_d[246:1107]

#salva su file
dati_s1_d.to_csv("s1.csv")
dati_s2_d.to_csv("s2.csv")

# finestra mobile
mw = []
x1 = np.arange(862)

for i in range(1950,8846):
set1 = dati_s1_d[i-160:i]
set2 = dati_s2_d[i-160:i]
mw_v = np.corrcoef(set1.iloc[:,0],set2.iloc[:,0])
mw.append(mw_v[0,1])

plt.figure()

plt.subplot(311)
plt.plot(meteo_d.index,dati_s1_d[1950:8846], color='green', label='P2')
plt.plot(meteo_d.index,dati_s2_d[1950:8846], color='blue', label='P30')
plt.legend()

plt.xlabel('Tempo')
plt.ylabel('Raw Radar (mm)')
plt.title('P2 P30')


plt.subplot(312)
plt.plot(meteo_d.index,mw, color='red')

plt.xlabel('Tempo')
plt.ylabel('Indice corr.')


plt.subplot(313)
plt.bar(meteo_d.index,meteo_d['Pluv.[mm]'])
plt.xlabel('Tempo')
plt.ylabel('Prec. (mm)')
plt.show()

#### ricerca del lag
print("########lag")
correlation = signal.correlate(dati_s1_d-np.mean(dati_s1_d), dati_s2_d - np.mean(dati_s2_d), mode="full")
lags = signal.correlation_lags(len(dati_s1_d), len(dati_s2_d), mode="full")
lag = lags[np.argmax(correlation)]
print(lag)


Confronto Monocular Midas vs Metashape

 Questo e' un semplice confronto da una ricostruzione 3D derivante da una singola immagine effettuata da MiDas e lo stesso oggetto ricostruito da molte immagini mediante MetaShape. Ovviamente la battaglia e'ad armi impari perche' Metashape (usando piu' punti di ripresa) ha il vantaggio della stereoscopia. Inoltre c'e' da dire che le reti sono allenate con soggetti urbani indoor ed outdoor

Affioramento roccioso

In questo caso si osserva che in MiDas i bordi dell'immagine sono in rilievo. Il blocco in aggetto viene ricostruito in modo sostanzialmente corretto

Immagine originale
Metashape

Midas

Immagine da drone
L'immagine da drone e' la piu' complicata per MiDas perche' ha una visione nadirale. Si vede che MiDas non riesce a risolvere in nessuno modo il rilievo tra i due ruscellamenti anche aumentando l'esagerazione verticale

Immagine reale 


Metashape


MiDas (20x verticale)

Midas (100x verticale)

Primo Piano
In questo caso sono risolti tre piani (primo piano, piano intermedio ovvero cartello e sfondo)




Debugger integrato ESP32S3

Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede  nell'ID USB della porta Jtag. Nel modulo...