OpenCV – parametres de cameras

l’utilisation de camera USB ou de PIcamera avec Open CV peut necessiter de regler les parametres video tels que taille d’image, debit d’image , luminosité, contraste, saturation, etc ..

voyons avec un petit programme python comment faire ce type de reglage .

le programme ci dessous permet de regler les parametres classiques : luminosite , contraste, saturation, teinte d’une petite camera USB 640×480 ou d’une PIcam.

import cv2

cap1=cv2.VideoCapture(1) #sortie 1 Webcam USB
USBcamwin="USBcam"  # nom de la fenetre Webcam

while True:
    ret, frame1 = cap1.read()
    cap1.set(10,60) #luminosité
    cap1.set(11,60) #contraste
    cap1.set(12,60) #saturation
    cap1.set(13,60) #teinte
    cv2.imshow(USBcamwin, frame1)
    key=cv2.waitKey(1)
    if key & 0xFF == ord('q'):
        cv2.destroyAllWindows   
        break

la liste des parametres complets est disponible ici : flags video

la structure du paramètre est la suivante: cap1. set ( n° flag , valeur )

on trouve la liste des valeurs de flag dans le lien au dessus , les plus courants sont les suivants:

  • 10 = luminosité
  • 11 = contraste
  • 12 = saturation
  • 13 = teinte
  • 14 = gain
  • 20 = finesse
  • 22 = gamma
  • 30 = ISO

pour la valeur du parametre , il n’y a malheureusement pas de regle, elle depends de la camera utilisée , par exemple pour une PIcam :

  • luminosité: de 0 a 100
  • contrast de -100 a 100
  • saturation de -100 a 100

en fonction de votre camera , il vous faudra donc faire soit une recherche sur le web soit tout simplement faire des essais .

et comme souvent , vous pourrez par exemple associer les valeurs a des parametres pilotés par des sliders ou des widgets TKinter au travers d’une fenetre de menu comme dans la vignette de cette page.

OpenCV – nuances de gris/N&B/Contours

nous allons voir ici comment transformer , en temps réel, le flux vidéo en nuance de gris et en noir et blanc.

puis a partir de ces étapes préliminaires faire la détection de contour.

premier petit bout de programme Python, on récupère le flux vidéo d’une webcam USB et on l’affiche :

import cv2 
capture = cv2.VideoCapture(0) 
while (True):
    ret, frame = capture.read() 
    cv2.imshow('video original', frame)
    if cv2.waitKey(1) == 27:
        break 
capture.release()
cv2.destroyAllWindows()

la boucle « if + break  » permet d’arrêter l’affichage de la vidéo en appuyant sur la touche « Echap » du clavier ( code ascii 27). voici le résultat de ce bout de programme:

évolution du programme de base , on transforme le flux video RGB en nuance de gris et on affiche les 2 vidéos ensembles pour comparer le résultat:

import cv2  
capture = cv2.VideoCapture(0)

while True:  
    # extraction des images
    (ret, frame) = capture.read()     
    # conversion en nuance de gris
    grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # affichage des 2 videos
    cv2.imshow('video original', frame)
    cv2.imshow('video grey', grayFrame)
    # fin du programme par appui de la touche Echap
    if cv2.waitKey(1) == 27:
        break
 
capture.release()
cv2.destroyAllWindows()

voila ce que ça donne:

variante suivante du deuxième programme , on récupère le flux vidéo de la webcam USB , on le transforme en nuance de gris et en noir et blanc binaire et on affiche les 3 vidéos ensembles pour comparer le résultat:

import cv2 
capture = cv2.VideoCapture(0)
 
while (True): 
    (ret, frame) = capture.read() 
    grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # conversion en noir et blanc
    (thresh, blackAndWhiteFrame) = cv2.threshold(grayFrame, 127, 255, cv2.THRESH_BINARY)    
    cv2.imshow('video original', frame)
    cv2.imshow('video grey', grayFrame)
    cv2.imshow('video bw', blackAndWhiteFrame)
    if cv2.waitKey(1) == 27:
        break
 
capture.release()
cv2.destroyAllWindows()

copie d’écran du résultat avec les 3 flux vidéo affichés ensembles :

ensuite premier traitement du flux video , la recherche et le dessin du contour des objets tracé en rouge :

import cv2 
capture = cv2.VideoCapture(0)
 
