Outils pour utilisateurs

Outils du site


diy:projets:approximationvitesse

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
diy:projets:approximationvitesse [2018/07/18 20:32] – [Calcul de la vitesse] sduranddiy:projets:approximationvitesse [2018/07/19 12:41] (Version actuelle) – [Bilan et sources du projet] sdurand
Ligne 3: Ligne 3:
 ==== Idée générale ==== ==== Idée générale ====
  
-Avec ce nouveau projet, nous allons **estimer la vitesse** d'un objet se déplaçant **perpendiculairement à la caméra** de notre Raspberry à une **distance donnée**, comme illustré par le schéma ci-dessous. +//**Je ne garantis en aucun cas la qualité de la méthode présentée ci-dessous ou de la précision qu'elle permet d'obtenir. De plus, cette implémentation peut très vite donner des résultats aberrants quand plusieurs objets en mouvements sont dans le champ de vision de la caméra (ou encore quand vous ne respectez pas la disposition décrite par le schéma ci-dessous).**// 
 + 
 +Avec ce nouveau projet, nous allons **estimer la vitesse** d'un objet se déplaçant **perpendiculairement à la caméra** de notre Raspberry à une **distance donnée** (en utilisant **OpenCV**), comme illustré par le schéma ci-dessous. 
  
 {{:diy:projets:scheme.png?400|}} {{:diy:projets:scheme.png?400|}}
  
 Pour estimer cette vitesse, nous aurons besoin de:  Pour estimer cette vitesse, nous aurons besoin de: 
-  * **mesurer le déplacement d'un objet** en pixels entre deux images capturées par la caméra.+  * **mesurer le déplacement d'un objet** en pixel entre deux images capturées par la caméra.
   * **calculer** à partir de ce déplacement et de la distance "caméra/trajectoire" la vitesse qu'on cherche.   * **calculer** à partir de ce déplacement et de la distance "caméra/trajectoire" la vitesse qu'on cherche.
 +
 ==== Mesure du déplacement ==== ==== Mesure du déplacement ====
  
 Pour mesurer le déplacement, on va utiliser de la **détection de mouvement**. Pour mesurer le déplacement, on va utiliser de la **détection de mouvement**.
  
-Pour cette partie du projet, je vous recommande de consulter [[https://www.pyimagesearch.com/2015/06/01/home-surveillance-and-motion-detection-with-the-raspberry-pi-python-and-opencv/|ce site]] pour des détails précis sur l'implémentationmais vous allez voir, **l'idée est simple**.+Pour cette partie du projet, je vous recommande de consulter [[https://www.pyimagesearch.com/2015/06/01/home-surveillance-and-motion-detection-with-the-raspberry-pi-python-and-opencv/|ce site]] pour des détails sur l'implémentation mais vous allez voir, **l'idée est simple**.
  
 On va simplement prendre une image de référence et à partir des différences qu'on observera avec les nouvelles images, on déduira **la nouvelle position de notre objet**.  On va simplement prendre une image de référence et à partir des différences qu'on observera avec les nouvelles images, on déduira **la nouvelle position de notre objet**. 
Ligne 35: Ligne 38:
     frame_count = frame_count + 1     frame_count = frame_count + 1
          
-    # On passe en niveau de gris et on floute pour éviter les différences ponctuelles+    # On passe en niveau de gris et on floute pour limiter les différences ponctuelles
     grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)     grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
     greyFrame = cv2.GaussianBlur(grayFrame, (21, 21), 0)     greyFrame = cv2.GaussianBlur(grayFrame, (21, 21), 0)
Ligne 45: Ligne 48:
     thresh = cv2.threshold(diff, 24, 255, cv2.THRESH_BINARY)[1]     thresh = cv2.threshold(diff, 24, 255, cv2.THRESH_BINARY)[1]
  
-    # On dilate un peu le résultat et on récupère les contours, parmis ces contours, on aura notre objets en mouvement (si le seuillage qu'on a choisi est adapté)+    # On dilate un peu le résultat et on récupère les contours, parmis ces contours, on aura notre objet en mouvement (si le seuillage qu'on a choisi est adapté)
     thresh = cv2.dilate(thresh, None, iterations=2)     thresh = cv2.dilate(thresh, None, iterations=2)
     _, contours, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)     _, contours, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
 </code> </code>
  
-On récupèrera ensuite les coordonnées de notre objets en mouvement en passant par une boîte enveloppante, de cette façon:+On récupèrera ensuite les coordonnées de notre objet en mouvement en passant par une boîte enveloppante, de cette façon:
 <code Python> <code Python>
 x, y, w, h = cv2.boundingRect(cnt_m) x, y, w, h = cv2.boundingRect(cnt_m)
 </code> </code>
  
-En **mesurant le temps écoulé entre chaque mesure** du déplacement, on est en mesure d'obtenir une **vitesse en pixels par seconde**. Reste maintenant à se ramener à une vitesse en m/s (ou autre, au choix).+Si vous vous amusez à afficher cette boîte, vous obtiendrez quelque chose de ce genre: 
 +{{:diy:projets:execution.png?400|}} 
 + 
 +En **mesurant le temps écoulé entre chaque mesure** du déplacement, on est en mesure d'obtenir une **vitesse en pixels par seconde**. Reste maintenant à se ramener à une vitesse en m/s. 
 ==== Calcul de la vitesse ==== ==== Calcul de la vitesse ====
  
