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

venerdì 24 aprile 2026

RTMP Stream da drone DJI

Per prima cosa, per avere uno stream dal drone si crea un server RTMP tramite il docker di Mediamtx mettendo i seguenti files nella stessa cartella 

docker-compose.yml

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

version: "3.8"
services:
  mediamtx:
    image: bluenviron/mediamtx:latest
    container_name: mediamtx
    restart: unless-stopped
    ports:
      - "8554:8554"   # RTSP
      - "8888:8888"   # HTTP / WebRTC
      - "8889:8889"   # HTTPS
      - "1935:1935"   # RTMP
    volumes:
      - ./mediamtx.yml:/mediamtx.yml:ro

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

mediamtx.yml

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

# Porte
rtmpAddress: :1935
rtspAddress: :8554
hlsAddress: :8888
webrtcAddress: :8889
apiAddress: :9997

# Configurazione HLS (bassa latenza)
hlsSegmentDuration: 1s
hlsPartDuration: 200ms
hlsSegmentMaxSize: 50MB

# Path dello stream
paths:
  mystream:
    # Permessi semplificati (versioni recenti)
    source: publisher

    # Lancia ffmpeg automaticamente quando arriva uno stream
    runOnReady: >
      ffmpeg -i rtmp://localhost:1935/mystream
      -vf fps=1 -q:v 2 /tmp/frames/frame_%04d.jpg
    runOnReadyRestart: yes
 

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

e lanciando 

docker run -d --name mediamtx -p 0.0.0.0:1935:1935 -p 8554:8554 -p 8888:8888 bluenviron/mediamtx:latest 

Lo stream si puo' visualizzare con FFMpeg direttamente sulla macchina docker 

ffplay -fflags nobuffer \
       -flags low_delay \
       -framedrop \
       -sync ext \
       rtmp://localhost:1935/luca

e si possono salvare anche i frame ad intervalli prefissati

ffmpeg -i rtmp://localhost:1935/live/mystream \ -vf fps=1 \ -q:v 2 \ /tmp/frames/frame_%04d.jpg 

per semplificare lo sviluppo si puo' usare un cellulare al posto del drone usando la app RMTP Streamer

si va nel pulsante Server e si impostano i parametri del docker server

si torna indietro e si preme Go Stream in basso a destra
 

altrimenti da DJI Flight queste sono le schermate per impostare lo stream


 


 

a questo punto puo' essere interessante uno script che legga il flusso e salva un fotogramma quando c'e' una differenza compresa tra il 65% ed il 75% dal precedente salvato in modo da poi dare in pasto a Opendronemap per la ricostruzione 

 

import cv2
import numpy as np
import os

def main():
# Inserisci qui l'indirizzo del tuo server RTMP
rtmp_url = "rtmp://192.168.1.79:1935/luca"
# Inizializzazione cattura video
cap = cv2.VideoCapture(rtmp_url)

# Buffer setting: utile per stream di rete per ridurre la latenza
cap.set(cv2.CAP_PROP_BUFFERSIZE, 3)

if not cap.isOpened():
print(f"Errore: Impossibile connettersi al server RTMP: {rtmp_url}")
return

output_dir = "catture_rtmp"
if not os.path.exists(output_dir):
os.makedirs(output_dir)

print("Connessione stabilita. In attesa del primo frame...")

# 1. Leggi e salva il primo fotogramma come riferimento iniziale
ret, first_frame = cap.read()
if not ret:
print("Errore: Impossibile ricevere dati dallo stream.")
return

# Funzione di utility per preparare l'immagine al confronto
def prepare_frame(f):
gray = cv2.cvtColor(f, cv2.COLOR_BGR2GRAY)
return cv2.GaussianBlur(gray, (21, 21), 0)

ref_gray = prepare_frame(first_frame)
count = 0
# Salva il primo riferimento
cv2.imwrite(f"{output_dir}/ref_iniziale.jpg", first_frame)
print("Primo frame salvato. Monitoraggio differenze (65%-75%) avviato...")

try:
while True:
ret, frame = cap.read()
if not ret:
print("Perdita del segnale RTMP...")
break

# Preparazione frame corrente
current_gray = prepare_frame(frame)

# 2. Calcolo della differenza
# absdiff calcola la differenza assoluta pixel per pixel
diff_frame = cv2.absdiff(ref_gray, current_gray)
# Applichiamo una soglia: se la differenza di un pixel è > 25, diventa bianco (255)
_, thresh = cv2.threshold(diff_frame, 25, 255, cv2.THRESH_BINARY)
# 3. Calcolo percentuale di cambiamento
# Rapporto tra pixel bianchi e numero totale di pixel
change_pixels = np.count_nonzero(thresh)
total_pixels = thresh.size
diff_percentage = (change_pixels / total_pixels) * 100

