Repository for OpenCV's extra modules
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

406 lines
17 KiB

// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "precomp.hpp"
#include "rlof/rlof_localflow.h"
#include "rlof/geo_interpolation.hpp"
#include "opencv2/ximgproc.hpp"
namespace cv {
namespace optflow {
Ptr<RLOFOpticalFlowParameter> RLOFOpticalFlowParameter::create()
{
return Ptr<RLOFOpticalFlowParameter>(new RLOFOpticalFlowParameter);
}
void RLOFOpticalFlowParameter::setSolverType(SolverType val){ solverType = val;}
SolverType RLOFOpticalFlowParameter::getSolverType() const { return solverType;}
void RLOFOpticalFlowParameter::setSupportRegionType(SupportRegionType val){ supportRegionType = val;}
SupportRegionType RLOFOpticalFlowParameter::getSupportRegionType() const { return supportRegionType;}
void RLOFOpticalFlowParameter::setNormSigma0(float val){ normSigma0 = val;}
float RLOFOpticalFlowParameter::getNormSigma0() const { return normSigma0;}
void RLOFOpticalFlowParameter::setNormSigma1(float val){ normSigma1 = val;}
float RLOFOpticalFlowParameter::getNormSigma1() const { return normSigma1;}
void RLOFOpticalFlowParameter::setSmallWinSize(int val){ smallWinSize = val;}
int RLOFOpticalFlowParameter::getSmallWinSize() const { return smallWinSize;}
void RLOFOpticalFlowParameter::setLargeWinSize(int val){ largeWinSize = val;}
int RLOFOpticalFlowParameter::getLargeWinSize() const { return largeWinSize;}
void RLOFOpticalFlowParameter::setCrossSegmentationThreshold(int val){ crossSegmentationThreshold = val;}
int RLOFOpticalFlowParameter::getCrossSegmentationThreshold() const { return crossSegmentationThreshold;}
void RLOFOpticalFlowParameter::setMaxLevel(int val){ maxLevel = val;}
int RLOFOpticalFlowParameter::getMaxLevel() const { return maxLevel;}
void RLOFOpticalFlowParameter::setUseInitialFlow(bool val){ useInitialFlow = val;}
bool RLOFOpticalFlowParameter::getUseInitialFlow() const { return useInitialFlow;}
void RLOFOpticalFlowParameter::setUseIlluminationModel(bool val){ useIlluminationModel = val;}
bool RLOFOpticalFlowParameter::getUseIlluminationModel() const { return useIlluminationModel;}
void RLOFOpticalFlowParameter::setUseGlobalMotionPrior(bool val){ useGlobalMotionPrior = val;}
bool RLOFOpticalFlowParameter::getUseGlobalMotionPrior() const { return useGlobalMotionPrior;}
void RLOFOpticalFlowParameter::setMaxIteration(int val){ maxIteration = val;}
int RLOFOpticalFlowParameter::getMaxIteration() const { return maxIteration;}
void RLOFOpticalFlowParameter::setMinEigenValue(float val){ minEigenValue = val;}
float RLOFOpticalFlowParameter::getMinEigenValue() const { return minEigenValue;}
void RLOFOpticalFlowParameter::setGlobalMotionRansacThreshold(float val){ globalMotionRansacThreshold = val;}
float RLOFOpticalFlowParameter::getGlobalMotionRansacThreshold() const { return globalMotionRansacThreshold;}
class DenseOpticalFlowRLOFImpl : public DenseRLOFOpticalFlow
{
public:
DenseOpticalFlowRLOFImpl()
: param(Ptr<RLOFOpticalFlowParameter>(new RLOFOpticalFlowParameter))
, forwardBackwardThreshold(1.f)
, gridStep(6, 6)
, interp_type(InterpolationType::INTERP_GEO)
, k(128)
, sigma(0.05f)
, lambda(999.f)
, fgs_lambda(500.0f)
, fgs_sigma(1.5f)
, use_post_proc(true)
{
prevPyramid[0] = cv::Ptr<CImageBuffer>(new CImageBuffer);
prevPyramid[1] = cv::Ptr<CImageBuffer>(new CImageBuffer);
currPyramid[0] = cv::Ptr<CImageBuffer>(new CImageBuffer);
currPyramid[1] = cv::Ptr<CImageBuffer>(new CImageBuffer);
}
virtual void setRLOFOpticalFlowParameter(Ptr<RLOFOpticalFlowParameter> val) CV_OVERRIDE { param = val; }
virtual Ptr<RLOFOpticalFlowParameter> getRLOFOpticalFlowParameter() const CV_OVERRIDE { return param; }
virtual float getForwardBackward() const CV_OVERRIDE { return forwardBackwardThreshold; }
virtual void setForwardBackward(float val) CV_OVERRIDE { forwardBackwardThreshold = val; }
virtual void setInterpolation(InterpolationType val) CV_OVERRIDE { interp_type = val; }
virtual InterpolationType getInterpolation() const CV_OVERRIDE { return interp_type; }
virtual Size getGridStep() const CV_OVERRIDE { return gridStep; }
virtual void setGridStep(Size val) CV_OVERRIDE { gridStep = val; }
virtual int getEPICK() const CV_OVERRIDE { return k; }
virtual void setEPICK(int val) CV_OVERRIDE { k = val; }
virtual float getEPICSigma() const CV_OVERRIDE { return sigma; }
virtual void setEPICSigma(float val) CV_OVERRIDE { sigma = val; }
virtual float getEPICLambda() const CV_OVERRIDE { return lambda; }
virtual void setEPICLambda(float val) CV_OVERRIDE { lambda = val; }
virtual float getFgsLambda() const CV_OVERRIDE { return fgs_lambda; }
virtual void setFgsLambda(float val) CV_OVERRIDE { fgs_lambda = val; }
virtual float getFgsSigma() const CV_OVERRIDE { return fgs_sigma; }
virtual void setFgsSigma(float val) CV_OVERRIDE { fgs_sigma = val; }
virtual bool getUsePostProc() const CV_OVERRIDE { return use_post_proc; }
virtual void setUsePostProc(bool val) CV_OVERRIDE { use_post_proc = val; }
virtual void calc(InputArray I0, InputArray I1, InputOutputArray flow) CV_OVERRIDE
{
CV_Assert(!I0.empty() && I0.depth() == CV_8U && (I0.channels() == 3 || I0.channels() == 1));
CV_Assert(!I1.empty() && I1.depth() == CV_8U && (I1.channels() == 3 || I1.channels() == 1));
CV_Assert(I0.sameSize(I1));
if (param.empty())
param = Ptr<RLOFOpticalFlowParameter>(new RLOFOpticalFlowParameter());
if (param->supportRegionType == SR_CROSS)
CV_Assert( I0.channels() == 3 && I1.channels() == 3);
CV_Assert(interp_type == InterpolationType::INTERP_EPIC || interp_type == InterpolationType::INTERP_GEO);
// if no parameter is used use the default parameter
Mat prevImage = I0.getMat();
Mat currImage = I1.getMat();
int noPoints = prevImage.cols * prevImage.rows;
std::vector<cv::Point2f> prevPoints(noPoints);
std::vector<cv::Point2f> currPoints, refPoints;
noPoints = 0;
cv::Size grid_h = gridStep / 2;
for (int r = grid_h.height; r < prevImage.rows - grid_h.height; r += gridStep.height)
{
for (int c = grid_h.width; c < prevImage.cols - grid_h.width; c += gridStep.width)
{
prevPoints[noPoints++] = cv::Point2f(static_cast<float>(c), static_cast<float>(r));
}
}
prevPoints.erase(prevPoints.begin() + noPoints, prevPoints.end());
currPoints.resize(prevPoints.size());
calcLocalOpticalFlow(prevImage, currImage, prevPyramid, currPyramid, prevPoints, currPoints, *(param.get()));
flow.create(prevImage.size(), CV_32FC2);
Mat dense_flow = flow.getMat();
std::vector<Point2f> filtered_prevPoints;
std::vector<Point2f> filtered_currPoints;
if (gridStep == cv::Size(1, 1) && forwardBackwardThreshold <= 0)
{
for (unsigned int n = 0; n < prevPoints.size(); n++)
{
dense_flow.at<Point2f>(prevPoints[n]) = currPoints[n] - prevPoints[n];
}
return;
}
if (forwardBackwardThreshold > 0)
{
// reuse image pyramids
calcLocalOpticalFlow(currImage, prevImage, currPyramid, prevPyramid, currPoints, refPoints, *(param.get()));
filtered_prevPoints.resize(prevPoints.size());
filtered_currPoints.resize(prevPoints.size());
float sqrForwardBackwardThreshold = forwardBackwardThreshold * forwardBackwardThreshold;
noPoints = 0;
for (unsigned int r = 0; r < refPoints.size(); r++)
{
Point2f diff = refPoints[r] - prevPoints[r];
if (diff.x * diff.x + diff.y * diff.y < sqrForwardBackwardThreshold)
{
filtered_prevPoints[noPoints] = prevPoints[r];
filtered_currPoints[noPoints++] = currPoints[r];
}
}
filtered_prevPoints.erase(filtered_prevPoints.begin() + noPoints, filtered_prevPoints.end());
filtered_currPoints.erase(filtered_currPoints.begin() + noPoints, filtered_currPoints.end());
}
else
{
filtered_prevPoints = prevPoints;
filtered_currPoints = currPoints;
}
if (interp_type == InterpolationType::INTERP_EPIC)
{
Ptr<ximgproc::EdgeAwareInterpolator> gd = ximgproc::createEdgeAwareInterpolator();
gd->setK(k);
gd->setSigma(sigma);
gd->setLambda(lambda);
gd->setUsePostProcessing(false);
gd->interpolate(prevImage, filtered_prevPoints, currImage, filtered_currPoints, dense_flow);
}
else
{
Mat blurredPrevImage, blurredCurrImage;
GaussianBlur(prevImage, blurredPrevImage, cv::Size(5, 5), -1);
std::vector<uchar> status(filtered_currPoints.size(), 1);
interpolate_irregular_nn_raster(filtered_prevPoints, filtered_currPoints, status, blurredPrevImage).copyTo(dense_flow);
std::vector<Mat> vecMats;
std::vector<Mat> vecMats2(2);
cv::split(dense_flow, vecMats);
cv::bilateralFilter(vecMats[0], vecMats2[0], 5, 2, 20);
cv::bilateralFilter(vecMats[1], vecMats2[1], 5, 2, 20);
cv::merge(vecMats2, dense_flow);
}
if (use_post_proc)
{
ximgproc::fastGlobalSmootherFilter(prevImage, flow, flow, fgs_lambda, fgs_sigma);
}
}
virtual void collectGarbage() CV_OVERRIDE
{
prevPyramid[0].release();
prevPyramid[1].release();
currPyramid[0].release();
currPyramid[1].release();
}
protected:
Ptr<RLOFOpticalFlowParameter> param;
float forwardBackwardThreshold;
Ptr<CImageBuffer> prevPyramid[2];
Ptr<CImageBuffer> currPyramid[2];
cv::Size gridStep;
InterpolationType interp_type;
int k;
float sigma;
float lambda;
float fgs_lambda;
float fgs_sigma;
bool use_post_proc;
};
Ptr<DenseRLOFOpticalFlow> DenseRLOFOpticalFlow::create(
Ptr<RLOFOpticalFlowParameter> rlofParam,
float forwardBackwardThreshold,
cv::Size gridStep,
InterpolationType interp_type,
int epicK,
float epicSigma,
float epicLambda,
bool use_post_proc,
float fgs_lambda,
float fgs_sigma)
{
Ptr<DenseRLOFOpticalFlow> algo = makePtr<DenseOpticalFlowRLOFImpl>();
algo->setRLOFOpticalFlowParameter(rlofParam);
algo->setForwardBackward(forwardBackwardThreshold);
algo->setGridStep(gridStep);
algo->setInterpolation(interp_type);
algo->setEPICK(epicK);
algo->setEPICSigma(epicSigma);
algo->setEPICLambda(epicLambda);
algo->setUsePostProc(use_post_proc);
algo->setFgsLambda(fgs_lambda);
algo->setFgsSigma(fgs_sigma);
return algo;
}
class SparseRLOFOpticalFlowImpl : public SparseRLOFOpticalFlow
{
public:
SparseRLOFOpticalFlowImpl()
: param(Ptr<RLOFOpticalFlowParameter>(new RLOFOpticalFlowParameter))
, forwardBackwardThreshold(1.f)
{
prevPyramid[0] = cv::Ptr< CImageBuffer>(new CImageBuffer);
prevPyramid[1] = cv::Ptr< CImageBuffer>(new CImageBuffer);
currPyramid[0] = cv::Ptr< CImageBuffer>(new CImageBuffer);
currPyramid[1] = cv::Ptr< CImageBuffer>(new CImageBuffer);
}
virtual void setRLOFOpticalFlowParameter(Ptr<RLOFOpticalFlowParameter> val) CV_OVERRIDE { param = val; }
virtual Ptr<RLOFOpticalFlowParameter> getRLOFOpticalFlowParameter() const CV_OVERRIDE { return param; }
virtual float getForwardBackward() const CV_OVERRIDE { return forwardBackwardThreshold; }
virtual void setForwardBackward(float val) CV_OVERRIDE { forwardBackwardThreshold = val; }
virtual void calc(InputArray prevImg, InputArray nextImg,
InputArray prevPts, InputOutputArray nextPts,
OutputArray status,
OutputArray err) CV_OVERRIDE
{
CV_Assert(!prevImg.empty() && prevImg.depth() == CV_8U && (prevImg.channels() == 3 || prevImg.channels() == 1));
CV_Assert(!nextImg.empty() && nextImg.depth() == CV_8U && (nextImg.channels() == 3 || nextImg.channels() == 1));
CV_Assert(prevImg.sameSize(nextImg));
if (param.empty())
{
param = makePtr<RLOFOpticalFlowParameter>();
}
CV_DbgAssert(!param.empty());
if (param->supportRegionType == SR_CROSS)
{
CV_CheckChannelsEQ(prevImg.channels(), 3, "SR_CROSS mode requires images with 3 channels");
CV_CheckChannelsEQ(nextImg.channels(), 3, "SR_CROSS mode requires images with 3 channels");
}
Mat prevImage = prevImg.getMat();
Mat nextImage = nextImg.getMat();
Mat prevPtsMat = prevPts.getMat();
if (param->useInitialFlow == false)
nextPts.create(prevPtsMat.size(), prevPtsMat.type(), -1, true);
int npoints = 0;
CV_Assert((npoints = prevPtsMat.checkVector(2, CV_32F, true)) >= 0);
if (npoints == 0)
{
nextPts.release();
status.release();
err.release();
return;
}
Mat nextPtsMat = nextPts.getMat();
CV_Assert(nextPtsMat.checkVector(2, CV_32F, true) == npoints);
std::vector<cv::Point2f> prevPoints(npoints), nextPoints(npoints), refPoints;
prevPtsMat.copyTo(cv::Mat(1, npoints, CV_32FC2, &prevPoints[0]));
if (param->useInitialFlow )
nextPtsMat.copyTo(cv::Mat(1, nextPtsMat.cols, CV_32FC2, &nextPoints[0]));
cv::Mat statusMat;
cv::Mat errorMat;
if (status.needed() || forwardBackwardThreshold > 0)
{
status.create((int)npoints, 1, CV_8U, -1, true);
statusMat = status.getMat();
statusMat.setTo(1);
}
if (err.needed() || forwardBackwardThreshold > 0)
{
err.create((int)npoints, 1, CV_32F, -1, true);
errorMat = err.getMat();
errorMat.setTo(0);
}
calcLocalOpticalFlow(prevImage, nextImage, prevPyramid, currPyramid, prevPoints, nextPoints, *(param.get()));
cv::Mat(1,npoints , CV_32FC2, &nextPoints[0]).copyTo(nextPtsMat);
if (forwardBackwardThreshold > 0)
{
// reuse image pyramids
calcLocalOpticalFlow(nextImage, prevImage, currPyramid, prevPyramid, nextPoints, refPoints, *(param.get()));
}
for (unsigned int r = 0; r < refPoints.size(); r++)
{
Point2f diff = refPoints[r] - prevPoints[r];
errorMat.at<float>(r) = sqrt(diff.x * diff.x + diff.y * diff.y);
if (errorMat.at<float>(r) <= forwardBackwardThreshold)
statusMat.at<uchar>(r) = 0;
}
}
protected:
Ptr<RLOFOpticalFlowParameter> param;
float forwardBackwardThreshold;
Ptr<CImageBuffer> prevPyramid[2];
Ptr<CImageBuffer> currPyramid[2];
};
Ptr<SparseRLOFOpticalFlow> SparseRLOFOpticalFlow::create(
Ptr<RLOFOpticalFlowParameter> rlofParam,
float forwardBackwardThreshold)
{
Ptr<SparseRLOFOpticalFlow> algo = makePtr<SparseRLOFOpticalFlowImpl>();
algo->setRLOFOpticalFlowParameter(rlofParam);
algo->setForwardBackward(forwardBackwardThreshold);
return algo;
}
void calcOpticalFlowDenseRLOF(InputArray I0, InputArray I1, InputOutputArray flow,
Ptr<RLOFOpticalFlowParameter> rlofParam ,
float forewardBackwardThreshold, Size gridStep,
InterpolationType interp_type,
int epicK, float epicSigma, float epicLambda,
bool use_post_proc, float fgsLambda, float fgsSigma)
{
Ptr<DenseRLOFOpticalFlow> algo = DenseRLOFOpticalFlow::create(
rlofParam, forewardBackwardThreshold, gridStep, interp_type,
epicK, epicSigma, epicLambda, use_post_proc, fgsLambda, fgsSigma);
algo->calc(I0, I1, flow);
algo->collectGarbage();
}
void calcOpticalFlowSparseRLOF(InputArray prevImg, InputArray nextImg,
InputArray prevPts, InputOutputArray nextPts,
OutputArray status, OutputArray err,
Ptr<RLOFOpticalFlowParameter> rlofParam,
float forewardBackwardThreshold)
{
Ptr<SparseRLOFOpticalFlow> algo = SparseRLOFOpticalFlow::create(
rlofParam, forewardBackwardThreshold);
algo->calc(prevImg, nextImg, prevPts, nextPts, status, err);
}
Ptr<DenseOpticalFlow> createOptFlow_DenseRLOF()
{
return DenseRLOFOpticalFlow::create();
}
Ptr<SparseOpticalFlow> createOptFlow_SparseRLOF()
{
return SparseRLOFOpticalFlow::create();
}
}} // namespace