giovedì 28 novembre 2024

Arduino logger low power

Aggiornamento:

ho interrotto l'esperimento prima della fine effettiva della batteria

L'Arduino e' rimasta attiva dalle 8:37 del 1/11/2024 alle 8:50 del 15/12/2024 partendo da circa 4.3 V per terminare a 3.91 V ed ha effettuato 31424 misure dal sensore di torbidita'

Al di sotto il grafico di scarica



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

 

Alla fine ci sono riuscito

La arduino MKR zero e' ormai da un mese che e' rimasta accesa sul tavolo...o meglio si attiva ogni minuto, legge il pin 0, legge lo stato della carica della batteria, scrive sulla Sd card e si addormenta in deep sleep

la batteria da 6600 mAh e' costituita da 18650

 


 

 

#include "ArduinoLowPower.h"
#include <SD.h>
#include <RTCZero.h>

RTCZero rtc;

/* Change these values to set the current initial time */
const byte seconds = 00;
const byte minutes = 05;
const byte hours = 14;

/* Change these values to set the current initial date */
const byte day = 01;
const byte month = 11;
const byte year = 24;


const int chipSelect = SDCARD_SS_PIN;
int i;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  delay(1000);
  SD.begin(chipSelect);

  rtc.begin(); // initialize RTC
  rtc.setHours(hours);
  rtc.setMinutes(minutes);
  rtc.setSeconds(seconds);
  rtc.setDay(day);
  rtc.setMonth(month);
  rtc.setYear(year);

}

void loop() {
  if (i == 60) {
              digitalWrite(LED_BUILTIN, HIGH);
              delay(500);
              digitalWrite(LED_BUILTIN, LOW);
              delay(500);

              int batteria = analogRead(ADC_BATTERY);
              float voltage = batteria * (4.3 / 1023.0);
              if (voltage < 3.9)
                {
                 for (i=1;i<10;i++)
                 {
                  digitalWrite(LED_BUILTIN, HIGH);
                  delay(50);
                  digitalWrite(LED_BUILTIN, LOW);
                  delay(50);
                }
              }
            
              File dataFile = SD.open("data.txt", FILE_WRITE);

              int sensor = analogRead(0);
              String anno = String(rtc.getYear());
              String mese = String(rtc.getMonth());
              String giorno = String(rtc.getDay());
              String ora = String(rtc.getHours());
              String minuto = String(rtc.getMinutes());
              String secondo = String(rtc.getSeconds());

              if (mese.length() == 1) {mese = "0"+ mese;}
              if (giorno.length() == 1) {giorno = "0"+ giorno;}
              if (ora.length() == 1) {ora = "0"+ ora;}
              if (minuto.length() == 1) {minuto = "0"+ minuto;}
              if (secondo.length() == 1) {secondo = "0"+ secondo;}
             
              if (dataFile) {
                dataFile.println(anno+"/"+mese+"/"+giorno+"-"+ora+":"+minuto+":"+secondo+";"+String(sensor)+";"+String(voltage));
                dataFile.close();
                }
              i = 0;
              }
  i++;
  LowPower.sleep(1000);
}

Turn On raspberry via GPIO

 Per accenderere una Raspberry e' sufficiente mettere allo stato zero il pin GPIO3..quindi basta collegare con un cavo (non in maniera permanente) il pin GPIO ed un pin GND


 


 

 

mercoledì 13 novembre 2024

Update Plotly Dash Csv

 

 


from dash import Dash, html, dcc, callback, Output, Input,State
import plotly.express as px
import pandas as pd

import sqlite3
df = pd.read_csv('./sir.csv')


#cnx = sqlite3.connect('winet.db')
#df = pd.read_sql_query("SELECT * FROM sensori", cnx)


app = Dash(__name__)

app.layout = [
html.H1(children='Sensori', style={'textAlign':'center'}),
html.Div([
dcc.Graph(id='graph-content',
figure={
'data': [
{'x': df.Data, 'y': df.Livello,
'type': 'line', 'name': '68'},
],
'layout': {
'title': 'Soggiacenza'
}
}),
dcc.Interval(
id='interval-component',
interval=2*1000,
n_intervals=0
)
])
]

@app.callback(
Output(component_id='graph-content', component_property='figure'),
Input('interval-component', 'n_intervals'), [State('graph-content', 'figure')]
)

