import cv2 as CvObject
import numpy as np

# PART 1 - Introduction
# Topics
# >> Read frames from camera
# >> Baic Filters (Smoothening,blurring)
# >> Morphological Transformation
# >> Edge Detection

Selext_WebCam = 0
Select_External_Camera = 1
CamTitle = "MyCam"

# Store the captured video inside cap varaiable
capture = CvObject.VideoCapture(Selext_WebCam)



# if camera is open then or started capturing


while (capture.isOpened()):

    

    # Start capturing frames/images 
    
    '''
    cap.read() return two values

    >> ret - able to capture or not (true,false) return values
    >> img - captured Frame 

    '''
    # 'Camera' is an identifier for frame which is taken from camera
    
    ret,Camera = capture.read()

    # Show the title "myimage" and start showing
    # CvObject.imshow(CamTitle,Camera)

    #  Grayscale Camera

    # RGB(Red,Blue,Green) Notation is inverted as BGR in OpenCV
    
    GrayScale = CvObject.cvtColor(Camera,CvObject.COLOR_BGR2GRAY)
    # CvObject.imshow('GrayScale',GrayScale)

    # Detect BLUE COLOR
    
    # BGR to Binary (means only one color is visible) within a particular range
    # Range is defined in BGR 

    
    # Detect in range using hsv (Hue,Saturation,Value)

    lower_color_bound_HSV = np.array([150,100,0])
    upper_color_bound_HSV = np.array([255,180,180]) 

    
    
    imgThreshold = CvObject.inRange(Camera,lower_color_bound_HSV,upper_color_bound_HSV)

    #CvObject.imshow('Thresholded',imgThreshold)
    
    # Bitwise AND will help BlackOut (fill black color) in uncomman region
    # mask will help to put the mask on the comman portion so that it will 
    # look recolored

    MonoColor = CvObject.bitwise_and(Camera,Camera,mask=imgThreshold)
    
    #CvObject.imshow('MonoColor',MonoColor)



    # Blurring and Smoothening

    #Kernel size
    x=5
    y=5

    # Kernel is 15*15 matrix with all element "1", 
    # Kernel will decide smoothness/brurness/sharpness
    # according to the Kernel defination
    # float32 is datatype divide all elements by (15*15=225)
        

    #Kernel Defination
    
    kernel = np.ones((x,y),np.float32)/(x*y)

    # 2D filter consist of 3 parameter
    # >> Frame (I choose GrayScale Frame )
    # >> depth = -1
    # >> kernel Matrix

    # filter2D helps you to build customFilter
    # with the use of kernel Definations
    
    smoothed = CvObject.filter2D(GrayScale,-1,kernel)

    #CvObject.imshow('Smoothed',smoothed)


    # Gaussian Blur :
    
    # It uses Gaussian Probability Distribution in order to remove
    # gaussian noise in the Frame,if Standard deviation(sigmaX,sigmaY)
    # is 0 than deviation is computed using kernel size(x,y)

    sigmaX = 0
    sigmaY = 0

    gaussianblur = CvObject.GaussianBlur(GrayScale,(x,y),sigmaX,sigmaY)

    #CvObject.imshow('Gaussian Blur',gaussianblur)

    # Median Blur - It uses median of the group of pixels to do smoothening

    
    
    kernel_size = x # Only square kernal is allowed
    #medianblur = CvObject.medianBlur(GrayScale,kernel_size)
    
    #CvObject.imshow('Median Blur',medianblur)


    # Bilateral Filter -
    # It is designed to overcome the drawback of Gaussian filter
    # Used to avoid edge smoothening but slower process 
    # intensity of each pixel is replaced by average intensity of it's neighbours
    # it is formulated on the basis of anisotropic diffusion Partial Differentail Eqn
    
    diameter = 15 # diamter of pixel neighbourhood,How many pixels should be selected as neighbourhood
    SigmaColor = 80 # recoloring by calculating neighbour color and equilizing it
    SigmaSpace =  80 # rebuilding pixel intensities according to neighbours creating new space                 
    
    bilateral = CvObject.bilateralFilter(Camera,diameter,SigmaColor,SigmaSpace)
    #CvObject.imshow('BilateralFilter',bilateral)



    # Morphological Transformation - Transformation based on shapes
    

    # Erosion - 

    # erodes the boundary of foreground object
    # or Make Outline more bolder and thicker
    # Remove foreground and make outline thick
    

    # Kernel Defination for erosion
    
    kernel_Erode_or_Dilate = np.ones((2*x,2*y),np.uint8)

    erosion = CvObject.erode(Camera,kernel_Erode_or_Dilate,iterations = 1)
    #CvObject.imshow('Erosion',erosion)

    # Dilation - Opposite of erosion (Remove Outlines) 

    # Remove Outline and make Outline Dilute 

    dilate = CvObject.dilate(Camera,kernel_Erode_or_Dilate,iterations = 1)
    #CvObject.imshow('Dilation',dilate)

    

    # Opening - erosion followed by dilation means after dilution the erosion is compensated (Somehow it Cartoonize) 
    # lighten the Outline than darken the required outline

    opening = CvObject.morphologyEx(Camera,CvObject.MORPH_OPEN,kernel_Erode_or_Dilate)
    #CvObject.imshow('Opening',opening)

    # Closing - dilation followed by erosion means after erosion the dilution is compensated (Make You Ugliest person :P )
    # darken the outline then remove the other unecessary darker outlines

    closing = CvObject.morphologyEx(Camera,CvObject.MORPH_CLOSE,kernel_Erode_or_Dilate)
    #CvObject.imshow('Closing',closing)

    
    # Morphological Gradient - differnce of dilation and erosion

    gradient = CvObject.morphologyEx(Camera,CvObject.MORPH_GRADIENT,kernel_Erode_or_Dilate)
    #CvObject.imshow('Gradient',gradient)

    # Top Hat - difference between Opening and original
    topHat = CvObject.morphologyEx(Camera,CvObject.MORPH_TOPHAT,kernel_Erode_or_Dilate)
    #CvObject.imshow('TopHat',topHat)


    # Black Hat - difference between Closing and original
    BlackHat = CvObject.morphologyEx(Camera,CvObject.MORPH_BLACKHAT,kernel_Erode_or_Dilate)
    #CvObject.imshow('BlackHat',BlackHat)

    # Edge Detection

    # Laplacian - Boundary value Problem
    
    # In Edges, there is High Variation in Intensities between edges and the rest
    # Using First Derrivative we will find the values which can be considered as edge
    # Using Second Derrivative we can confirm whether it is edge or not
    # Laplacian is the way to compute Second derrivative for real valued function
    # if Del(F) = 0 ,Divergence is zero than it is en edge means intensities are not
    # diverging or intensities remains same at the positions where we are supposed to find
    # edges after calculation of first derrivative
    
    
    laplacian = CvObject.Laplacian(Camera,CvObject.CV_64F)
    #CvObject.imshow('Laplacian',laplacian)



    # First Order Derrivative Approaches
    
    # Sobel - 1D Edge scan

    SobelKernelSize = 5


    # For SobelX means scanX for edges or find edges in Y , activateX = 1 and activateY = 0 
    # it can be simply seen by when we find dY/dX , we are finding maxima/minima in 'Y'
    # at given point "X", Y axis edges will be detected
    
    
    activateX = 1 
    activateY = 0

    #sobelX = CvObject.Sobel(Camera,CvObject.CV_64F,activateX ,activateY,ksize = SobelKernelSize)

    #CvObject.imshow('SobelX',sobelX)


    # For SobelY means scanX for edges or find edges in X
    # activateX = 0 and activateY = 1 
    
    activateX = 0 
    activateY = 1
    

    #sobelY = CvObject.Sobel(Camera,CvObject.CV_64F,activateX ,activateY,ksize = SobelKernelSize)

    #CvObject.imshow('SobelY',sobelY)


    # Canny - Based on noise reduction

    # remove x axis noise 200 times

    
    Reduce_noiseX = 200 # reduced noise effect will be found on Y axis OR all edges in x is visible

    Reduce_noiseY = 250 # reduced noise effect will be found on X axis OR all edges in y is visible

    canny = CvObject.Canny(Camera,Reduce_noiseX,Reduce_noiseY)

    CvObject.imshow('Canny',canny)
    
    
    
    # Closing Camera
    
    time = 10 #10  millisec
    key = CvObject.waitKey(time)


    # if key is "ESC" (ASCII = 27) than exit the capturing
    # press hard 

    if key == 27:
        break



capture.release()
CvObject.destroyAllWindows()











    
