1. ############################################################################
    #
    #   Name:           optical_flow_cv.py
    #   Python:         3.5.1 on win32
    #   Autor:          Adrian Haas
    #   
    ############################################################################
    #  Calculate optical flow tracking element
    ############################################################################
    #
    # Claculates the optical flow, to move a virtual object. For optical flow
    # calculation opencv is used:
    # https://opencv-python-tutroals.readthedocs.io/en/latest/ -> Video Analysis
    #
    ############################################################################
    
    import numpy
    import warnings
    import cv2
    from scipy import ndimage as fil, signal as sgn
    from matplotlib import pyplot as plt, animation, colors
    from subprocess import Popen, PIPE
    from mpl_toolkits.axes_grid1.inset_locator import inset_axes
    from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes
    from video_metadata import metadata
    from track import sq_tr
    
    
    ############################################################################
    #read video
    ############################################################################
    
    
    ############################################################################
    #a) header information
    ############################################################################
    
    movie="MVI_4234.MOV"
    warnings.filterwarnings("ignore")
    
    info=metadata(movie)
    xline=info.width
    yline=info.height
    duration=info.duration
    framerate=info.rate
    
    ############################################################################
    #b) read video
    ############################################################################
    
    #open pipe for reading
    p = Popen(['ffmpeg', '-i',movie,'-ss','0','-f', 'image2pipe', '-pix_fmt',
               'rgb24', '-vcodec', 'rawvideo', '-'], stdout=PIPE)
    
    
    ############################################################################
    #Animation function
    ############################################################################
    
    def ani(i):
    
       global oldpic,pos_x,pos_y
    
       #READ NEXT FRAME
    
       newimage=p.stdout.read(xline*yline*3)
       image=numpy.fromstring(newimage,dtype='uint8').reshape((yline,xline,3))
       image2=image.copy() #restore orginal img for plot
    
       #rgb->bw  
       newpic=numpy.mean(image,axis=2)
       newpic=numpy.floor(newpic)
    
       if i==0:
          oldpic=newpic
    
    
       #OPTICAL FLOW CALCULATION
    
       flow = cv2.calcOpticalFlowFarneback(newpic,oldpic, None,
                                           0.5, 3, 15, 3, 5, 1.2, 0)
       f1=-flow[...,0]
       f2=-flow[...,1]
    
    
       #calculate angle and magnitude
       theta=numpy.arctan2(-f2,f1)
       f_abs=(f1**2+f2**2)**0.5
    
       #COLOR CODING
    
       # angle as hue
       theta0=theta+numpy.pi/2
       maskt=theta0<0
       theta0[maskt]=theta0[maskt]+2*numpy.pi
    
       h=(theta0)/(2*numpy.pi)
    
    
       # set full saturation
       s=numpy.zeros((yline,xline))
       s[:,:]=1
    
       # magnitude as value
       if i>0:
          f_abs=f_abs/numpy.max(f_abs) 
       v=f_abs
    
    
       #CREATE COLOR CODE IMAGE
       hsv=numpy.dstack((h,s,v))
       rgbout=255*colors.hsv_to_rgb(hsv)
       image=numpy.uint8(rgbout)
    
    
       #DEFINE SHIFT VECTOR
    
       #caluate mean for an area
    
       f1_mean=-numpy.mean(f1[pos1.ya:pos1.yb,pos1.xa:pos1.xb])
       f2_mean=-numpy.mean(f2[pos1.ya:pos1.yb,pos1.xa:pos1.xb])
    
       direction=numpy.arctan2(-f2_mean,f1_mean)
    
       #define x and y value of the pointer
       dir_x=numpy.cos(direction-numpy.pi/2)
       dir_y=numpy.sin(direction-numpy.pi/2)
    
    
       #UPDATE OBJECTS
    
       oldpic=newpic.copy()
    
       #set new animation frame
    
    
       pic.set_data(image)
       pic2.set_data(image2)
    
       zeiger.set_xdata(240+100*dir_y)
       zeiger.set_ydata(320+100*dir_x)
    
       zeiger2.set_xdata([240,240+100*dir_y])
       zeiger2.set_ydata([320,320+100*dir_x])
    
    
    
       #start position
       if i==0:
          pos_x=350
          pos_y=250
    
       pos_x-=f1_mean
       pos_y-=f2_mean
    
       pos1.update(int(pos_x),int(pos_y),21)
    
       #status report
       if i%10==0:
          print(str(numpy.round((i/duration/framerate)*100,2))+" %")
    
       return pic,pic2,zeiger,zeiger2,
    
    
    ############################################################################
    #Plot definition
    ############################################################################
    
    #INIT
    
    #output and input image
    
    pic0=numpy.zeros(yline*xline*3).reshape((yline,xline,3))
    pic20=numpy.zeros(yline*xline*3).reshape((yline,xline,3))
    
    dir_x=0
    dir_y=0
    
    
    
    #legend image
    
    centerx=xline/2
    centery=yline/2
    
    degree_table=numpy.fliplr(numpy.fromfunction(lambda i,j:
          numpy.angle((i-centerx)+1j*(j-centery)),(xline,yline),dtype=int))
    
    h=(degree_table+numpy.pi)/(2*numpy.pi)
    s=numpy.zeros((xline,yline))
    v=numpy.zeros((xline,yline))
    
    s[:,:]=1
    v[:,:]=0.8
    
    hsv=numpy.dstack((h,s,v))
    hsv=numpy.flipud(hsv) #as opencv has upside down
    rgbout=255*colors.hsv_to_rgb(hsv)
    legend=numpy.uint8(rgbout)
    
    
    #DEFINE PLOT
    
    
    fig = plt.figure(frameon=False)
    fig.set_size_inches(19.2,10.8) # 1 inch 100 pixel
    
    ax = plt.Axes(fig, [0., 0., 1., 1.])
    ax.set_axis_off()
    fig.add_axes(ax)
    
    #Optical flow image (right)
    axins=plt.axes([640/1920,0,1280/1920,960/1080])
    axins.text(10.0, 15,"Optischer Fluss, opencv Farneback",
               color="white",fontsize=20)
    
    
    pic=axins.imshow(pic0,aspect="auto")
    
    plt.tick_params(
        which='both',      
        bottom='off',      
        top='off',         
        labelbottom='off', 
        left='off',
        labelleft='off',
        right='off')
    
    pos1=sq_tr(500,450,21) #track object
    
    plt.ylim(480,0)
    plt.xlim(0,640)
    
    
    #Input image (left bottom)
    
    axins=plt.axes([0,0,640/1920,480/1080])
    axins.text(10.0, 30,"Orignalbild",color="white",fontsize=20)
    
    pic2=axins.imshow(pic20,aspect="auto")
    
    plt.tick_params(
        which='both',      
        bottom='off',     
        top='off',         
        labelbottom='off', 
        left='off',
        labelleft='off',
        right='off')
    
    
    #title (top of top)
    
    axins=plt.axes([0,960/1080,1920/1920,120/1080])
    axins.text(10.0, 0.0,"Giessbach",color="white",fontsize=20)
    axins.set_axis_bgcolor("black")
    
    plt.tick_params(
        which='both',      
        bottom='off',      
        top='off',         
        labelbottom='off', 
        left='off',
        labelleft='off',
        right='off')
    
    
    #Legend(left top)
    
    axins=plt.axes([0,480/1080,640/1920,480/1080])
    axins.text(10.0, 40,"Richtung",color="white",fontsize=20)
    axins.text(100.0, 320,"$270\degree$",color="white",fontsize=14)
    axins.text(380.0, 320,"$90\degree$",color="white",fontsize=14)
    axins.text(240.0, 100,"$0\degree$",color="white",fontsize=14)
    axins.text(230.0, 540,"$180\degree$",color="white",fontsize=14)
    axins.imshow(legend,aspect="auto")
    
    zeiger,=plt.plot(240+dir_y,320+dir_x,"ko")
    zeiger2,=plt.plot([240,240+dir_y],[320,320+dir_x],color="black")
    
    plt.tick_params(
        which='both',      
        bottom='off',      
        top='off',        
        labelbottom='off', 
        left='off',
        labelleft='off',
        right='off')
    
    plt.ylim(640,0)
    plt.xlim(0,480)
    
    
    ############################################################################
    #Animate and write video
    ############################################################################
    
    #define objects
    Writer = animation.writers['ffmpeg']
    
    writer = Writer(fps=2*25, metadata=dict(artist='Haas Adrian'), bitrate=45675,
                    extra_args=['-vcodec', 'libx264', '-pix_fmt', 'yuv420p'])
    
    movie_ani = animation.FuncAnimation(fig, ani, frames=int(duration*framerate),
                                        interval=1, blit=False)
    
    movie_ani.save('video1.mp4', writer=writer)
    
    p.stdout.close()
    #plt.show()