def update_graph(n,figure):
df = pd.read_csv('./sir.csv')
figure['data'][0]['x'] = df.Data
figure['data'][0]['y'] = df.Livello
return figure


if __name__ == '__main__':
app.run(debug=True)

 

martedì 5 novembre 2024

Alpine Linux 2024 su IBM A31

Ho provato a far resuscitare un IBM A31 destinato alla discarica. La macchina ha processore P4, 256 Mb di RAM, la batteria CMOS morta ed e' data 2002 (ps non ha trackpad)

La scelta e' caduta su Alpine Linux. Si puo' fare il boot direttamente da USB ed ho installato l'opzione SYS




l'idea era di avere una macchina con GCC ed X con I3 (attenzione che la tastiera del portatile non ha il tasto Windows quindi quando si configura I3 si deve fare la giusta scelta come tasto modificatore)

Questi sono i comandi per la configurazione

apk add --update alpine-sdk

setup-xorg-base

apk add emacs mc

apk add xf86-video-fbdev xf86-video-vesa font-terminus dbus

dbus-uuidgen > /var/lib/dbus/machine-id

rc-update add dbus

apk add i3wm i3status xterm

addgroup luca input

addgroup luca video

startx /usr/bin/i3


il sistema con la sola consolle occupa circa 159 Mb di RAM, il disco fisso da 20 Gb e' occupato per circa il 5%

alla fine e' ancora una macchina usabile



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

venerdì 1 novembre 2024

Misuratore di torbidita' TS-300B

Gia' siamo partiti male....ordinato su Aliexpress (costato 1/3 rispetto ad Amazon) ed il cavo di collegamento ha 3 pin....

 


 mentre il connettore sulla scheda ha 4 pin (ed ovviamente il cavo non entra)

 


Il problema e' dal lato scheda ... sulla scheda i pin sono nominati ADVG (dall'alto verso il basso) per l'ingresso del TS-300B e GTV per il lato di connessione verso Arduino

 


incrociando le informazioni con altre schede simili il pinout e'

A = analog input

D = soglia digitale level output

V = Power Positive

G = GND

mentre per il lato arduino

G = GND

T = segnale

