Aprendo un cassetto e' saltato fuori questo progetto del 2010
Non si vede benissimo ma e' una Arduino 2009 (probabilmente un clone)
Aprendo un cassetto e' saltato fuori questo progetto del 2010
Non si vede benissimo ma e' una Arduino 2009 (probabilmente un clone)
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=';')
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)
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
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
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')
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
elenco_foto.xml
come compilare il programma di esempio di OpenCv con Visual Code
Installare le estensioni CMake, CMale Tools, C++ Intellisense
CMakeLists.txt
.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
main.cpp
Aprendo un cassetto e' saltato fuori questo progetto del 2010 Non si vede benissimo ma e' una Arduino 2009 (probabilmente un clone)