Python code

Open a new folder and place a new python file in this folder. This will be your project folder. Open your project in your favourite code editor and navigate to your project folder.

Import Libraries

import numpy as np
import cv2
from time import time
import pafy
import requests

requests -> to send data using post

numpy and cv2 -> to analyze data from a video

pafy -> to make opencv work with youtube-dl so you can use youtube videos

Define variables

#tweak these settings to get more accurate predictions
min_contour_width=100  #original = 40 
min_contour_height=100  # original = 40
offset=5       # original = 10


# define variables and functions
matches =[]
start_time = time()
seconds = 600
cars=0
def get_centroid(x, y, w, h):
    x1 = int(w / 2)
    y1 = int(h / 2)

    cx = x + x1
    cy = y + y1
    return cx,cy
    #return (cx, cy)

Choose the input

Decide what your input will be. To change the Youtube video, just change the URL variable. In this example we use a youtube livestream. but it also can be:

  • name of video file (eg. video.avi)
  • image (eg. img_02.jpg)
  • URL of video stream (eg. protocol://host:port/script_name script_params|auth)
  • a camera attached to the device (eg. 0 or 1)
# cap = cv2.VideoCapture(0) will open the webcam
URL = "https://www.youtube.com/watch?v=y7QiNgui5Tg" #URL to parse
play = pafy.new(URL).streams[-1] #'-1' means read the lowest quality of video.
assert play is not None # we want to make sure their is a input to read.
cap = cv2.VideoCapture(play.url) #create a opencv video stream.


if cap.isOpened():
    ret,frame1 = cap.read()
else:
    ret = False
ret,frame1 = cap.read()
ret,frame2 = cap.read()

Detect movement

With these lines of code we can detect mouvement on our video. Around the moving objects a rectangle will be drawn so the program can track its position. If the object (car) passes a certain x and y value, increase the cars counter. Send after some time a post request with the amount of cars passed and set the counter back to 0.

while ret:
    d = cv2.absdiff(frame1,frame2)
    grey = cv2.cvtColor(d,cv2.COLOR_BGR2GRAY)
    #blur = cv2.GaussianBlur(grey,(5,5),0)
    blur = cv2.GaussianBlur(grey,(5,5),0)
    #ret , th = cv2.threshold(blur,20,255,cv2.THRESH_BINARY)
    ret , th = cv2.threshold(blur,20,255,cv2.THRESH_BINARY)
    dilated = cv2.dilate(th,np.ones((3,3)))
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2, 2))

        # Fill any small holes
    closing = cv2.morphologyEx(dilated, cv2.MORPH_CLOSE, kernel) 
    contours,h = cv2.findContours(closing,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    for(i,c) in enumerate(contours):
        (x,y,w,h) = cv2.boundingRect(c)
        contour_valid = (w >= min_contour_width) and (
            h >= min_contour_height)

        if not contour_valid:
            continue
        cv2.rectangle(frame1,(x-10,y-10),(x+w+10,y+h+10),(255,0,0),2)
        
        cv2.line(frame1, (1100, 750), (1100, 300), (255,127,0), 3) 
        centroid = get_centroid(x, y, w, h)
        matches.append(centroid)
        cv2.circle(frame1,centroid, 5, (0,255,0), -1)
        cx,cy= get_centroid(x, y, w, h)
        for (x,y) in matches:

            # do a post request and send the amount of cars passed in the last .. seconds
            if time() - start_time > seconds:
                post_url = "https://project40-tm.herokuapp.com/stats/car"
                myobj = {'amount': cars}
                requests.post(post_url, json = myobj)
                cars = 0
                start_time = time()

            #if car passed a certain line, increase the counter of cars with one    
            if y<(750+offset) and y>(300-offset) and x>(1100-offset) and x<(1100+offset):
                cars=cars+1
                matches.remove((x,y))

# uncomment the lines below to see what the code does if you run it locally

    # cv2.drawContours(frame1,contours,-1,(0,0,255),2)
    # cv2.imshow("Original" , frame1)
    # cv2.imshow("Difference" , th)
    # if cv2.waitKey(1) == 27:
    #     break
    frame1 = frame2
    ret , frame2 = cap.read()
# print(matches)    
# cv2.destroyAllWindows()
# cap.release()

You are now ready to run your code. Test it locally and see if it works! Try to change the variables to make the predictions even more accurate. When the code works like intented, you are ready to publish it. We are going to publish it on Heroku. Complete code found on Github

Screenshot of car detection on a live stream Screenshot of car detection on a live stream