while (True): 
    (ret, frame) = capture.read() 
    grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # conversion en noir et blanc
    (thresh, blackAndWhiteFrame) = cv2.threshold(grayFrame, 127, 255, cv2.THRESH_BINARY)
    # recherche du controur
    contours = cv2.findContours(blackAndWhiteFrame, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) [-2]
    # dessin du contour en rouge
    for c in contours:
        cv2.drawContours(frame, [c], -1, (0,0,255), 2)        
    cv2.imshow('contour', frame)   
    if cv2.waitKey(1) == 27:
        break
 
capture.release()
cv2.destroyAllWindows()

copie d’ecran du resultat:

petite variante du traitement précédent , juste en remplaçant le 2 en fin de la ligne de commande « drawContour » par -2 on remplis le contour au lieu de dessiner le contour.

cv2.drawContours(frame, [c], -1, (0,0,255), 2) 
remplacé par:
cv2.drawContours(frame, [c], -1, (0,0,255), -2)

voici le programme modifié:

import cv2 
capture = cv2.VideoCapture(0)
 
while (True): 
    (ret, frame) = capture.read() 
    grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # conversion en noir et blanc
    (thresh, blackAndWhiteFrame) = cv2.threshold(grayFrame, 127, 255, cv2.THRESH_BINARY)
    contours = cv2.findContours(blackAndWhiteFrame, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) [-2]
    for c in contours:
        cv2.drawContours(frame, [c], -1, (0,0,255), -2)        
    cv2.imshow('contour', frame)   
    if cv2.waitKey(1) == 27:
        break
 
capture.release()
cv2.destroyAllWindows()

et voici le resultat sur le flux video en temps réel

OpenCV – La souris

nous allons aborder ici les rudiments d’utilisation de la souris avec Open CV.

pour cela un programme tres basique qui illustre les évènements de la souris et les traitements associés.

en préliminaire , voici la liste des évènements souris reconnus par OPENCV:

voyons maintenant le programme

import cv2      #import de la librairie openCV
import numpy	#import de la librairie numpy (maths sur les matrices d'ordre N)
# les images sont traitées comme des matrices d'ordre 3 (X,Y,couleurRGB)
# x pixels en largeur + Y pixels en hauteur + 3 bits de couleurs (RGB) 

# fonction qui defini les reactions aux evenements souris
def click_event(event,x,y,flags,param):     
    if event == cv2.EVENT_RBUTTONDOWN:
        cv2.circle(img,(x,y),20,(0,255,0),3)
        strXY = str(x) + ',' + str(y)
        cv2.putText(img, strXY, (x+21,y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,0),1)
    elif event == cv2.EVENT_LBUTTONDOWN:
        cv2.rectangle(img,(x-20,y-20),(x+20,y+20),(255,0,0),3)
        strXY = str(x) + ',' + str(y)
        cv2.putText(img, strXY, (x+21,y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,0),1)
 
# creation d'un fond noir (img)dans une fenetre('image')et liaison de la fonction setmoussecallback
img = numpy.zeros((480,640,3), numpy.uint8)  
cv2.namedWindow('image')
cv2.setMouseCallback('image',click_event)

while(1):
    cv2.imshow('image',img)
    if cv2.waitKey(1) == 27:
        break
cv2.destroyAllWindows()

ce qui donne comme exemple de résultat un programme qui ouvre une fentre a fond noir et dessine un rectangle bleu ou un cercle vert a l’endroit de la souris suivant qu’on clique sur le bouton droit ou gauche de la souris. il affiche en plus a droite de la figure les coordonnées (X,Y ) de la position de souris dans l’image ( coordonnées en pixels).

prenons quelques instants pour détailler et comprendre ce qui se passes:

au milieu de lignes de codes on trouve les 3 lignes suivantes :

img = numpy.zeros((480,640,3), numpy.uint8)  
cv2.namedWindow('image')
cv2.setMouseCallback('image',click_event)
  • la première ligne défini une variable tableau « img » a partir de la librairie numpy qui met a zéro (numpy.zeros) les valeurs de la matrices d’ordre 3 définissant en fait une image de 480pixels de hauteur, par 640 pixels de largeur et 3 valeurs de couleurs BGR pour chaque pixel . les valeurs sont codées sur 8bits via le code ‘numpy.uint8’ . comme les valeur BGR sont mises a zéro par la fonction numpy, cela fait une image en noir
  • la deuxième ligne crée une fenêtre OpenCV dont le nom est ‘image’
  • la troisieme ligne affecte les évènements de la souris à la fenêtre ‘Image’ et a la fonction ‘clik_event’