V = Vcc  (e' un sensore che deve essere alimentato a 5 V)

Il sensore ha due led L2 che mostra la presenza di alimentazione ed il led L1 che si illumina quando si raggiunge la soglia di tordibita'

Il funzionamento e' semplice...da un lato c'e' un led IR e dall'altro un ricevitore...a seconda di quanta luce arriva al ricevitore viene stimata la torbidita'...visto cio' il sensore e' sensibile alla luce ambientale (deve quindi lavorare al buio ancora meglio dentro ad un tubo)


Leggendo ho trovato che questo tipo di sensori vengono usati in lavastoviglie


 

 

 

 

 

mercoledì 30 ottobre 2024

Polarita' Lipo e JST

Ho imparato a mie spese che non tutte le batterie LiPo hanno la polarita' connessa nello stesso modo al connettore JST

Come si vede nella foto sottostante una LiPo e' connessa in modo corretto ad una Arduino MKR (positivo a sinistra) Nella stessa foto si vede il connettore di un'altra batteria con positivo a destra ...e meno male che non si' bruciata la scheda


In ogni caso i connettori JST con un po' di pazienza di possono smontare ed invertire i cavi

lunedì 21 ottobre 2024

Change detection monocular metric

Ho provato ad usare la rete di neurale a questo indirizzo https://github.com/apple/ml-depth-pro per ottenere una mappa di profondita' da un unico jpg

 Questa l'immagine di partenza


con una NVidia 4070 l'elaborazione e' inferiore al secondo e questo il risultato
 

La rete viene definita metrica ma i risultati sono lontanissimi dalle misure reali degli oggetti fotografati

Se si prendono due immagini distanti nel tempo



 si puo' calcolare la differenza delle distanze ed eventuali cambiamenti

 Una volta ottenuta la mappa di profondita' e' possibile avere anche la nuvola dei punti utilizzando il seguente programmino in Python

import open3d as o3d
import sys

a23 = np.load("agosto23.npz")
a24 = np.load("agosto24.npz")
dd = a24['depth']-a23['depth']

plt.imshow(dd, interpolation='nearest',cmap='plasma')
plt.colorbar()
#plt.show()
plt.savefig('grafico.png',dpi=600)


#versione O3D
depth = o3d.geometry.Image(a23['depth'])
print("Prof"+str(np.shape(depth)))
color = o3d.io.read_image("rgb.jpg")
print(np.shape(color))

rgbd = o3d.geometry.RGBDImage.create_from_color_and_depth(color, depth,convert_rgb_to_intensity = False)
intrinsic = o3d.camera.PinholeCameraIntrinsic(width=3840, height=2160, fx=2520.7, fy=2518.2, cx=1918, cy=1022)

pcd = o3d.geometry.PointCloud.create_from_rgbd_image(rgbd, intrinsic)
pcd.transform([[1,0,0,0],[0,-1,0,0],[0,0,-1,0],[0,0,0,1]])
o3d.visualization.draw_geometries([pcd])
o3d.io.write_point_cloud("nuvola2.ply", pcd)


questo il risultato






 

 

 

 

 


lunedì 14 ottobre 2024

Arduino 2009 dal passato

 Aprendo un cassetto e' saltato fuori questo progetto del 2010


Non si vede benissimo ma e' una Arduino 2009 (probabilmente un clone)

Inner Join con Pandas

 Avevo la necessita' di unire due file csv (misura di tempo; misura del sensore) ma i due sensori hanno avuto dei fermi per cui non era sufficiente mettere le colonne affiancate ed era necessaria una inner join (ma sulla macchine di lavoro non ho accesso un sql server) ..sono oltre 85000 dati quindi e' escluso fare a mano

La libreria Pandas e' venuta in aiuto




CSV Portata

tempo;valore
38923.54;37
38923.58;36
38923.63;36
38923.67;36

CSV Tordibita

tempo;valore
38923.54;0
38923.58;0


import pandas as pd
from matplotlib import pyplot as plt

por = pd.read_csv('portata.csv',sep=';')
tor = pd.read_csv('torbidita.csv',sep=';')
por['tempo'] = por['tempo'].astype(str)
tor['tempo'] = tor['tempo'].astype(str)

unione = por.merge(tor, on="tempo", how='inner')
unione.plot(
x='valore_x',
xlabel='Portata',
y='valore_y',
ylabel='Torbidita',
title= '25/07/06 - 27/02/2017',
kind='scatter'
)
plt.show()
#unione.to_csv("unione.csv", sep=';')


venerdì 11 ottobre 2024

Aruco e Image Stacking

Uno dei problemi maggiori dell'uso dei tag aruco in esterno per misurare distanze e' che le condizioni di illuminazione solare sono molto variabili e la compressione jpg completa l'opera aggiungendo rumore su rumore

Per cercare di limitare il problema ho provato a fare image stacking sovrapponendo 8 foto (una ogni ora dalle 09 alle 16) con lo script al link https://github.com/maitek/image_stacking ed applicando il programma visto qui


Il miglioramento non e' trascurabile perche' la standard deviation e' passata

3.1 m => da 0.19% a 0.16% (0.5 cm)

5.4 m => da 0.35% a 0.28% (1.5 cm)

7.6 m => da 0.71% a 0.38% (2.8 cm)

9.6 m => da 0.5% a 0.41% (4.8 cm)

 

import os
import cv2
import numpy as np
from time import time



# Align and stack images with ECC method
# Slower but more accurate
def stackImagesECC(file_list):
M = np.eye(3, 3, dtype=np.float32)

first_image = None
stacked_image = None

for file in file_list:
image = cv2.imread(file,1).astype(np.float32) / 255
print(file)
if first_image is None:
# convert to gray scale floating point image
first_image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
stacked_image = image
else:
# Estimate perspective transform
s, M = cv2.findTransformECC(cv2.cvtColor(image,cv2.COLOR_BGR2GRAY), first_image, M, cv2.MOTION_HOMOGRAPHY)
w, h, _ = image.shape
# Align image to first image
image = cv2.warpPerspective(image, M, (h, w))
stacked_image += image

stacked_image /= len(file_list)
stacked_image = (stacked_image*255).astype(np.uint8)
return stacked_image


# Align and stack images by matching ORB keypoints
# Faster but less accurate
def stackImagesKeypointMatching(file_list):

orb = cv2.ORB_create()

# disable OpenCL to because of bug in ORB in OpenCV 3.1
cv2.ocl.setUseOpenCL(False)

stacked_image = None
first_image = None
first_kp = None
first_des = None
for file in file_list:
print(file)
image = cv2.imread(file,1)
imageF = image.astype(np.float32) / 255

# compute the descriptors with ORB
kp = orb.detect(image, None)
kp, des = orb.compute(image, kp)

# create BFMatcher object
matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

if first_image is None:
# Save keypoints for first image
stacked_image = imageF
first_image = image
first_kp = kp
first_des = des
else:
# Find matches and sort them in the order of their distance
matches = matcher.match(first_des, des)
matches = sorted(matches, key=lambda x: x.distance)

src_pts = np.float32(
[first_kp[m.queryIdx].pt for m in matches]).reshape(-1, 1, 2)
dst_pts = np.float32(
[kp[m.trainIdx].pt for m in matches]).reshape(-1, 1, 2)

# Estimate perspective transformation
M, mask = cv2.findHomography(dst_pts, src_pts, cv2.RANSAC, 5.0)
w, h, _ = imageF.shape
imageF = cv2.warpPerspective(imageF, M, (h, w))
stacked_image += imageF

stacked_image /= len(file_list)
stacked_image = (stacked_image*255).astype(np.uint8)
return stacked_image

# ===== MAIN =====
# Read all files in directory
import argparse


if __name__ == '__main__':

parser = argparse.ArgumentParser(description='')
parser.add_argument('input_dir', help='Input directory of images ()')
parser.add_argument('output_image', help='Output image name')
parser.add_argument('--method', help='Stacking method ORB (faster) or ECC (more precise)')
parser.add_argument('--show', help='Show result image',action='store_true')
args = parser.parse_args()

image_folder = args.input_dir
if not os.path.exists(image_folder):
print("ERROR {} not found!".format(image_folder))
exit()

file_list = os.listdir(image_folder)
file_list = [os.path.join(image_folder, x)
for x in file_list if x.endswith(('.jpg', '.png','.bmp'))]

if args.method is not None:
method = str(args.method)
else:
method = 'KP'

tic = time()

if method == 'ECC':
# Stack images using ECC method
description = "Stacking images using ECC method"
print(description)
stacked_image = stackImagesECC(file_list)

elif method == 'ORB':
#Stack images using ORB keypoint method
description = "Stacking images using ORB method"
print(description)
stacked_image = stackImagesKeypointMatching(file_list)

else:
print("ERROR: method {} not found!".format(method))
exit()

print("Stacked {0} in {1} seconds".format(len(file_list), (time()-tic) ))

print("Saved {}".format(args.output_image))
cv2.imwrite(str(args.output_image),stacked_image)

# Show image
if args.show:
cv2.imshow(description, stacked_image)
cv2.waitKey(0)

 

 

 

 

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

mercoledì 2 ottobre 2024

Aruco Tag e filtri Kalman

Usando gli Aruco tag in ambiente esterno con illuminazione solare a diverse ore e in diversi periodi dell'anno ho trovato un errore nella stima della distanza tra due tag compresi tra 0.7% e 1.3% della distanza misurata. La domanda e' stata: e' possibile ridurre l'errore ?

Ho provato ad applicare il filtro Kalman per condizioni statiche (le distanze tra i tag nel tempo non sono variate) usando usando il codice a questo indirizzo 


Nel  grafico sottostante i punti blu sono i dati non filtrati, in linea continua blu i dati filtrati, in linea rossa il valore reale della misura di distanza

questo il codice impiegato con modestissime modifiche rispetto a quello di esempio

 

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd



def kalman_1d(x, P, measurement, R_est, Q_est):
x_pred = x
P_pred = P + Q_est
K = P_pred / (P_pred + R_est)
x_est = x_pred + K * (measurement - x_pred)
P_est = (1 - K) * P_pred
return x_est, P_est


def plot_1d_comparison(measurements_made, estimate, true_value, axis):
axis.plot(measurements_made ,'k+' ,label='measurements' ,alpha=0.3)
axis.plot(estimate ,'-' ,label='KF estimate')
if not isinstance(true_value, (list, tuple, np.ndarray)):
# plot line for a constant value
axis.axhline(true_value ,color='r' ,label='true value', alpha=0.5)
else:
# for a list, tuple or array, plot the points
axis.plot(true_value ,color='r' ,label='true value', alpha=0.5)
axis.legend(loc = 'lower right')
axis.set_title('Estimated position vs. time step')
axis.set_xlabel('Time')
axis.set_ylabel('$x_t$')

def plot_1d_error(estimated_error, lower_limit, upper_limit, axis):
# lower_limit and upper_limit are the lower and upper limits of the vertical axis
axis.plot(estimated_error, label='KF estimate for $P$')
axis.legend(loc = 'upper right')
axis.set_title('Estimated error vs. time step')
axis.set_xlabel('Time')
axis.set_ylabel('$P_t$')
plt.setp(axis ,'ylim' ,[lower_limit, upper_limit])


nome_file = "20_40"
df = pd.read_csv(nome_file+'.csv',header=0,sep=";")

#11 5.38
#15 3.39
#25 7.46
#40 4.26

mu = 4.26 # Actual position
R = 0.1 # Actual standard deviation of actual measurements (R)

# Generate measurements
#n_measurements = 1000 # Change the number of points to see how the convergence changes
#Z = np.random.normal(mu, np.sqrt(R), size=n_measurements)
Z = df[df.columns[2]].to_numpy()
# Estimated covariances
Q_est = 1e-4
R_est = 2e-2

# initial guesses
x = 5.1 # Use an integer (imagine the initial guess is determined with a meter stick)
P = 0.04 # error covariance P

KF_estimate=[] # To store the position estimate at each time point
KF_error=[] # To store estimated error at each time point
for z in Z:
x, P = kalman_1d(x, P, z, R_est, Q_est)
KF_estimate.append(x)
KF_error.append(P)

fig, axes = plt.subplots(1 ,2, figsize=(12, 5))
plot_1d_comparison(Z, KF_estimate, mu, axes[0])
np.savetxt(nome_file+"_stima.csv",KF_estimate)
plot_1d_error(KF_error, 0, 0.015, axes[1])
plt.tight_layout()
plt.savefig(nome_file+'.png')

 

 

 

 

venerdì 27 settembre 2024

Opencv camera calibration in cpp

Oltre che con uno script Python come visto qui la calibrazione della camera si puo' fare anche con il programma in CPP

Questo il procedimento per compilare il programma partendo dai sorgenti

 

git clone https://github.com/opencv/opencv

git clone https://github.com/opencv/opencv_contrib

 

sudo cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D OPENCV_ENABLE_NONFREE=ON \
-D INSTALL_C_EXAMPLES=ON \
-D INSTALL_PYTHON_EXAMPLES=ON \
-D OPENCV_GENERATE_PKGCONFIG=ON \
-D OPENCV_PC_FILE_NAME=opencv.pc \
-D OPENCV_GENERATE_PKCONFIG=ON \
-D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \
-D PYTHON_EXECUTABLE=/usr/bin/python3 \
-D PYTHON_DEFAULT_EXECUTABLE=$(which python3) .. \
-D BUILD_EXAMPLES=ON  \
-D BUILD_opencv_apps=ON  \
-DBUILD_opencv_gapi:BOOL=OFF
-D BUILD_DOCS=ON \
..

 

sudo make install 

export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib

 

si naviga fino al folder

/opencv/samples/cpp/tutorial_code/calib3d/camera_calibration 

e si digita il comando

g++ -ggdb camera_calibration.cpp -o camera_calibration `pkg-config --cflags --libs opencv`

per il funzionamento del programma occorrono due file xml, il primo con le impostazioni ed il secondo con l'elenco delle immagini di calibrazione

camera_calibration -d parametri.xml

parametri.xml

<?xml version="1.0"?>
<opencv_storage>
<Settings>
<!-- Number of inner corners per a item row and column. (square, circle) -->
<BoardSize_Width>9</BoardSize_Width>
<BoardSize_Height>4</BoardSize_Height>
<!-- The size of a square in some user defined metric system (pixel, millimeter)-->
<Square_Size>0.115</Square_Size>
<Marker_Size>0.090</Marker_Size>
<!-- The type of input used for camera calibration. One of: CHESSBOARD CHARUCOBOARD CIRCLES_GRID ASYMMETRIC_CIRCLES_GRID -->
<Calibrate_Pattern>"CHARUCOBOARD"</Calibrate_Pattern>
<ArUco_Dict_Name>DICT_4X4_250</ArUco_Dict_Name>
<ArUco_Dict_File_Name></ArUco_Dict_File_Name>
<!-- The input to use for calibration.
To use an input camera -> give the ID of the camera, like "1"
To use an input video -> give the path of the input video, like "/tmp/x.avi"
To use an image list -> give the path to the XML or YAML file containing the list of the images, like "/tmp/circles_list.xml"
-->
<Input>"elenco_foto.xml"</Input>
<!-- If true (non-zero) we flip the input images around the horizontal axis.-->
<Input_FlipAroundHorizontalAxis>0</Input_FlipAroundHorizontalAxis>
<!-- Time delay between frames in case of camera. -->
<Input_Delay>100</Input_Delay>
<!-- How many frames to use, for calibration. -->
<Calibrate_NrOfFrameToUse>25</Calibrate_NrOfFrameToUse>
<!-- Consider only fy as a free parameter, the ratio fx/fy stays the same as in the input cameraMatrix.
Use or not setting. 0 - False Non-Zero - True-->
<Calibrate_FixAspectRatio> 1 </Calibrate_FixAspectRatio>
<!-- If true (non-zero) tangential distortion coefficients are set to zeros and stay zero.-->
<Calibrate_AssumeZeroTangentialDistortion>1</Calibrate_AssumeZeroTangentialDistortion>
<!-- If true (non-zero) the principal point is not changed during the global optimization.-->
<Calibrate_FixPrincipalPointAtTheCenter> 1 </Calibrate_FixPrincipalPointAtTheCenter>
<!-- The name of the output log file. -->
<Write_outputFileName>"parametri_camera.xml"</Write_outputFileName>
<!-- If true (non-zero) we write to the output file the feature points.-->
<Write_DetectedFeaturePoints>1</Write_DetectedFeaturePoints>
<!-- If true (non-zero) we write to the output file the extrinsic camera parameters.-->
<Write_extrinsicParameters>1</Write_extrinsicParameters>
<!-- If true (non-zero) we write to the output file the refined 3D target grid points.-->
<Write_gridPoints>1</Write_gridPoints>
<!-- If true (non-zero) we show after calibration the undistorted images.-->
<Show_UndistortedImage>1</Show_UndistortedImage>
<!-- If true (non-zero) will be used fisheye camera model.-->
<Calibrate_UseFisheyeModel>0</Calibrate_UseFisheyeModel>
<!-- If true (non-zero) distortion coefficient k1 will be equals to zero.-->
<Fix_K1>0</Fix_K1>
<!-- If true (non-zero) distortion coefficient k2 will be equals to zero.-->
<Fix_K2>0</Fix_K2>
<!-- If true (non-zero) distortion coefficient k3 will be equals to zero.-->
<Fix_K3>0</Fix_K3>
<!-- If true (non-zero) distortion coefficient k4 will be equals to zero.-->
<Fix_K4>1</Fix_K4>
<!-- If true (non-zero) distortion coefficient k5 will be equals to zero.-->
<Fix_K5>1</Fix_K5>
</Settings>
</opencv_storage>


elenco_foto.xml

<?xml version="1.0"?>
<opencv_storage>
<images>
hikvision/01.jpg
hikvision/02.jpg
hikvision/03.jpg
hikvision/04.jpg
hikvision/05.jpg
hikvision/06.jpg
hikvision/07.jpg
hikvision/08.jpg
hikvision/09.jpg
hikvision/10.jpg
hikvision/11.jpg
hikvision/12.jpg
hikvision/13.jpg
hikvision/14.jpg
hikvision/15.jpg
hikvision/16.jpg
</images>
</opencv_storage>





Debug OpenCV Cpp con VIsual Code

come compilare il programma di esempio di OpenCv con Visual Code

 


 

Installare le estensioni CMake, CMale Tools, C++ Intellisense

CMakeLists.txt

# CMakeLists.txt

# Older versions of CMake are likely to work just fine but, since
# I don't know where to cut off I just use the version I'm using
cmake_minimum_required(VERSION "3.17")

# name of this example project
project(simple-demo)

# set OpenCV_DIR variable equal to the path to the cmake
# files within the previously installed opencv program
set(OpenCV_DIR /home/luca/opencv/install/lib/cmake/opencv4)

# Tell compiler to use C++ 14 features which is needed because
# Clang version is often behind in the XCode installation
set(CMAKE_CXX_STANDARD 14)

# configure the necessary common CMake environment variables
# needed to include and link the OpenCV program into this
# demo project, namely OpenCV_INCLUDE_DIRS and OpenCV_LIBS
find_package( OpenCV REQUIRED )

# tell the build to include the headers from OpenCV
include_directories( ${OpenCV_INCLUDE_DIRS} )

# specify the executable target to be built
add_executable(simple-demo main.cpp)

# tell it to link the executable target against OpenCV
target_link_libraries(simple-demo ${OpenCV_LIBS} )


.vscode/launch.json 

qui si possono inserire gli argomenti da linea di comando

se si imposta a false stopAtEntry il debugger si ferma solo ai breakpoint

{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Debugger",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/simple-demo",
"args": ["valeria.jpg"],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb"
}
]
}

