############################################################################ # # 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()