faisant appel a une fonction ‘click_event’, il faut définir celle ci , c’est l’objet des lignes suivantes:

def click_event(event,x,y,flags,param):     
    if event == cv2.EVENT_RBUTTONDOWN:
        cv2.circle(img,(x,y),20,(0,255,0),3)
        strXY = str(x) + ',' + str(y)
        cv2.putText(img, strXY, (x+21,y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,0),1)
    elif event == cv2.EVENT_LBUTTONDOWN:
        cv2.rectangle(img,(x-20,y-20),(x+20,y+20),(255,0,0),3)
        strXY = str(x) + ',' + str(y)
        cv2.putText(img, strXY, (x+21,y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,0),1)

la premiere boucle if correspondant au bouton droit enfoncé , elle dessine un cercle dans la fenetre ‘img’ , dont le centre est aux coordonnées x,Y retournées par la souris , d’un rayon de 20 pixels, de la couleur BGR (0,255,0) soit le Vert (G). puis retourne une variable string ‘strXY’ constituée des coordonnées XY du pointeur de souris avec une virgule au milieu. et affiche le texte dans la fenetre’img’ constitué de la variable ‘strXY’ , affichée aux coordonnées (x+21,Y) en ulisant la police de caracteres arial taille 0.5 en couleur (255,255,0) soit un bleu clair et d’epaisseur 1 .

la deuxieme boucle If fait la meme chose si le bouton Gauche est enfoncé et dessine un rectangle bleu cantré sur la position de la souris de largeur et hauteur identique (20 pixels) de couleur bleu foncé et affiche a droite les coordonnées XY.

la derniere partie du programme :

while(1):
    cv2.imshow('image',img)
    if cv2.waitKey(1) == 27:
        break
cv2.destroyAllWindows()

effectue une boucle permanente qui affiche l’image ‘img’ resultante de toutes les operations dans la fenetre ‘image’ puis teste l’appui de touche au clavier et termine le programme si ‘echap » est appuyée la dernier ligne de commande ferme la fenêtre du programme .

OpenCV – SimpleBlobDetector

SimpleBlobDetector est un utilitaire d’OpenCV permettant la détection automatique des « Blobs ». en Anglais un Blob est une tache . cet utilitaire est donc intéressant pour la détection de formes basiques circulaires, elliptiques ou rectangulaire. il trouve son intérêt par exemple en astronomie pour la détection d’étoiles sur un ciel noir avec une camera.

pour illustrer , ses possibilités , commençons par un programme simple utilisant une camera USB et une feuille blanche avec quelques taches faites au marqueur noir.

import numpy as np
import cv2
cap = cv2.VideoCapture(0)

