#Import the OpnenCV libraries 
import cv2

#Import system libraries
import sys

#Import numpy framework as np
import numpy as np

#Import tkinter
from tkinter import *
from tkinter import filedialog

#Initialize the global variable
inpt="0"

#Create main window
top = Tk()

#Function to get the input
def callback():
    global inpt
    try:
        inpt=int(E1.get())
    except:
        print("Enter proper camera number")
        top.destroy()
        sys.exit()
    top.destroy()

#Function to get the browsed file path
def browsefunc():
    global inpt
    filename = filedialog.askopenfilename()
    inpt=filename
    top.destroy()

#Label about browse button 
info1 = Label(top, text="Browse the video file")
info1.grid(row=0,padx=50,pady=(30,5))

#Browse button
browsebutton = Button(top, text="Browse", command=browsefunc)
browsebutton.grid(row=2,padx=50,pady=5)

#Label to try another approach to get started
info2 = Label(top, text="Or")
info2.grid(row=3,padx=50,pady=10)

#Label about input box
info3 = Label(top, text="Enter the camera number")
info3.grid(row=4,padx=50,pady=5)

#Input box
E1 = Entry(top)
E1.grid(row=5,padx=50,pady=5)

#Submit button for the input box
MyButton1 = Button(top, text="Submit", width=10, command=callback)
MyButton1.grid(row=6,padx=50,pady=(5,30))

#Main event loop to take action against each event triggered by the user
top.mainloop()


#Input the video file
inp=cv2.VideoCapture(inpt)

#Mask generated by MOG2 method
fgbg=cv2.createBackgroundSubtractorMOG2()

#Initialize counter value to zero
i=0

#Initialize minimum area of an object can be
minArea=10000

#While loop to loop through each frame
while True:

    #Capture each frame in variable frame
    _,frame=inp.read()

    try:
        #Get the shape of a frame
        height, width, channels = frame.shape
    except:
        sys.exit()
    
    #Convert frame to gray scale
    gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)

    #Apply MOG2 mask to gray scaled frame
    fgmask=fgbg.apply(gray,None,0.01)

    #Apply threshold to fgmask frame to get rid of shadow
    ret,thresh = cv2.threshold(fgmask,127,255,cv2.THRESH_BINARY)

    #Create 15x15 matrix of ones
    kernel = np.ones((15,15),np.uint8)

    #Apply morphologyEx to threshold frame 
    '''It is the difference between dilation and erosion of an image.
    The result will look like the outline of the object.'''
    outline = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)

    #Create 70x70 matrix of ones
    kernel = np.ones((70,70),np.uint8)

    #Apply Dilation to outline with kernel
    '''A pixel element is ‘1’ if atleast one pixel under the kernel is ‘1’.
    So it increases the white region in the image or size of foreground object increases.'''
    newone=cv2.dilate(outline,kernel)
    
    #Find all the contours present in the frame
    '''Contours can be explained simply as a curve joining all the continuous points
    along the boundary), having same color or intensity.
    The contours are a useful tool for shape analysis and object detection and recognition.'''
    contours, hierarchy = cv2.findContours(newone,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

    #Loop through each contours that are found in the frame found
    for c in contours:

        #Apply moments method to each current contour
        '''Image moments help you to calculate some features like center of mass of the object, area of the object etc'''
        M=cv2.moments(c)

        #This gives centroid of the contour
        #Calculate the x co-ordinate of centroid
        cX = int(M["m10"] / M["m00"])
        #Calculate the y co-ordinate of centroid
        cY = int(M["m01"] / M["m00"])

        #Find the area of the given contour and check if its less then minimum area
        if cv2.contourArea(c) < minArea:
            #If it's less then the minimum area then ignore the contour
            continue

        #Check if the centroid of the contour is crossing the virtual line
        if(cY>int(height/2) and cY<int(height/2)+20):

            #If it crosses the line increment the counter variable means count the vehicle
            i+=1
        
    #Draw the virtual line
    cv2.line(frame,(0,int(height/2)),(int(width),int(height/2)),(255,0,0),3)

    #Show the number of counted vehicle on frame
    cv2.putText(frame,'COUNT: %r' %i, (10,70), cv2.FONT_HERSHEY_SIMPLEX,3, (0, 0, 255), 5)

    #Show the output 
    cv2.imshow("Output",frame)

    #Checking if the Esc is clicked
    if cv2.waitKey(30) == 27:

        #If clicked then exit the loop
        break

#Release the input resource
inp.release()

#Close all the windows
cv2.destroyAllWindows()