-On a désormais la vitesse parcouru par notre objet en pixels par seconde, il nous reste simplement à **appliquer la formule** du schéma donné précédemment pour obtenir notre vitesse en m/s.+On a désormais la vitesse de notre objet en pixels par seconde, il nous reste simplement à **appliquer la formule** du schéma précédent pour obtenir notre vitesse en m/s.
  
 <code Python> <code Python>
-# On calcule au préalable la distance en mètre que va représenté un pixel de l'image (fov: field of view, voyez les specs de votre caméra pour avoir la bonne valeur)+import math 
 + 
 +# On calcule au préalable la distance en mètre que va représenter un pixel de l'image (fov: field of view, voyez les specs de votre caméra pour avoir la bonne valeur)
 fov = math.radians(53.5) fov = math.radians(53.5)
 meters_per_pixel = 2 * math.sin(fov/2) * float(sys.argv[1])/width meters_per_pixel = 2 * math.sin(fov/2) * float(sys.argv[1])/width
 </code> </code>
 +
 +Il ne vous reste plus qu'à multiplier ce nombre par le déplacement en pixel par seconde, et voilà, **vous avez la vitesse de votre objet !**
 +
 ==== Bilan et sources du projet ==== ==== Bilan et sources du projet ====
  
 +Malheureusement, je n'ai trouvé personne sur internet qui avait réalisé un tel système de cette façon, **vous devrez donc vous montrer méfiant par rapport aux résultats obtenus.**
 +
 +Il semblerai quand même que les résultats qu'on obtient soient cohérents à vitesse de marche/course, mais il serait préférable d'**effectuer plus de tests avant d'utiliser cette technique dans une application**. De plus, **la méthode même dans le cas où elle serait prouvée correcte reste approximative, évitez donc d'utiliser cette technique dans des applications nécessitant de la précision**.
 +
 +<code Python>
 +import cv2
 +import sys
 +import math
 +
 +if len(sys.argv) != 2:
 +    print("Usage: python speedmeasure.py distance_in_meters")
 +    exit(-1)
 +
 +cam = cv2.VideoCapture(0)
 +width = 640
 +height = 480
 +
 +cam.set(cv2.CAP_PROP_FRAME_WIDTH, width)
 +cam.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
 +
 +fov = math.radians(53.5)
 +meters_per_pixel = 2 * math.sin(fov/2) * float(sys.argv[1])/width
 +
 +frame_count = 0
 +
 +grabbedAFrame, firstFrame = cam.read()
 +
 +if not grabbedAFrame:
 +    print("ERROR: Could not grab the first frame from the camera.")
 +    exit(-2)
 +
 +firstFrame = cv2.cvtColor(firstFrame, cv2.COLOR_BGR2GRAY)
 +firstFrame = cv2.GaussianBlur(firstFrame, (21, 21), 0)
 +firstFrame = firstFrame.astype("float")
 +
 +boxMid = 0
 +t0 = cv2.getTickCount()
 +t1 = t0
 +x, y, w, h = 0, 0, 0, 0
 +
 +# Nombre d'images entre chaque calcul de la vitesse, on aurait également pu utiliser une contrainte temporelle
 +frames_before_refresh = 10
 +
 +while frame_count < 400: 
 +    grabbedAFrame, frame = cam.read()
 +
 +    if not grabbedAFrame: 
 +        continue
 +
 +    frame_count = frame_count + 1
 +    
 +    grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
 +    greyFrame = cv2.GaussianBlur(grayFrame, (21, 21), 0)
 +
 +    cv2.accumulateWeighted(greyFrame, firstFrame, 0.5)
 +    diff = cv2.absdiff(cv2.convertScaleAbs(firstFrame), greyFrame)
 +    thresh = cv2.threshold(diff, 24, 255, cv2.THRESH_BINARY)[1]
 +
 +    thresh = cv2.dilate(thresh, None, iterations=2)
 +    _, contours, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
 +
 +    if len(contours) != 0:
 +        cnt_m = contours[0]
 +        area_m = cv2.contourArea(cnt_m)
 +
 +
 +        for cnt in contours[1:]:
 +            area = cv2.contourArea(cnt)
 +            if area > area_m:
 +                area_m = area
 +                cnt_m = cnt
 +
 +        if frame_count % frames_before_refresh == 0:
 +            t2 = cv2.getTickCount()
 +            x, y, w, h = cv2.boundingRect(cnt_m)
 +            newMid = x + w/2
 +            elapsed = (t2 - t1)/cv2.getTickFrequency()
 +            pixels_per_sec = abs(newMid - boxMid)/elapsed
 +            print('Speed (pixels/s): ' + str(pixels_per_sec))
 +            print('Speed (m/s): ' + str(pixels_per_sec * meters_per_pixel))
 +            print('FPS: ' + str(frames_before_refresh/elapsed) + '\n')
 +            t1 = t2
 +            boxMid = newMid
 +    # A dé-commenter si vous voulez un retour vidéo
 +    # cv2.rectangle(greyFrame, (x, y), (x+w, y+h), (0, 255, 0), 2)
 +
 +    # cv2.imshow('frame', greyFrame)  
 +    # cv2.waitKey(1)
 +    
 +# cv2.destroyAllWindows()
 +</code>
  
 ---- ----
 //Auteur: S. Durand// //Auteur: S. Durand//
diy/projets/approximationvitesse.1531945924.txt.gz · Dernière modification : 2018/07/18 20:32 de sdurand