while (True):
    ret, frame = cap.read()
    # entrée des parametres de SimpleBlobDetector
    params = cv2.SimpleBlobDetector_Params()    
    params.minThreshold = 10;     # Change thresholds
    params.maxThreshold = 300; 
    params.filterByColor = False    # Filter by color.
    params.BlobColor = 0   # 0 for darkcolor & 255 for light colors   
    params.filterByArea = True    # Filter by Area.
    params.minArea = 200
    params.maxArea = 600    
    params.filterByCircularity = False   # Filter by Circularity
    params.minCircularity = 0.1
    params.maxCircularity = 1    
    params.filterByConvexity = False    # Filter by Convexity
    params.minConvexity = 0.87
    params.maxConvexity = 2    
    params.filterByInertia = False     # Filter by Inertia
    params.minInertiaRatio = 0.01
    params.maxInertiaRatio = 0.1
    # utilisation de SimpleBlobDetector
    detector = cv2.SimpleBlobDetector_create(params)
    keypoints = detector.detect(frame)
    im_with_keypoints = cv2.drawKeypoints(frame, keypoints, np.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
    cv2.imshow('frame', im_with_keypoints)
    
    if cv2.waitKey(1) == 27:
        break

voici le resultat avec les parametres saisis.

toutes les taches faites au feutre ne sont pas entourées , c’est tout simplement le resultat de la definition des lignes de filtre ci dessous qui fixent la taille mini et maxi des zone de pixels a choisir ( entre 200 et 600 pixels):

 params.filterByArea = True    # Filter by Area.
    params.minArea = 200
    params.maxArea = 600    

on active les differents type de filtre en mettant la valeur a  » True » ( pour desactiver , il faut mettre « False« ) et en choisissant une valeur pour les 2 lignes de seuils mini et maxi.

pour illustrer la fonction de chaque filtre , ci dessous une petite image de synthese:

nous allons maintenant sur le meme principe , determiner les coordonnées d’une tache blanche sur une feuille sombre . voici le programme:

import numpy as np
import cv2
cap = cv2.VideoCapture(0)

while (True):
    ret, frame = cap.read()    
    params = cv2.SimpleBlobDetector_Params()    
    params.minThreshold = 10;     
    params.maxThreshold = 300;
    params.filterByColor = True   
    params.blobColor = 255  
    params.filterByArea = True   
    params.minArea = 100
    params.maxArea = 600 
    detector = cv2.SimpleBlobDetector_create(params)
    keypoints = detector.detect(frame)    
    im_with_keypoints = cv2.drawKeypoints(frame, keypoints, np.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)    
    cv2.imshow('frame', im_with_keypoints)
    for kp in keypoints:
     print (int(kp.pt[0]), int(kp.pt[1]))
    
    if cv2.waitKey(1) == 27:
        break

l’evolution majeure par rapport au premier programme , est l’activation du mode couleur et la prise en compte de couleurs lumineuses ( ici la tache blanche sur fond sombre) dans les 2 lignes en rouge. et l’ajout d’une boucle imprimant les coordonnées (en pixel de l’image) dans les 2 lignes bleues. si on fait tourner ce programme dans thonny python , et que l’on fait bouger l’image ou la camera voici 2 exemples du resultat ( a gauche les coordonnées qui s’affichent dans la fenêtre shell de thonny python):

nous avons ici les bases d’un programme python pour de l’autoguidage sur une monture équatoriale astronomique… ne reste qu’a transformer ces coordonnées « pixels » en deplacements AD/DEC au fur et a mesure du déplacement de l’étoile de référence dans l’image ….

OpenCV – Détection de Mouvement

la detection de mouvement est une option interressante par exemple dans le cas de video surveillance , ci dessous un programme basique qui fait le boulot.

NOTA: derriere les caractères # des ligne en bleu qui peuvent remplacer la ligne juste avant pour des tests au choix soit sur un fichier video soit sur le livestream d’une camera. et également soit en dessinant des rectangles autour des objets en mouvement soit en dessinant le contour de l’objet.

import cv2
import numpy as np

cap = cv2.VideoCapture(0)
#cap = cv2.VideoCapture('OPENCVmotiondetection.avi')

ret, frame1 = cap.read()
ret, frame2 = cap.read()

while cap.isOpened():
    diff = cv2.absdiff(frame1, frame2)
    gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (5,5), 0)
    _, thresh = cv2.threshold(blur, 20, 255, cv2.THRESH_BINARY)
    dilated = cv2.dilate(thresh, None, iterations=3)
    _, contours, _ = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    for contour in contours:
        (x, y, w, h) = cv2.boundingRect(contour)
        if cv2.contourArea(contour) < 500:
            continue
        cv2.rectangle(frame1, (x, y), (x+w, y+h), (0, 255, 0), 2)
        #cv2.drawContours(frame1, contours, -1, (0, 255, 0), 2)
    cv2.imshow("feed", frame1)
    frame1 = frame2
    ret, frame2 = cap.read()
    if cv2.waitKey(40) == 27:
        break

cv2.destroyAllWindows()
cap.release()

une copie d’ecran du resultat sur une video AVI et avec dessin de rectangles englobants sur les objets en mouvement:

examinons maintenant , une variante du programme précédent utilisant des fonction elaborées de OpenCV ainsi que le principe des masques , qui permet de n’appliquer la detection que sur la partie droite de la video

NOTA: les ligne en bleu sont des variantes du programme par rapport a la ligne en dessous ( il faut remplacer l’une par l’autre).

import cv2
import numpy as np

#cap = cv2.VideoCapture(1)
cap = cv2.VideoCapture('OPENCVmotiondetection.avi')
object_detector = cv2.createBackgroundSubtractorMOG2(history=100, varThreshold=10)