main.cpp


#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>

using std::cout;
using std::endl;

int main(int argc, char** argv) {

if (argc != 2) {
cout << "Expecting a image file to be passed to program" << endl;
return -1;
}
cv::Mat img = cv::imread(argv[1]);
if (img.empty()) {
cout << "Not a valid image file" << endl;
return -1;
}
cv::namedWindow("Simple Demo", cv::WINDOW_AUTOSIZE);
cv::imshow("Simple Demo", img);
cv::waitKey(0);
cv::destroyAllWindows();

return 0;
}

lunedì 23 settembre 2024

Spot Robot Calibration Board Boston Bynamics e OpenCV

Ho avuto la fortuna di poter usare una enorma Charuco Board legata al cane robot Spot della Boston Dynamics


Nonostante non sia esplicitamente indicato si tratta di una Charuco Board 4x4_100 di 9 colonne e 4 righe

Per usarla per calibrare una camera si puo' usare il seguente script OpenCV

Attenzione: per funzionare lo script necessita setLegacyPattern(True)

import os
import numpy as np
import cv2

# ------------------------------
# ENTER YOUR REQUIREMENTS HERE:
ARUCO_DICT = cv2.aruco.DICT_4X4_250
SQUARES_VERTICALLY = 9
SQUARES_HORIZONTALLY = 4
SQUARE_LENGTH = 0.115
MARKER_LENGTH = 0.09
# ...
PATH_TO_YOUR_IMAGES = './hikvision'
# ------------------------------

