// Author: Ce Liu (c) Dec, 2009; celiu@mit.edu // Modified By: Deepak Pathak (c) 2016; pathak@berkeley.edu #include "OpticalFlow.hpp" #include "ImageProcessing.hpp" #include "GaussianPyramid.hpp" #include #include using namespace std; #ifndef _MATLAB bool OpticalFlow::IsDisplay=false; #else bool OpticalFlow::IsDisplay=false; #endif //OpticalFlow::InterpolationMethod OpticalFlow::interpolation = OpticalFlow::Bicubic; OpticalFlow::InterpolationMethod OpticalFlow::interpolation = OpticalFlow::Bilinear; OpticalFlow::NoiseModel OpticalFlow::noiseModel = OpticalFlow::Lap; GaussianMixture OpticalFlow::GMPara; Vector OpticalFlow::LapPara; OpticalFlow::OpticalFlow(void) { } OpticalFlow::~OpticalFlow(void) { } //-------------------------------------------------------------------------------------------------------- // function to compute dx, dy and dt for motion estimation //-------------------------------------------------------------------------------------------------------- void OpticalFlow::getDxs(DImage &imdx, DImage &imdy, DImage &imdt, const DImage &im1, const DImage &im2) { //double gfilter[5]={0.01,0.09,0.8,0.09,0.01}; double gfilter[5]={0.02,0.11,0.74,0.11,0.02}; //double gfilter[5]={0,0,1,0,0}; if(1) { //DImage foo,Im; //Im.Add(im1,im2); //Im.Multiplywith(0.5); ////foo.imfilter_hv(Im,gfilter,2,gfilter,2); //Im.dx(imdx,true); //Im.dy(imdy,true); //imdt.Subtract(im2,im1); DImage Im1,Im2,Im; im1.imfilter_hv(Im1,gfilter,2,gfilter,2); im2.imfilter_hv(Im2,gfilter,2,gfilter,2); Im.copyData(Im1); Im.Multiplywith(0.4); Im.Add(Im2,0.6); //Im.Multiplywith(0.5); //Im1.copyData(im1); //Im2.copyData(im2); Im.dx(imdx,true); Im.dy(imdy,true); imdt.Subtract(Im2,Im1); } else { // Im1 and Im2 are the smoothed version of im1 and im2 DImage Im1,Im2; im1.imfilter_hv(Im1,gfilter,2,gfilter,2); im2.imfilter_hv(Im2,gfilter,2,gfilter,2); //Im1.copyData(im1); //Im2.copyData(im2); Im2.dx(imdx,true); Im2.dy(imdy,true); imdt.Subtract(Im2,Im1); } imdx.setDerivative(); imdy.setDerivative(); imdt.setDerivative(); } //-------------------------------------------------------------------------------------------------------- // function to do sanity check: imdx*du+imdy*dy+imdt=0 //-------------------------------------------------------------------------------------------------------- void OpticalFlow::SanityCheck(const DImage &imdx, const DImage &imdy, const DImage &imdt, double du, double dv) { if(imdx.matchDimension(imdy)==false || imdx.matchDimension(imdt)==false) { cout<<"The dimensions of the derivatives don't match!"<imWidth-1-interval || yimHeight-1-interval) continue; pMask[offset]=1; } } void OpticalFlow::genInImageMask(DImage &mask, const DImage &flow,int interval) { int imWidth,imHeight; imWidth=flow.width(); imHeight=flow.height(); if(mask.matchDimension(flow.width(),flow.height(),1)==false) mask.allocate(imWidth,imHeight); else mask.reset(); const _FlowPrecision *pFlow; _FlowPrecision *pMask; pFlow = flow.data();; pMask=mask.data(); double x,y; for(int i=0;iimWidth-1-interval || yimHeight-1-interval) continue; pMask[offset]=1; } } //-------------------------------------------------------------------------------------------------------- // function to compute optical flow field using two fixed point iterations // Input arguments: // Im1, Im2: frame 1 and frame 2 // warpIm2: the warped frame 2 according to the current flow field u and v // u,v: the current flow field, NOTICE that they are also output arguments // //-------------------------------------------------------------------------------------------------------- void OpticalFlow::SmoothFlowSOR(const DImage &Im1, const DImage &Im2, DImage &warpIm2, DImage &u, DImage &v, double alpha, int nOuterFPIterations, int nInnerFPIterations, int nSORIterations) { DImage mask,imdx,imdy,imdt; int imWidth,imHeight,nChannels,nPixels; imWidth=Im1.width(); imHeight=Im1.height(); nChannels=Im1.nchannels(); nPixels=imWidth*imHeight; DImage du(imWidth,imHeight),dv(imWidth,imHeight); DImage uu(imWidth,imHeight),vv(imWidth,imHeight); DImage ux(imWidth,imHeight),uy(imWidth,imHeight); DImage vx(imWidth,imHeight),vy(imWidth,imHeight); DImage Phi_1st(imWidth,imHeight); DImage Psi_1st(imWidth,imHeight,nChannels); DImage imdxy,imdx2,imdy2,imdtdx,imdtdy; DImage ImDxy,ImDx2,ImDy2,ImDtDx,ImDtDy; DImage foo1,foo2; double prob1,prob2,prob11,prob22; double varepsilon_phi=pow(0.001,2); double varepsilon_psi=pow(0.001,2); //-------------------------------------------------------------------------- // the outer fixed point iteration //-------------------------------------------------------------------------- for(int count=0;count1) { ImDxy.collapse(imdxy); ImDx2.collapse(imdx2); ImDy2.collapse(imdy2); ImDtDx.collapse(imdtdx); ImDtDy.collapse(imdtdy); } else { imdxy.copyData(ImDxy); imdx2.copyData(ImDx2); imdy2.copyData(ImDy2); imdtdx.copyData(ImDtDx); imdtdy.copyData(ImDtDy); } // laplacian filtering of the current flow field Laplacian(foo1,u,Phi_1st); Laplacian(foo2,v,Phi_1st); for(int i=0;i0) { _weight = phiData[offset-1]; sigma1 += _weight*du.data()[offset-1]; sigma2 += _weight*dv.data()[offset-1]; coeff += _weight; } if(j0) { _weight = phiData[offset-imWidth]; sigma1 += _weight*du.data()[offset-imWidth]; sigma2 += _weight*dv.data()[offset-imWidth]; coeff += _weight; } if(i1) { ImDxy.collapse(imdxy); ImDx2.collapse(imdx2); ImDy2.collapse(imdy2); ImDtDx.collapse(imdtdx); ImDtDy.collapse(imdtdy); } else { imdxy.copyData(ImDxy); imdx2.copyData(ImDx2); imdy2.copyData(ImDy2); imdtdx.copyData(ImDtDx); imdtdy.copyData(ImDtDy); } // filtering //imdx2.smoothing(A11,3); //imdxy.smoothing(A12,3); //imdy2.smoothing(A22,3); A11.copyData(imdx2); A12.copyData(imdxy); A22.copyData(imdy2); // add epsilon to A11 and A22 A11.Add(alpha*0.5); A22.Add(alpha*0.5); // form b //imdtdx.smoothing(b1,3); //imdtdy.smoothing(b2,3); b1.copyData(imdtdx); b2.copyData(imdtdy); // laplacian filtering of the current flow field Laplacian(foo1,u,Phi_1st); Laplacian(foo2,v,Phi_1st); _FlowPrecision *b1Data,*b2Data; const _FlowPrecision *foo1Data,*foo2Data; b1Data=b1.data(); b2Data=b2.data(); foo1Data=foo1.data(); foo2Data=foo2.data(); for(int i=0;i& para) { int nChannels = Im1.nchannels(); if(para.dim()!=nChannels) para.allocate(nChannels); else para.reset(); double temp; Vector total(nChannels); for(int k = 0;k0 && temp<1000000) { para[k] += temp; total[k]++; } } for(int k = 0;k0) outputData[offset]+=fooData[offset-1]; } foo.reset(); // vertical filtering for(int i=0;i0) outputData[offset]+=fooData[offset-width]; } } void OpticalFlow::testLaplacian(int dim) { // generate the random weight DImage weight(dim,dim); for(int i=0;i=0) printf(" "); printf(" %1.0f ",sysMatrix.data()[i*dim*dim+j]); } printf("\n"); } } //-------------------------------------------------------------------------------------- // function to perfomr coarse to fine optical flow estimation //-------------------------------------------------------------------------------------- void OpticalFlow::Coarse2FineFlow(DImage &vx, DImage &vy, DImage &warpI2,const DImage &Im1, const DImage &Im2, double alpha, double ratio, int minWidth, int nOuterFPIterations, int nInnerFPIterations, int nCGIterations) { // first build the pyramid of the two images GaussianPyramid GPyramid1; GaussianPyramid GPyramid2; if(IsDisplay) cout<<"Constructing pyramid..."; GPyramid1.ConstructPyramid(Im1,ratio,minWidth); GPyramid2.ConstructPyramid(Im2,ratio,minWidth); if(IsDisplay) cout<<"done!"<=0;k--) { if(IsDisplay) cout<<"Pyramid level "<=0;k--) { if(IsDisplay) cout<<"Pyramid level "< foo; if(foo.loadImage(filename) == false) return false; if(!flow.matchDimension(foo)) flow.allocate(foo); for(int i = 0;i foo; if(foo.loadImage(myfile) == false) return false; if(!flow.matchDimension(foo)) flow.allocate(foo); for(int i = 0;i foo; foo.allocate(flow); for(int i =0;i foo; foo.allocate(flow); for(int i =0;i foo; foo.allocate(flow.width(),flow.height()); double Max = flow.max(); double Min = flow.min(); for(int i = 0;i