while True:
    ret, frame = cap.read()    
    roi = frame[0:480 , 320:640]        # def Region Off Interest   
    mask = object_detector.apply(roi)   # definission d'un masque avec la ROI
    _, mask = cv2.threshold(mask, 254, 255, 0)   # ne garde que les pixel blancs
    _, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    for cnt in contours:
        area = cv2.contourArea(cnt)
        if area > 100 :
            #cv2.drawContours(roi, [cnt], -1, (0, 255, 0), 2)  #dessin contour
            x, y, w, h =cv2.boundingRect(cnt)    # definition rectangle englobant
            cv2.rectangle(roi, (x, y), (x+w, y+h), (0, 255, 0), 3) #dessin rectangle
    
    cv2.imshow("Frame", frame)
    cv2.imshow("ROI", roi)
    cv2.imshow("Mask", mask)
    
    if cv2.waitKey(40) == 27:
        break

cv2.destroyAllWindows()
cap.release()

le resultat avec l’affichage , de la video de base, du ROI et du masque N&B

PIcam et Webcam en même temps

afficher l’image simultanée d’une PIcam et d’une webcam USB avec un bout de Python c’est possible , le programme est extrêmement simple:

copier le petit morceau de python ci dessous dans votre éditeur python et lancez le (votre PICAM doit etre raccordée a son slot et une webcam raccordée au RPI en USB), vous devriez voir 2 fenêtres s’ouvrir dans votre écran avec chacune la vidéo de la camera concernée a l’intérieur.

ce programme nécessite d’avoir installé au préalable la librairie python « OpenCV ».

import cv2

cap0=cv2.VideoCapture(0) #sortie 0 Picam
cap1=cv2.VideoCapture(1) #sortie 1 Webcam USB

while True:
    ret, frame0 = cap0.read()
    ret, frame1 = cap1.read()
    cv2.imshow("PIcam", frame0)
    cv2.imshow("USBcam", frame1)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

NOTA1: les numéros de sorties a utiliser (ici sortie 0 et sortie 1 ) sont fonctionnels dans la majorité des cas. mais si vous rencontrez des problèmes , utiliser la commande shell « lsusb » pour déterminer quelles sorties du RPI sont utilisées.

NOTA2:il est possible d’ajouter d’autres webcam , pour cela il suffit d’implémenter autant de lignes dédié ( capx , ret, et cv2.imshow) que de flux video souhaité.

ce type d’utilisation en astro , permet par exemple d’utiliser une Webcam USB en autoguidage et la PIcam HQ en prise de vue pause longue ou en vidéo planetaire . une autre utilisation potentielle avec plusieurs Wab cam serait pour la video surveillance exterieure et interieure d’un observatoire en combinaison avec de la detection de mouvement et un envoi automatique de photo par mail …

AMELIORATION: voyons comment redimensionner et positionner les 2 fenêtres d’affichage

import cv2

cap0=cv2.VideoCapture(0) #sortie 0 Picam
Picamwin="PIcam"    # nom de la fenetre PIcam
cv2.namedWindow(PIcamwin, cv2.WINDOW_NORMAL)
cv2.resizeWindow(PIcamwin, 600, 450)
cv2.moveWindow(PIcamwin, 420, 110)

cap1=cv2.VideoCapture(1) #sortie 1 Webcam USB
USBcamwin="USBcam"  # nom de la fenetre Webcam
cv2.namedWindow(USBcamwin,cv2.WINDOW_NORMAL)
cv2.resizeWindow(USBcamwin, 400, 300)
cv2.moveWindow(USBcamwin, 10, 260)