# 4. Logica di salvataggio e aggiornamento riferimento
if 65.0 <= diff_percentage <= 75.0:
count += 1
filename = f"{output_dir}/cambiamento_{count}.jpg"
cv2.imwrite(filename, frame)
# Il frame attuale diventa il nuovo riferimento
ref_gray = current_gray
print(f"[{count}] Salvato! Differenza: {diff_percentage:.2f}%. Nuovo riferimento impostato.")

# Visualizzazione a schermo
cv2.putText(frame, f"Diff: {diff_percentage:.1f}%", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.imshow("RTMP Monitor - Press 'q' to stop", frame)

if cv2.waitKey(1) & 0xFF == ord('q'):
break

except KeyboardInterrupt:
print("\nChiusura forzata dall'utente.")
finally:
cap.release()
cv2.destroyAllWindows()
print("Risorse liberate correttamente.")

if __name__ == "__main__":
main()


Per procedere da linea di comando alla creazione di un modello 3d si puo' usare il docker di opendronemap (le impostazioni sono volutamente per la creazione di un modello speditivo da usare in campagna...per il perfezionamento si puo' fare in ufficio(

docker run -ti --rm \
  -v /home/luca/Downloads/immagini:/datasets/immagini \
  opendronemap/odm \
  --project-path /immagini \
  --pc-quality low \
  --pc-sample 0.01 \
  --resize-to 2000 \
  --feature-quality low \
  --skip-orthophoto
 

 

 

giovedì 6 novembre 2025

Ros Noetic Docker Phantomx Reactor Robotic Arm

Ci avevo provato qui ma non era andato bene (solo Arduino era ok)..ci riprovo adesso con il dispositivo fisico 

 

  

 

Attenzione: la scheda Arbotix deve essere gia' montato lo sketch ROS (vedi post precedente)

Per prima cosa si crea nella propria home

mkdir ~/ws_catkin

mkdir ~/ws_catkin/src 

xhost +local:docker

poi si lancia il docker (immagine completa di No Etic) 

sudo docker run -it   --net=host   --env="DISPLAY=$DISPLAY"   --env="QT_X11_NO_MITSHM=1"   --env="XAUTHORITY=$XAUTH"   --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw"   --volume="$HOME/ws_catkin:/root/ws_catkin:rw" --device=/dev/ttyUSB0:/dev/ttyUSB0 --privileged   --name ros_noetic_gui   osrf/ros:noetic-desktop-full

per testare si usa il simulatore turtle  

roscore&

rosrun turtlesim turtlesim_node&
 
si dovrebbe essere aperta una finestra grafica 

 
si richiedono i servizi disponibili
rosservice list
 
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
/turtlesim/get_loggers
/turtlesim/set_logger_level
 
ed i topic 
rostopic list
 
/rosout
/rosout_agg
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose

 
si richiedono le info su un topic  
rostopic info /turtle1/cmd_vel 
 
Type: geometry_msgs/Twist
Publishers: None
Subscribers:
/turtlesim (http://...)



ed il formato dei messaggi
rosmsg show geometry_msgs/Twist
geometry_msgs/Vector3 linear
  float64 x
  float64 y
  float64 z
geometry_msgs/Vector3 angular
  float64 x
  float64 y
  float64 z



a questo punto si puo' muovere la tartaruga
rostopic pub /turtle1/cmd_vel geometry_msgs/Twist "{linear: {x: 3.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 2.0}}"
 
per lo spostamento assoluto 
rosservice call /turtle1/teleport_absolute 5 5 0

si puo' pilotare la tartaruga anche la pressione dei tasti usando  
rosrun turtlesim turtle_teleop_key 
 
a questo punto si inizia a modificare il container per impostarlo sul Phantomx Reactor 
sudo apt update
sudo apt install udev python3-serial 
 
a questo punto si inizia a preparare l'ambiente  ROS per il braccio robotico
 
cd /root/ws_catkin/src 
git clone https://github.com/vanadiumlabs/arbotix_ros.git
git clone https://github.com/RobotnikAutomation/phantomx_reactor_arm
git clone https://github.com/arebgun/dynamixel_motor.git
cd ..
 
i file su Github sono fatti per Python 2.7 mentre Ros NoEtic usa Python3 ...delle due l'una ... o si installa python2.7 o si modificano i files 
 
 
cd ~/ws_catkin/src/phantomx_reactor_arm/phantomx_reactor_arm_controller/src


sed -i '1s|/usr/bin/env python|/usr/bin/env python3|' *.py

chmod +x *.py
 
sed -i 's/except rospy\.ROSException, e:/except rospy.ROSException as e:/' phantomx_reactor_parallel_motor_joints.py
 
 
catkin_make
source devel/setup.bash
rospack profile
  
 
0.023993   /opt/ros/noetic/share
0.002395   /root/ws_catkin/src
0.000854   /root/ws_catkin/src/arbotix_ros
0.000626   /root/ws_catkin/src/dynamixel_motor
0.000614   /root/ws_catkin/src/phantomx_reactor_arm

se tutto va bene 
rospack list | grep arbotix
arbotix_controllers /root/ws_catkin/src/arbotix_ros/arbotix_controllers
arbotix_firmware /root/ws_catkin/src/arbotix_ros/arbotix_firmware
arbotix_msgs /root/ws_catkin/src/arbotix_ros/arbotix_msgs
arbotix_python /root/ws_catkin/src/arbotix_ros/arbotix_python
arbotix_sensors /root/ws_catkin/src/arbotix_ros/arbotix_sensors
rospack list | grep phantomx
phantomx_reactor_arm_controller /root/ws_catkin/src/phantomx_reactor_arm/phantomx_reactor_arm_controller
phantomx_reactor_arm_description /root/ws_catkin/src/phantomx_reactor_arm/phantomx_reactor_arm_description
phantomx_reactor_arm_moveit_config /root/ws_catkin/src/phantomx_reactor_arm/phantomx_reactor_arm_moveit_config


si prepara la porta USB
sudo cp phantomx_reactor_arm/phantomx_reactor_arm_controller/config/57-reactor_arbotix.rules /etc/udev/rules.d/
 
lanciare il comando 
udevadm info -a -n /dev/ttyUSB0 | grep serial
che risponde 
ATTRS{serial}=="AH06H0KT"

e quindi
sudo nano /etc/udev/rules.d/99-reactor.rules
e si copia 
SUBSYSTEM=="tty", ATTRS{serial}=="AH06H0KT", SYMLINK+="ttyUSB_REACTOR"

si aggiorna udev 
sudo service udev reload
sudo service udev restart
sudo udevadm trigger 

se persistono problemi (ovvero che non viene vista la porta USB_REACTOR) puo' essere forzata con 
 
ln -s /dev/ttyUSB0 /dev/ttyUSB_REACTOR

quasi pronti...si dovrebbe lanciare il comando 

roslaunch phantomx_reactor_arm_controller arbotix_phantomx_reactor_arm_wrist.launch&
 
a questo punto si possono testare le stringhe comando
 
 
rostopic pub /phantomx_reactor_controller/shoulder_yaw_joint/command std_msgs/Float64 "data: 0.0"
rostopic pub /phantomx_reactor_controller/shoulder_pitch_joint/command std_msgs/Float64 "data: 0.0"
rostopic pub /phantomx_reactor_controller/elbow_pitch_joint/command std_msgs/Float64 "data: 0.0"
rostopic pub /phantomx_reactor_controller/wrist_yaw_joint/command std_msgs/Float64 "data: 0.0"
rostopic pub /phantomx_reactor_controller/wrist_pitch_joint/command std_msgs/Float64 "data: 0.0"
rostopic pub /phantomx_reactor_controller/gripper_revolute_joint/command std_msgs/Float64 "data: 0.0"
rostopic pub /phantomx_reactor_controller/gripper_prismatic_joint/command std_msgs/Float64 "data: 0.0"
 
i valori sono espressi tutti in radianti e sono valori assoluti
per spostarsi dalla posizione neutra al +90 gradi si immette data:1.57, per tornare indietro di immette data:0.0 e NON data:-1.57 

Per impostare la velocita' (espressa in rad/s)
rosparam set /arbotix/joints/shoulder_yaw_joint/max_speed 0.5
 
 
 
Oltre ad usare il braccio si puo' usare l'emulazione ma si devono fare delle modifiche
nano ~/ws_catkin/src/phantomx_reactor_arm/phantomx_reactor_arm_moveit_config/launch/planning_context.launch

e si modifica la linea cambiando xacro.py a xacro
 
 <param if="$(arg load_robot_description)" name="$(arg robot_description)" command="$(find xacro)/xacro '$(find phantomx_reactor_arm_description)/robots/phantomx_reactor_arm_wrist.urdf.xacro'"/>

sudo apt update
sudo apt install ros-noetic-moveit
export RVIZ_PLUGIN_PATH=/opt/ros/noetic/lib


e si ricompila il ws_catkin

roslaunch phantomx_reactor_arm_moveit_config demo.launch

visto tutto il lavoro fatto e' il caso di salvare le impostazione tramite commit
si apre una nuova shell e si lancia
docker ps -a
si legge l'id e si lancia
 
docker commit b8a109b1fd3b braccio_robotico:latest
 
per riaprire 
docker run -it --net=host braccio_robotico:latest

si ricorda che ad ogni nuovo riavvio si deve lanciare 
source ~/ws_catkin/devel/setup.bash

rosservice list
/arbotix/SetupAnalogIn
/arbotix/SetupDigitalIn
/arbotix/SetupDigitalOut
/arbotix/get_loggers
/arbotix/set_logger_level
/elbow_pitch_joint/enable
/elbow_pitch_joint/relax
/elbow_pitch_joint/set_speed
/elbow_pitch_mimic_joint/enable
/elbow_pitch_mimic_joint/relax
/elbow_pitch_mimic_joint/set_speed
/gripper_revolute_joint/enable
/gripper_revolute_joint/relax
/gripper_revolute_joint/set_speed
/move_group/get_loggers
/move_group/planning_scene_monitor/set_parameters
/move_group/set_logger_level
/phantomx_reactor_controller/get_loggers
/phantomx_reactor_controller/set_logger_level
/phantomx_reactor_parallel_gripper/get_loggers
/phantomx_reactor_parallel_gripper/set_logger_level
/robot_state_publisher/get_loggers
/robot_state_publisher/set_logger_level
/rosout/get_loggers
/rosout/set_logger_level
/servos/enable_all
/servos/relax_all
/shoulder_pitch_joint/enable
/shoulder_pitch_joint/relax
/shoulder_pitch_joint/set_speed
/shoulder_pitch_mimic_joint/enable
/shoulder_pitch_mimic_joint/relax
/shoulder_pitch_mimic_joint/set_speed
/shoulder_yaw_joint/enable
/shoulder_yaw_joint/relax
/shoulder_yaw_joint/set_speed
/wrist_pitch_joint/enable
/wrist_pitch_joint/relax
/wrist_pitch_joint/set_speed
/wrist_roll_joint/enable
/wrist_roll_joint/relax
/wrist_roll_joint/set_speed
 
topics
/diagnostics
/elbow_pitch_joint/command
/elbow_pitch_mimic_joint/command
/gripper_revolute_joint/command
/joint_states
/move_group/planning_scene_monitor/parameter_descriptions
/move_group/planning_scene_monitor/parameter_updates
/phantomx_reactor_controller/elbow_pitch_joint/command
/phantomx_reactor_controller/gripper_prismatic_joint/command
/phantomx_reactor_controller/gripper_revolute_joint/command
/phantomx_reactor_controller/joint_command
/phantomx_reactor_controller/shoulder_pitch_joint/command
/phantomx_reactor_controller/shoulder_yaw_joint/command
/phantomx_reactor_controller/wrist_pitch_joint/command
/phantomx_reactor_controller/wrist_roll_joint/command
/rosout
/rosout_agg
/shoulder_pitch_joint/command
/shoulder_pitch_mimic_joint/command
/shoulder_yaw_joint/command
/tf
/tf_static
/wrist_pitch_joint/command
/wrist_roll_joint/command
 
 
per abilitare un asse
 

rosservice call /elbow_pitch_joint/enable "data: true"

 rostopic echo /joint_states

 

lunedì 9 giugno 2025

T-Dongle S3 ed IDF 5

Ho ripreso in mano il T-Dongle S3 di Lilygo ed i progetti IDF che sono presenti sul github ufficiale non funzionano piu' perche' la libreria LovyanGFX non risulta compatibile con IDF 5.x (il codice e' stato scritto per una versione precedente di IDF)


 

Ho provato a correggere ma alla fine ho preso un docker IDF 4.4 ed ho usato questo per compilare il progetto 

Importante: per mettere in modalita' programmazione la scheda si deve premere il pulsante e poi inserire la scheda nella porta USB.  Per avviare lo sketch la scheda deve essere rimossa e poi inserita

sudo apt update
sudo apt install docker.io
sudo systemctl enable docker --now
sudo usermod -aG docker $USER
newgrp docker

 

docker pull espressif/idf:release-v4.4

docker run --rm -it   --device=/dev/ttyACM0   -v ~/T-Dongle-S3:/project   -w /project   espressif/idf:release-v4.4 

 

 idf.py set-target esp32s3

 idf.py build

 

 

 

lunedì 4 novembre 2024

Dockerizza Flask

Un esempio semplice per inserire in un container Docker una applicazione Flask

Partiamo da una semplice applicazione che ha un file app.py ed un requirements.txt

Si crea nello stesso folder dei due files precedenti il Dockerfile

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

FROM python:3.8-slim-buster

WORKDIR /python-docker

COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt

COPY . .

CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"]

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

e si effettua la build con

docker build --tag flask-docker .

terminata la build del container

docker run -d -p 5000:5000 flask-docker

la applicazione sara' visibile su localhost:5000

mercoledì 9 ottobre 2024

Cron in Docker

E' possibile attivare un crontab all'interno di un docker aggiungendo al Dockerfile i seguenti comandi


RUN apt-get -y install cron 

RUN crontab -l | { cat; echo "0 3 * * * bash /root/mioscript.sh"; } | crontab - 

CMD cron

sabato 6 aprile 2024

Coral Mini dev board e rifiuti su spiaggia

Ho provato ad integrare il modello dei rifiuti su spiaggia visto qui e qui in Tensorflow lite per girare su Coral Mini Dev Board (basato su questo esempio)



Per prima cosa ho scaricato i dati in formato Pascal VOC (quindi con le annotations in formato xml) 

L'albero dei folder e' del tipo

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

dataset
    -train
        --images (solo jpg)
        --annotations (solo xml)
    -test
        --images
        --annotations
    -validation
        --images
        --annotations

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


Per questo motivo ho dovuto dividere i file rispetto al file zip scaricato da roboflow sono xml e jpg sono tutti nello stesso folder

Per fare il retrain ho usato il TF Lite Model Maker . Il problema e' che non ne vuole sapere di girare in Colab ed ho tirato su un Docker con il seguente Dockerfile

Inoltre TF Lite Model Maker effettua il retrain di modelli destinati a funzionare on edge e su mobile, in particolare usando EffiecientDet Lite 

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

FROM tensorflow/tensorflow:2.13.0-gpu

RUN apt-get update && \
    apt-get install -y libusb-1.0-0 libusb-1.0-0-dev

RUN pip install tflite-model-maker
RUN pip install pycocotools
 

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

lanciandolo con il comando

docker build -t litegpu .

docker run --gpus all -it -p  -v $PWD:/tmp -w /tmp litegpu bash

A questo punto si passa alla creazione vera e propria del modello con lo script python. Rispetto all'esempio di Colab, ho dovuto abbassare la batch size a 2 e rimuovere la validazione del modello altrimenti lo script satura tutta la memoria GPU

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

import numpy as np
import os

from tflite_model_maker.config import ExportFormat
from tflite_model_maker import model_spec
from tflite_model_maker import object_detector

import tensorflow as tf
assert tf.__version__.startswith('2')

tf.get_logger().setLevel('ERROR')
from absl import logging
logging.set_verbosity(logging.ERROR)


label_map = {1: 'Glass', 2: 'Metal',3: 'Net',4: 'null',5: 'PET_Bottle',6: 'Plastic_Buoy',7: 'Plastic_Buoy_China',8: 'Plastic_ETC',9: 'Rope',10: 'Styrofoam_Box',11: 'Styrofoam_Buoy',12: 'Styrofoam_Piece'}

train_images_dir = 'dataset/train/images'
train_annotations_dir = 'dataset/train/annotations'
val_images_dir = 'dataset/validation/images'
val_annotations_dir = 'dataset/validation/annotations'
test_images_dir = 'dataset/test/images'
test_annotations_dir = 'dataset/test/annotations'

train_data = object_detector.DataLoader.from_pascal_voc(train_images_dir, train_annotations_dir, label_map=label_map)
validation_data = object_detector.DataLoader.from_pascal_voc(val_images_dir, val_annotations_dir, label_map=label_map)
test_data = object_detector.DataLoader.from_pascal_voc(test_images_dir, test_annotations_dir, label_map=label_map)
print(f'train count: {len(train_data)}')
print(f'validation count: {len(validation_data)}')
print(f'test count: {len(test_data)}')


spec = object_detector.EfficientDetLite0Spec()
model = object_detector.create(train_data=train_data,
                               model_spec=spec,
                               validation_data=validation_data,
                               epochs=10,
                               batch_size=2,
                               train_whole_model=True)
#model.evaluate(test_data)
TFLITE_FILENAME = 'efficientdet-lite-litter.tflite'
LABELS_FILENAME = 'litter-labels.txt'
model.export(export_dir='.', tflite_filename=TFLITE_FILENAME, label_filename=LABELS_FILENAME,
             export_format=[ExportFormat.TFLITE, ExportFormat.LABEL])
model.evaluate_tflite(TFLITE_FILENAME, test_data)
-------------------------------------------------------------------------- 

con risultato finale

659 - loss: 0.8730 - learning_rate: 2.5257e-05 - gradient_norm: 5.0130 - val_det_loss: 0.6480 - val_cls_loss: 0.3706 - val_box_loss: 0.0055 - val_reg_l2_loss: 0.0659 - val_loss: 0.7139


Si potrebbe anche usare il modello 1 cambiando la linea

spec = object_detector.EfficientDetLite1Spec()

ma la mia scheda grafica non ha abbastanza memoria

Per verificare se il modello funziona si puo' all'interno del docker installare tramite pip

python3 -m pip install --extra-index-url https://google-coral.github.io/py-repo/ pycoral

e poi lanciare il comando lo script

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

from PIL import ImageDraw
from PIL import ImageFont
import PIL

import tflite_runtime.interpreter as tflite
from pycoral.adapters import common
from pycoral.adapters import detect
from pycoral.utils.dataset import read_label_file

def draw_objects(draw, objs, scale_factor, labels):
  """Draws the bounding box and label for each object."""
  COLORS = np.random.randint(0, 255, size=(len(labels), 3), dtype=np.uint8)
  for obj in objs:
    bbox = obj.bbox
    color = tuple(int(c) for c in COLORS[obj.id])
    draw.rectangle([(bbox.xmin * scale_factor, bbox.ymin * scale_factor),
                    (bbox.xmax * scale_factor, bbox.ymax * scale_factor)],
                   outline=color, width=3)
    font = ImageFont.truetype("LiberationSans-Regular.ttf", size=15)
    draw.text((bbox.xmin * scale_factor + 4, bbox.ymin * scale_factor + 4),
              '%s\n%.2f' % (labels.get(obj.id, obj.id), obj.score),
              fill=color, font=font)

# Load the TF Lite model
labels = read_label_file('./e0/litter-labels.txt')
interpreter = tflite.Interpreter('./e0/efficientdet-lite-litter.tflite')
interpreter.allocate_tensors()

# Resize the image for input
image = Image.open('./e0/1.jpg')
_, scale = common.set_resized_input(
    interpreter, image.size, lambda size: image.resize(size, PIL.Image.Resampling.LANCZOS))

# Run inference
interpreter.invoke()
objs = detect.get_objects(interpreter, score_threshold=0.4, image_scale=scale)

# Resize again to a reasonable size for display
display_width = 500
scale_factor = display_width / image.width
height_ratio = image.height / image.width
image = image.resize((display_width, int(display_width * height_ratio)))
draw_objects(ImageDraw.Draw(image), objs, scale_factor, labels)
image.save("output.jpg")

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

il risultato e' l'immagine di apertura del post

A questo punto si compilano i modelli per poter girare su Coral Dev Mini Board installando il compilatore sul PC

wget -O- https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/coral-edgetpu.gpg

apt-get update
apt-get install edgetpu-compiler

e poi lanciando la compilazione con

edgetpu_compiler efficientdet-lite-litter.tflite -d --num_segments=1

a questo punto si copiano i file del modello sulla Dev Board 

scp efficientdet-lite-litter_edgetpu.tflite mendel@192.168.100.2:/home/mendel

e si lancia

python3 detect_image.py --model efficientdet-lite-litter_edgetpu.tflite --labels litter-labels.txt --input CD_10196_jpg.rf.4a2b1adf824f2a18a7eea764b9012f36.jpg --output output.jpg


----INFERENCE TIME----
Note: The first inference is slow because it includes loading the model into Edge TPU memory.
347.37 ms
182.40 ms
181.49 ms
178.24 ms
182.33 ms
-------RESULTS--------
Styrofoam_Piece
  id:     11
  score:  0.453125
  bbox:   BBox(xmin=248, ymin=132, xmax=279, ymax=171)
PET_Bottle
  id:     4
  score:  0.4375
  bbox:   BBox(xmin=274, ymin=206, xmax=299, ymax=246)

 


Attenzione che la versione del runtime del compilatore deve essere compatibile con le librerie sulla Dev Board. In una prima prova avevo avuto l'errore

RuntimeError: Failed to prepare for TPU. Failed precondition: Package requires runtime version (14), which is newer than this runtime version (13).Node number 7 (EdgeTpuDelegateForCustomOp) failed to prepare.

ed infatti il comando  edgetpu_compiler --version rispondeva
Edge TPU Compiler version 16.0.384591198

mentre la runtime version era

python3 -c "import pycoral.utils.edgetpu; print(pycoral.utils.edgetpu.get_runtime_version())"
BuildLabel(COMPILER=6.3.0 20170516,DATE=redacted,TIME=redacted), RuntimeVersion(13)

Questo era dovuto al fatto che apt non scaricava gli aggiornamenti a causa della firma GPG scaduta dei repository Google Coral 

Il problema si e' risolto con

wget -O- https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/coral-edgetpu.gpg


venerdì 8 marzo 2024

Realsense Docker

Aggiornamento:

Il container e' disponibile gia' compilato su Docker.com al mio account

https://hub.docker.com/repository/docker/c1p81/realsense_2004/general 

per il pull

 docker pull c1p81/realsense_2004:latest

per aiblitare la porta USB si deve impostare il comando come segue

sudo docker run -d  --net=host --env="DISPLAY" --volume="$HOME/.Xauthority:/root/.Xauthority:rw"   -v /dev:/dev    --device-cgroup-rule "c 81:* rmw"     --device-cgroup-rule "c 189:* rmw" --privileged -v /dev/bus/usb:/dev/bus/usb  b105279d1264 realsense-viewer

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

Ho deciso di tirare fuori dal cassetto la D415 Realsense e come al solito montare l'SDK diventa sempre piu' difficile a causa delle politiche di Intel di dismissione dei propri dispositivi


 

Stavolta volevo provare la strada dell'ambiente docker ma ne' il container ufficiale ne' alcuni trovati su docker hub risultavano completamente funzionanti e me lo sono scritto da solo

(da modificare l'image_id)

Bash

docker run -it --rm  --privileged  -v /dev:/dev  -v "$HOME:/home/luca/"   --device-cgroup-rule "c 81:* rmw"     --device-cgroup-rule "c 189:* rmw"   b105279d1264 /bin/bash

Realsense Viewer

xhost +

docker run -d  --net=host --env="DISPLAY" --volume="$HOME/.Xauthority:/root/.Xauthority:rw"   -v /dev:/dev    --device-cgroup-rule "c 81:* rmw"     --device-cgroup-rule "c 189:* rmw"   2bd94ff6bc38 realsense-viewer

 

Save to disk

docker run -it --rm --privileged    -v /dev:/dev  -v "$HOME:/home/luca/"   --device-cgroup-rule "c 81:* rmw"     --device-cgroup-rule "c 189:* rmw"   34ea465a203e sh -c "cd /home/luca && rs-save-to-disk"

per creare il docker si usa il comando

docker build -t 20_04_real .

con il seguente Dockerfile


FROM public.ecr.aws/lts/ubuntu:20.04_stable

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update \
&& apt-get install -qq -y --no-install-recommends \
build-essential \
cmake \
lsb-release \
git \
curl \
libssl-dev \
libusb-1.0-0-dev \
pkg-config \
libudev-dev \
libgtk-3-dev \
libglfw3-dev \
libgl1-mesa-dev \
libglu1-mesa-dev \
curl \
python3 \
python3-dev \
python3-pip \
libopencv-dev \
python3-opencv \
python3-numpy \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*


RUN mkdir -p /etc/apt/keyrings
RUN curl -sSf https://librealsense.intel.com/Debian/librealsense.pgp | tee /etc/apt/keyrings/librealsense.pgp > /dev/null


RUN echo "deb [signed-by=/etc/apt/keyrings/librealsense.pgp] https://librealsense.intel.com/Debian/apt-repo `lsb_release -cs` main" | tee /etc/apt/sources.list.d/librealsense.list
RUN apt-get update


RUN apt-get -y install librealsense2-dkms librealsense2-utils librealsense2-dev librealsense2-dbg librealsense2-udev-rules mc nano locales
RUN apt-get clean
RUN pip install pyrealsense2

RUN git clone https://github.com/IntelRealSense/librealsense
RUN cd librealsense
RUN mkdir /librealsense/build
WORKDIR /librealsense/build
RUN cmake ../ -DBUILD_EXAMPLES=true
RUN make

giovedì 28 dicembre 2023

Docker Compose esempio

 In ufficio stanno spingendo per utilizzare docker per ogni applicazione

Per rendere lo sviluppo piu' tracciabile viene richiesto che oltre al docker file vi sia anche il file yaml di docker compose (in pratica le impostazioni del container che si dovrebbero passare sulla linea di comando sono scritti nel file compose.yaml

con build . (punto) viene indicato di usare il dockerfile compreso nello stesso folder

Per lanciare si usa

docker compose up -d

alla fine della costruzione dell'immagine viene fatto in automatico lo start

Si accede quindi con

docker exec -it Omnia bash

si termina con

docker compose stop

version: '3'

services:
omnia_apuane:
build: .
container_name: Omnia
ports:
- "9192:80"
dns:
- "10.100.1.3"
environment:
- HOST=omnia
- VIRTUAL_HOST=omnia.aaaa.aaaa.it
- VIRTUAL_PROTO=http
- VIRTUAL_PORT=80
- TZ=Europe/Rome
restart: always
network_mode: bridge

mercoledì 8 novembre 2023

R 3.6 docker personalizzato

 Un esempio di Dockerfile complesso per R 3.6



FROM rstudio/r-base:3.6-bookworm

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get -y update
RUN apt-get -y install gdal-bin libgdal-dev libpng-dev libudunits2-dev libfontconfig1-dev libmagick++-dev openjdk-17-jdk apache2 mc nano locales && apt-get clean




RUN service apache2 restart


#ENTRYPOINT ["/usr/sbin/apache2", "-k", "start"]
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
EXPOSE 80
CMD ["apachectl", "-D", "FOREGROUND"]

CMD apachectl -D FOREGROUND

# installa client Oracle
RUN wget https://download.oracle.com/otn_software/java/sqldeveloper/sqlcl-23.2.0.178.1027.zip && unzip sqlcl*.zip
ENV PATH=sqlcl/bin:$PATH


#imposta la localizzazione italiana
RUN sed -i -e 's/# it_IT.UTF-8 UTF-8/it_IT.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
ENV LANG it_IT.UTF-8
ENV LANGUAGE it_IT:it
ENV LC_ALL it_IT.UTF-8

# imposta la timezone a Europe/Rome
ENV TZ="Europe/Rome"

# scarica il sorgente della libreria non presente su CRAN
RUN curl -O "https://cran.r-project.org/src/contrib/Archive/randomForest/randomForest_4.6-10.tar.gz"
#setup R configs
RUN echo "r <- getOption('repos'); r['CRAN'] <- 'http://cran.us.r-project.org'; options(repos = r);" > ~/.Rprofile
RUN Rscript -e "install.packages('zoo')"
RUN Rscript -e "install.packages('leaflet')"
RUN Rscript -e "install.packages('sf')"
RUN Rscript -e "install.packages('leafpop')"
RUN Rscript -e "install.packages('forecast')"
RUN Rscript -e "install.packages('stringr')"
RUN Rscript -e "install.packages('lubridate')"
RUN Rscript -e "install.packages('randomForest_4.6-10.tar.gz', repos = NULL, type='source')"
RUN Rscript -e "install.packages('rpart')"
RUN Rscript -e "install.packages('e1071')"
RUN Rscript -e "install.packages('kknn')"
RUN Rscript -e "install.packages('jpeg')"
RUN Rscript -e "install.packages('data.table')"
RUN Rscript -e "install.packages('tidyr')"
RUN Rscript -e "install.packages('magick')"
RUN Rscript -e "install.packages('leaflet.extras')"
RUN Rscript -e "install.packages('leafem')"
RUN Rscript -e "install.packages('raster')"

# copia i file
ADD go.sh /root/go.sh
ADD omnia_apuane_spool.sql /root/omnia_apuane_spool.sql
ADD omnia_apuane.R /root/omnia_apuane.R
ADD omnia_arno.R /root/omnia_arno.R
ADD omnia_laguna.R /root/omnia_laguna.R

#crea folders in html
RUN mkdir /var/www/html/mappe
RUN mkdir /var/www/html/mappe/omnia_apuane
RUN mkdir /var/www/html/Acque
RUN mkdir /var/www/html/Acque/LAGUNA
RUN mkdir /var/www/html/Acque/ARNO
RUN mkdir /var/www/html/Acque/ARNO/bollettini


# per il ROracle
ADD instantclient-basic-linux.x64-21.11.0.0.0dbru.zip instantclient-basic-linux.x64-21.11.0.0.0dbru.zip
ADD instantclient-sdk-linux.x64-21.11.0.0.0dbru.zip instantclient-sdk-linux.x64-21.11.0.0.0dbru.zip
# ATTENZIONE il comando ADD decompatta in automatico
# i file tar.gz. Per questo motivo la riga successiva usa COPY
COPY ROracle_1.3-2_R_x86_64-linux-gnu.tar.gz /root/ROracle_1.3-2_R_x86_64-linux-gnu.tar.gz

RUN unzip instantclient-basic-linux.x64-21.11.0.0.0dbru.zip -d /opt/oracle/
RUN unzip instantclient-sdk-linux.x64-21.11.0.0.0dbru.zip -d /opt/oracle/

RUN apt-get install -y libaio1
ENV PATH="${PATH}:/opt/oracle/instantclient_21_11"
ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/opt/oracle/instantclient_21_11"

RUN ldconfig

# compila ROracle
RUN Rscript -e 'install.packages("/root/ROracle_1.3-2_R_x86_64-linux-gnu.tar.gz",repos=NULL,type="source")'
RUN Rscript -e "install.packages('RCurl')"
RUN Rscript -e "install.packages('stringr')"


#cancella i file temporanei
RUN rm randomForest_4.6-10.tar.gz
RUN rm sqlcl*.zip
RUN rm /root/*.tar.gz
RUN rm /root/*.zip

Docker pull via http_proxy

 la configurazione del proxy per effettuare un pull di un container docker si trova in

/etc/systemd/system/docker.service.d/http-proxy.conf

ed ha una sintassi del tipo

[Service]
Environment="HTTP_PROXY=http://proxy.aaaaaaaaaa.it:8080"
Environment="HTTPS_PROXY=http://proxy.aaaaaaaaaa.it:8080"

per rendere effettive le modifiche 

systemctl stop docker

systemctl stop docker.socket

systemctl daemon-reload

systemctl start docker

martedì 17 ottobre 2023

Small docker for Golang apps

 In ufficio oramai una applicazione non puo' andare in produzione se non e' in in container...anche se e' occupa pochissimo spazio disco...il che vuol dire che si deve cercare di ottimizzare l'occupazione dello spazio disco del container

Nel Dockerfile sottostante viene utilizzato un docker con compilatore per generare un eseguibile che sara' poi copiato in un docker minimale di produzione basato su Alpine



FROM golang as builder
RUN mkdir /app
COPY . /app
WORKDIR /app
RUN https_proxy=http://proxy.toscana.it:8080 go get github.com/go-resty/resty/v2
RUN https_proxy=http://proxy.toscana.it:8080 go get github.com/sijms/go-ora/v2

RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o myapp .

FROM alpine:latest

RUN apk --no-cache add ca-certificates
WORKDIR /root
COPY --from=builder /app/myapp .

Aggiornamento algoritmi di spectral unmxing

Durante il dottorato avevo provato a fare unmixing di suoli naturali Una discreta serie di campioni di suolo naturale era stato raccolto in ...