def calibrate_and_save_parameters():
# Define the aruco dictionary and charuco board
dictionary = cv2.aruco.getPredefinedDictionary(ARUCO_DICT)
board = cv2.aruco.CharucoBoard((SQUARES_VERTICALLY, SQUARES_HORIZONTALLY), SQUARE_LENGTH, MARKER_LENGTH, dictionary)
board.setLegacyPattern(True)
params = cv2.aruco.DetectorParameters()
params.cornerRefinementMethod = 0


image_files = [os.path.join(PATH_TO_YOUR_IMAGES, f) for f in os.listdir(PATH_TO_YOUR_IMAGES) if f.endswith(".jpg")]
image_files.sort()

all_charuco_corners = []
all_charuco_ids = []

for image_file in image_files:
print(image_file)
image = cv2.imread(image_file)
marker_corners, marker_ids, _ = cv2.aruco.detectMarkers(image, dictionary, parameters=params)

# If at least one marker is detected
if len(marker_ids) > 0:
charuco_retval, charuco_corners, charuco_ids = cv2.aruco.interpolateCornersCharuco(marker_corners, marker_ids, image, board)

if charuco_retval:
all_charuco_corners.append(charuco_corners)
all_charuco_ids.append(charuco_ids)

# Calibrate camera
retval, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.aruco.calibrateCameraCharuco(all_charuco_corners, all_charuco_ids, board, image.shape[:2], None, None)

# Save calibration data
np.save('hik_camera_matrix.npy', camera_matrix)
np.save('hik_dist_coeffs.npy', dist_coeffs)


cv2.destroyAllWindows()

calibrate_and_save_parameters()







LLama3 Anita

A seguito di questo post ho provato a vedere ho provato a vedere cosa accadeva ad utilizzare un modello specifico per la lingua italiana in...