while True:
    ret, frame0 = cap0.read()
    ret, frame1 = cap1.read()
    cv2.imshow(PIcamwin", frame0)
    cv2.imshow(USBcamwin, frame1)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

voici un exemple du resultat du pgme ci dessus avec une PIcam sur son slot et une Webcam USB sur port USB, l’ensemble affiché sur un petit ecran HDMI touschscreen 7″ 1024×600 pixels .chacune des video est affichée en taille de fenetre differente et positionnées en bas et dans la largeur de l’ecran , permettant l’acces au menu du bureau du RPI . l’affichage avec des fenetres Opencv permet en outre d’avoir la vue video via VNC en acces distant . ce qui n’est pas possible avec les fenetres live view de la librairie Picam.

POLARSCOPE en Python

tout le monde connait le prix d’un pole master, voyons ici comment faire le sien avec une webcam et un bout de python pour exploiter ça sur un raspberry PI.

Un polemaster est tout simplement une camera CCD commandée par un software qui affiche une mire d’alignement polaire comme par exemple la mire Skywatcher.

le principe est donc simple, il faut superposer une mire « graphique » sur la video d’une camera.

vous trouverez ci dessous un petit bout de programme Python qui affichera en temps réel la mire d’entête par dessus la vidéo d’une webcam.

pour la mise au point finale, il faudra faire des essai en fonction de la camera choisie , et de la focale de l’objectif monté dessus et ajuster les diametres et coordonnées des figures graphiques en fonction de vos besoins. l’idéal étant de se calibrer avec un viseur polaire optique type skywatcher . le principe fonctionne egalement avec une PIcam sur son slot , il suffit de changer le numéro de sortie ( en général 0 pour la PIcam) .

il faudra en préliminaire installer la librairie python computer Vision « OpenCV« . bien entendu , libre a vous de concevoir votre propre mire en utilisant les option d’openCV draw .

import cv2

cv2.namedWindow("POLARALIGN")
vc = cv2.VideoCapture(1)

if vc.isOpened(): # try to get the first frame
    rval, frame = vc.read()
else:
    rval = False
    
while rval:
    cv2.imshow("POLARALIGN", frame)
    rval, frame = vc.read()
    key = cv2.waitKey(20)
    if key == 27: # exit on ESC
        break
    else:
        cv2.circle(img=frame, center=(320, 210), radius=110, color=(0, 0, 255), thickness=3, lineType=8, shift=0)
        cv2.circle(img=frame, center=(320, 210), radius=120, color=(0, 0, 255), thickness=3, lineType=8, shift=0)
        cv2.line(img=frame, pt1=(320, 60), pt2=(320, 360), color=(255, 0, 0), thickness=2, lineType=8, shift=0)
        cv2.line(img=frame, pt1=(180, 210), pt2=(460, 210), color=(255, 0, 0), thickness=2, lineType=8, shift=0)
        cv2.line(img=frame, pt1=(220, 100), pt2=(420, 320), color=(0, 255, 255), thickness=2, lineType=8, shift=0)
        cv2.line(img=frame, pt1=(220, 320), pt2=(420, 100), color=(0, 255, 255), thickness=2, lineType=8, shift=0)        

vc.release()
cv2.destroyWindow("POLARALIGN")

Commande d’un APN reflex avec GPHOTO2

il est possible de commander et configurer un APN reflex moderne en remote via USB avec un Raspberry PI en utilisant la librairie GPHOTO2.cette option est très intéressante pour l’astro-photo, en particulier pour des time-laps en pauses longues. nous allons voir ici comment procéder.

le site internet dédié a Gphoto2 est accessible via ce lien: http://www.gphoto.org/

avant de poursuivre plus loin, il est important de verifier que votre APN reflexe est compatible avec la librairie, pour cela voir la liste ici:

liste des APN compatibles: http://www.gphoto.org/proj/libgphoto2/support.php

INSTRUCTION D’INSTALLATION

avant de pouvoir utiliser Gphoto2 il va falloir faire l’installation des prérequis et de la librairie elle même . ci dessous les instructions qui sont disponible dans le fichier joint en PDF pour pour pouvoir faire des copier coller des lignes de commandes.

PREREQUIS: installation des dependances:

sudo apt-get install git make autoconf libltdl-dev libusb-dev libexif-dev libpopt-dev libxml2-dev libjpeg-dev libgd-dev gettext autopoint

INSTALLATION DE libghoto2:

télécharger le code pour libgphoto2 ici: https://github.com/gphoto/libgphoto2.git

executer les commandes ci dessous pour installer libgphoto2

cd ~/libgphoto2
autoreconf --install --symlink
./configure
make
sudo make install

INSTALLATION DE ghoto2

télécharger le code pour gphoto2 ici: https://github.com/gphoto/gphoto2.git

executer les commandes ci dessous pour installer gphoto2

cd ~/gphoto2
autoreconf --install --symlink
./configure
make
sudo make install

MISE A JOUR DE LA CONFIGURATION RPI

ajouter la lignes ci dessous dans le fichierde configuration : /etc/ld.so.conf.d/libc.conf

/usr/local/lib

rafraichir le cache avant de continuer:

sudo ldconfig

créer les regles udev pour l’APN

/usr/local/lib/libgphoto2/print-camera-list udev-rules version 201 group plugdev mode 0660 | sudo tee /etc/udev/rules.d/90-libgphoto2.rules

créer la base de données pour udev

/usr/local/lib/libgphoto2/print-camera-list hwdb | sudo tee /etc/udev/hwdb.d/20-gphoto.hwdb

UTILISATION DE GPHOTO2

gphoto2 est un « catalogue » de fonctions permettant d’envoyer des commandes a votre APN reflex via le port USB et avec des commandes shell sous linux . voici la liste des commandes:

http://www.gphoto.org/doc/manual/ref-gphoto2-cli.html

nous allons en tester 2 pour cela connecter votre APN reflex a votre RPI via son cordon USB et executer la commande shell ci dessous pour verifier que votre Gphoto2 detecte bien votre APN:

gphoto2 –auto-detect

si le nom de votre Appareil photo apparait après l’exécution de la commande c’est que tout est OK et vous pouvez aller plus loin et exécuter le premier test en prenant une photo. pour cela exécuter la commande shell ci dessous:

gphoto2 –capture-image

UTILISATION DE GPHOTO2 AVEC PYTHON

le travail en mode de commande shell n’est pas des plus convivial particulierement la nuit en nomade . nous allons voir ici comment utiliser Gphoto2 via un programme python. pour cela, il faut d’abord installer le module python permettant d’encapsuler Gphoto2 . exécuter la commande:

sudo pip install -v gphoto2

nous allons maintenant écrire un petit programme Python qui permet de prendre une photo et de l’enregistrer sur le raspberry

import logging
import os
import subprocess
import sys

import gphoto2 as gp

logging.basicConfig(
        format='%(levelname)s: %(name)s: %(message)s', level=logging.WARNING)
callback_obj = gp.check_result(gp.use_python_logging())

def get_camera():
    camera = gp.Camera()
    camera.init()
    return camera

def capture_image_from_dslr():
    camera = get_camera()
    capture_image(camera)
    camera.exit()
    return 0

def capture_image(camera):
    print('Capturing image')
    file_path = camera.capture(gp.GP_CAPTURE_IMAGE)
    print('Camera file path: {0}/{1}'.format(file_path.folder, file_path.name))
    target = os.path.join('/tmp', file_path.name)
    print('Copying image to', target)
    camera_file = camera.file_get(
        file_path.folder, file_path.name, gp.GP_FILE_TYPE_NORMAL)
    camera_file.save(target)
    return 0
  
  if __name__ == "__main__":
    sys.exit(capture_image_from_dslr())

INTERFACE GRAPIQUE AVEC TKINTER : TIME LAPS PAUSE LONGUE

nous allons voir ici comment créer une interface graphique ergonomique avec Tkinter pour lancer des commandes au travers de menus . le programme ci dessous permet de faire une serie de photo en pause longue , il fonctionne avec un ecran tactile et affiche un cadre avec menu dans lequel on peut faire varier un certain nombre de paramètres de prise de vue.

NOTA: il a ete optimisé pour un CANON EOS M50.

les paramètres sont :

  • durée de pause pour chaque photo => reglage par slider de 0 a 180 secondes
  • intervalle entre chaque photo=> reglage par slider de 0 a 100 secondes
  • nombre de photo=> reglage par slider de 0 a 100 photos
  • en haut a droite sensibliité ISO=> reglage par choix dans liste de valeur
  • un bouton bleu en bas a gauche de lancement de séquence de prise de vue , une fois le cycle lancé , un message affiche le statu d’avancement en bas de l’ecran entre les 2 boutons
  • un bouton rouge en bas a gauche pour quitter le programme

programme en fichier txt

a copier coller dans votre editeur python ou a enregistrer directement avec l’extension « .py »

import tkinter as tk
import signal
import os
import subprocess
import time

win = tk.Tk()
win.title(" AStrophoto Pauses Longues")

### WIDGETS ###
canvas1 = tk.Canvas(win, width = 550, height = 320, relief = 'raised')
canvas1.pack()
slider1 = tk.Scale(win, from_=0, to=180, orient='horizontal', resolution=5, tickinterval=60, length=300, label='pause (s)')
canvas1.create_window(170,50, window=slider1)
slider2 = tk.Scale(win, from_=0, to=100, orient='horizontal', resolution=1, tickinterval=25, length=300, label='intervale (s)')
canvas1.create_window(170,130, window=slider2)
slider3 = tk.Scale(win, from_=0, to=100, orient='horizontal', resolution=1, tickinterval=25, length=300, label='nombre')
canvas1.create_window(170,210, window=slider3)
label1 = tk.Label(win, text='ISO')
label1.config(font=('helvetica', 15))
canvas1.create_window(450,24, window=label1)
spinbox1 = tk.Spinbox(win, values=["250","320","400","500","640","800","1000","1250","1600","2000","2500","3200","4000","5000","6400" ],width=4)
spinbox1.config(font=('helvetica', 30))
canvas1.create_window(450,60, window=spinbox1)

### Event Functions ###
def killgphoto2Process():
    p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE)
    out, err = p.communicate()
    for line in out.splitlines():
        if b'gvfsd-gphoto2' in line:
            pid = int(line.split(None,1)[0])
            os.kill(pid, signal.SIGKILL)
