/*
* stablizer.cpp - abstract for DVS (Digital Video Stabilizer)
*
* Copyright (c) 2014-2016 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Zong Wei <wei.zong@intel.com>
*/
#include "stabilizer.h"
using namespace cv;
using namespace cv::videostab;
using namespace std;
Mat
OnePassVideoStabilizer::nextStabilizedMotion(DvsData* frame, int& stablizedPos)
{
if (!(frame->data.empty()))
{
Mat image;
frame->data.getMat(ACCESS_READ).copyTo(image);
curPos_++;
if (curPos_ > 0)
{
at(curPos_, frames_) = image;
if (doDeblurring_)
at(curPos_, blurrinessRates_) = calcBlurriness(image);
at(curPos_ - 1, motions_) = estimateMotion();
if (curPos_ >= radius_)
{
curStabilizedPos_ = curPos_ - radius_;
Mat stabilizationMotion = estimateStabilizationMotion();
if (doCorrectionForInclusion_)
stabilizationMotion = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_);
at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion;
stablizedPos = curStabilizedPos_;
return stabilizationMotion;
}
}
else
setUpFrame(image);
log_->print(".");
return Mat();
}
if (curStabilizedPos_ < curPos_)
{
curStabilizedPos_++;
stablizedPos = curStabilizedPos_;
at(curStabilizedPos_ + radius_, frames_) = at(curPos_, frames_);
at(curStabilizedPos_ + radius_ - 1, motions_) = Mat::eye(3, 3, CV_32F);
Mat stabilizationMotion = estimateStabilizationMotion();
if (doCorrectionForInclusion_)
stabilizationMotion = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_);
at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion;
log_->print(".");
return stabilizationMotion;
}
return Mat();
}
Mat
OnePassVideoStabilizer::estimateMotion()
{
#if ENABLE_DVS_CL_PATH
cv::UMat frame0 = at(curPos_ - 1, frames_).getUMat(ACCESS_READ);
cv::UMat frame1 = at(curPos_, frames_).getUMat(ACCESS_READ);
cv::UMat ugrayImage0;
cv::UMat ugrayImage1;
if ( frame0.type() != CV_8U )
{
cvtColor( frame0, ugrayImage0, COLOR_BGR2GRAY );
}
else
{
ugrayImage0 = frame0;
}
if ( frame1.type() != CV_8U )
{
cvtColor( frame1, ugrayImage1, COLOR_BGR2GRAY );
}
else
{
ugrayImage1 = frame1;
}
return motionEstimator_.dynamicCast<KeypointBasedMotionEstimator>()->estimate(ugrayImage0, ugrayImage1);
#else
return motionEstimator_.dynamicCast<KeypointBasedMotionEstimator>()->estimate(at(curPos_ - 1, frames_), at(curPos_, frames_));
#endif
}
void
OnePassVideoStabilizer::setUpFrame(const Mat &firstFrame)
{
frameSize_ = firstFrame.size();
frameMask_.create(frameSize_, CV_8U);
frameMask_.setTo(255);
int cacheSize = 2 * radius_ + 1;
frames_.resize(2);
motions_.resize(cacheSize);
stabilizationMotions_.resize(cacheSize);
for (int i = -radius_; i < 0; ++i)
{
at(i, motions_) = Mat::eye(3, 3, CV_32F);
at(i, frames_) = firstFrame;
}
at(0, frames_) = firstFrame;
StabilizerBase::setUp(firstFrame);
}
Mat
TwoPassVideoStabilizer::nextStabilizedMotion(DvsData* frame, int& stablizedPos)
{
if (!(frame->data.empty()))
{
Mat image;
frame->data.getMat(ACCESS_READ).copyTo(image);
curPos_++;
if (curPos_ > 0)
{
at(curPos_, frames_) = image;
if (doDeblurring_)
at(curPos_, blurrinessRates_) = calcBlurriness(image);
at(curPos_ - 1, motions_) = estimateMotion();
if (curPos_ >= radius_)
{
curStabilizedPos_ = curPos_ - radius_;
Mat stabilizationMotion = estimateStabilizationMotion();
if (doCorrectionForInclusion_)
stabilizationMotion = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_);
at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion;
stablizedPos = curStabilizedPos_;
return stabilizationMotion;
}
}
else
setUpFrame(image);
log_->print(".");
return Mat();
}
if (curStabilizedPos_ < curPos_)
{
curStabilizedPos_++;
stablizedPos = curStabilizedPos_;
at(curStabilizedPos_ + radius_, frames_) = at(curPos_, frames_);
at(curStabilizedPos_ + radius_ - 1, motions_) = Mat::eye(3, 3, CV_32F);
Mat stabilizationMotion = estimateStabilizationMotion();
if (doCorrectionForInclusion_)
stabilizationMotion = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_);
at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion;
log_->print(".");
return stabilizationMotion;
}
return Mat();
}
Mat
TwoPassVideoStabilizer::estimateMotion()
{
#if ENABLE_DVS_CL_PATH
cv::UMat frame0 = at(curPos_ - 1, frames_).getUMat(ACCESS_READ);
cv::UMat frame1 = at(curPos_, frames_).getUMat(ACCESS_READ);
cv::UMat ugrayImage0;
cv::UMat ugrayImage1;
if ( frame0.type() != CV_8U )
{
cvtColor( frame0, ugrayImage0, COLOR_BGR2GRAY );
}
else
{
ugrayImage0 = frame0;
}
if ( frame1.type() != CV_8U )
{
cvtColor( frame1, ugrayImage1, COLOR_BGR2GRAY );
}
else
{
ugrayImage1 = frame1;
}
return motionEstimator_.dynamicCast<KeypointBasedMotionEstimator>()->estimate(ugrayImage0, ugrayImage1);
#else
return motionEstimator_.dynamicCast<KeypointBasedMotionEstimator>()->estimate(at(curPos_ - 1, frames_), at(curPos_, frames_));
#endif
}
void
TwoPassVideoStabilizer::setUpFrame(const Mat &firstFrame)
{
//int cacheSize = 2*radius_ + 1;
frames_.resize(2);
stabilizedFrames_.resize(2);
stabilizedMasks_.resize(2);
for (int i = -1; i <= 0; ++i)
at(i, frames_) = firstFrame;
StabilizerBase::setUp(firstFrame);
}
VideoStabilizer::VideoStabilizer(
bool isTwoPass,
bool wobbleSuppress,
bool deblur,
bool inpainter)
: isTwoPass_ (isTwoPass)
, trimRatio_ (0.05f)
{
Ptr<MotionEstimatorRansacL2> est = makePtr<MotionEstimatorRansacL2>(MM_HOMOGRAPHY);
Ptr<IOutlierRejector> outlierRejector = makePtr<TranslationBasedLocalOutlierRejector>();
Ptr<KeypointBasedMotionEstimator> kbest = makePtr<KeypointBasedMotionEstimator>(est);
kbest->setDetector(GFTTDetector::create(1000, 0.01, 15));
kbest->setOutlierRejector(outlierRejector);
if (isTwoPass)
{
Ptr<TwoPassVideoStabilizer> twoPassStabilizer = makePtr<TwoPassVideoStabilizer>();
stabilizer_ = twoPassStabilizer;
twoPassStabilizer->setEstimateTrimRatio(false);
twoPassStabilizer->setMotionStabilizer(makePtr<GaussianMotionFilter>(15, 10));
if (wobbleSuppress) {
Ptr<MoreAccurateMotionWobbleSuppressorBase> ws = makePtr<MoreAccurateMotionWobbleSuppressor>();
ws->setMotionEstimator(kbest);
ws->setPeriod(30);
twoPassStabilizer->setWobbleSuppressor(ws);
}
} else {
Ptr<OnePassVideoStabilizer> onePassStabilizer = makePtr<OnePassVideoStabilizer>();
stabilizer_ = onePassStabilizer;
onePassStabilizer->setMotionFilter(makePtr<GaussianMotionFilter>(15, 10));
}
stabilizer_->setMotionEstimator(kbest);
stabilizer_->setRadius(15);
if (deblur)
{
Ptr<WeightingDeblurer> deblurrer = makePtr<WeightingDeblurer>();
deblurrer->setRadius(3);
deblurrer->setSensitivity(0.001f);
stabilizer_->setDeblurer(deblurrer);
}
if (inpainter)
{
bool inpaintMosaic = true;
bool inpaintColorAverage = true;
bool inpaintColorNs = false;
bool inpaintColorTelea = false;
// init inpainter
InpaintingPipeline *inpainters = new InpaintingPipeline();
Ptr<InpainterBase> inpainters_(inpainters);
if (true == inpaintMosaic)
{
Ptr<ConsistentMosaicInpainter> inp = makePtr<ConsistentMosaicInpainter>();
inp->setStdevThresh(10.0f);
inpainters->pushBack(inp);
}
if (true == inpaintColorAverage)
inpainters->pushBack(makePtr<ColorAverageInpainter>());
else if (true == inpaintColorNs)
inpainters->pushBack(makePtr<ColorInpainter>(0, 2));
else if (true == inpaintColorTelea)
inpainters->pushBack(makePtr<ColorInpainter>(1, 2));
if (!inpainters->empty())
{
inpainters->setRadius(2);
stabilizer_->setInpainter(inpainters_);
}
}
}
VideoStabilizer::~VideoStabilizer() {}
void
VideoStabilizer::configFeatureDetector(int features, double minDistance)
{
Ptr<ImageMotionEstimatorBase> estimator = stabilizer_->motionEstimator();
Ptr<FeatureDetector> detector = estimator.dynamicCast<KeypointBasedMotionEstimator>()->detector();
if (NULL == detector) {
return;
}
detector.dynamicCast<GFTTDetector>()->setMaxFeatures(features);
detector.dynamicCast<GFTTDetector>()->setMinDistance(minDistance);
}
void
VideoStabilizer::configMotionFilter(int radius, float stdev)
{
if (isTwoPass_) {
Ptr<TwoPassVideoStabilizer> stab = stabilizer_.dynamicCast<TwoPassVideoStabilizer>();
Ptr<IMotionStabilizer> motionStabilizer = stab->motionStabilizer();
motionStabilizer.dynamicCast<GaussianMotionFilter>()->setParams(radius, stdev);
} else {
Ptr<OnePassVideoStabilizer> stab = stabilizer_.dynamicCast<OnePassVideoStabilizer>();
Ptr<MotionFilterBase> motionFilter = stab->motionFilter();
motionFilter.dynamicCast<GaussianMotionFilter>()->setParams(radius, stdev);
}
stabilizer_->setRadius(radius);
}
void
VideoStabilizer::configDeblurrer(int radius, double sensitivity)
{
Ptr<DeblurerBase> deblurrer = stabilizer_->deblurrer();
if (NULL == deblurrer) {
return;
}
deblurrer->setRadius(radius);
deblurrer.dynamicCast<WeightingDeblurer>()->setSensitivity(sensitivity);
}
void
VideoStabilizer::setFrameSize(Size frameSize)
{
frameSize_ = frameSize;
}
Mat
VideoStabilizer::nextFrame()
{
if (isTwoPass_) {
Ptr<TwoPassVideoStabilizer> stab = stabilizer_.dynamicCast<TwoPassVideoStabilizer>();
return stab->nextFrame();
} else {
Ptr<OnePassVideoStabilizer> stab = stabilizer_.dynamicCast<OnePassVideoStabilizer>();
return stab->nextFrame();
}
}
Mat
VideoStabilizer::nextStabilizedMotion(DvsData* frame, int& stablizedPos)
{
Mat HMatrix;
if (isTwoPass_) {
Ptr<TwoPassVideoStabilizer> stab = stabilizer_.dynamicCast<TwoPassVideoStabilizer>();
HMatrix = stab->nextStabilizedMotion(frame, stablizedPos);
} else {
Ptr<OnePassVideoStabilizer> stab = stabilizer_.dynamicCast<OnePassVideoStabilizer>();
HMatrix = stab->nextStabilizedMotion(frame, stablizedPos);
}
return HMatrix;
}
Size
VideoStabilizer::trimedVideoSize(Size frameSize)
{
Size outputFrameSize;
outputFrameSize.width = ((int)((float)frameSize.width * (1 - 2 * trimRatio_)) >> 3) << 3;
outputFrameSize.height = ((int)((float)frameSize.height * (1 - 2 * trimRatio_)) >> 3) << 3;
return (outputFrameSize);
}
Mat
VideoStabilizer::cropVideoFrame(Mat& frame)
{
Rect cropROI;
Size inputFrameSize = frame.size();
Size outputFrameSize = trimedVideoSize(inputFrameSize);
cropROI.x = (inputFrameSize.width - outputFrameSize.width) >> 1;
cropROI.y = (inputFrameSize.height - outputFrameSize.height) >> 1;
cropROI.width = outputFrameSize.width;
cropROI.height = outputFrameSize.height;
Mat croppedFrame = frame(cropROI).clone();
return croppedFrame;
}