def takepicture():    
    tmpPause = int(slider1.get())
    isovalue = int(spinbox1.get())
    interPause = int(slider2.get())
    nbrPhoto = int(slider3.get())
    tempphoto = (tmpPause + interPause)
    print("def BULB et def ISO")
    subprocess.run(["gphoto2","--set-config","shutterspeed=bulb"])
    time.sleep(2)
    print("Bulb OK")
    subprocess.run(["gphoto2","--set-config","iso="+str(isovalue)])
    time.sleep(2)
    print("ISO OK")
    i=1
    while i <= nbrPhoto :
        label2=tk.Label(win,text='photo '+str(i)+'/'+str(nbrPhoto)+' reste '+ str((nbrPhoto - i)*tempphoto)+ ' secondes', fg='blue',font=('helvetica',14, 'bold'),width=25)
        canvas1.create_window(275,300, window=label2)
        win.update_idletasks()
        print("i=",(i))
        subprocess.run(["gphoto2","--set-config","eosremoterelease=2"])
        time.sleep(tmpPause)
        subprocess.run(["gphoto2","--set-config","eosremoterelease=4"])
        time.sleep(2)
        print("photo",(i))
        time.sleep(interPause)
        i=i+1
def close():
    win.destroy()    # ferme le pgme

takePic = tk.Button (text='LANCER', command=takepicture, bg='blue', fg='white', font=('helvetica',10, 'bold'))
canvas1.create_window(50,300, window=takePic)
exitButton = tk.Button(text='QUITTER', command=close, bg='red', fg='white', font=('helvetica',10, 'bold'))
canvas1.create_window(500,300, window=exitButton)
killgphoto2Process()            
win.mainloop() # Loops forever

pour finir , une petite video de démo/test

réaliser une roue et vis sans fin

petit tuto pour expliquer comment faire un ensemble roue et vis sans fin avec les moyens du bord classique a savoir : de la vis pas metrique pour le vis sans fin , un rond dans le materiau choisi et un taraud correspondant au diametre et au pas de la vis metrique et un tour pour usiner les dentures de la roue.

attention, cette technique est a reserver pour les materiaux tendres ( plastique , alu , laiton).

aucune garantie de resultat probant sur l’acier …

le principe est simple: le taraud monté dans le mandrin va servir de fraise de taillage , la piece elle est montée sur un axe fixé sur le chariot transversal et laissée libre de tourner mais sans jeu . ensuite on fait « rentrer » la roue dans le taraud et c’est le profil du taraud qui va entrainer la roue en rotation et generer la denture sur la roue . on augmente doucement la prise de passe a chaque tour complet ( faire un repaire sur la roue pour pouvoir visualiser un tour complet. le taraud doit tourner a vitesse lente .

pour ceux qui voudraient faire autrement que du pas mmetrique , on peut faire avec des tarauds pas anglais ou eventuellement fabriquer l’equivalent d’un taraud au pas et au profil voulu .

petite video youtube de la manip sur une roue en teflon ( systeme pour motoriser une petite monture equatoriale astro):

FONDERIE – le sable

élément primordiale pour la fonderie artisanale a la maison le sable . 2 solutions s’offrent a vous : l’achat en ligne ou aller jusqu’au bout dans le Do It Yourself et le faire vous même .

pour l’achat , voici 2 liens de site pro en ligne ou s’en procurer :

Artisant Foundry basé en Angletter: https://www.artisanfoundry.co.uk/

Angele Shop: en allemagne: https://www.angele-shop.com/shop/fr/

pour la version DIY, ci dessous petite vide youtube qui explique la recette . les produits de base sont du sable; le plus fin possible ( sable de maçonnerie, de rivière ou d’aquariophilie), de l’eau , et de la Bentonite en poudre fine. on trouve de la bentonite en achat en ligne , par exemple ici: https://www.mon-droguiste.com