Home | History | Annotate | Download | only in libdvs
      1 /*
      2  * stablizer.cpp - abstract for DVS (Digital Video Stabilizer)
      3  *
      4  *    Copyright (c) 2014-2016 Intel Corporation
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *        http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  *
     18  * Author: Zong Wei <wei.zong (at) intel.com>
     19  */
     20 
     21 #include "stabilizer.h"
     22 
     23 using namespace cv;
     24 using namespace cv::videostab;
     25 using namespace std;
     26 
     27 Mat
     28 OnePassVideoStabilizer::nextStabilizedMotion(DvsData* frame, int& stablizedPos)
     29 {
     30     if (!(frame->data.empty()))
     31     {
     32         Mat image;
     33         frame->data.getMat(ACCESS_READ).copyTo(image);
     34 
     35         curPos_++;
     36 
     37         if (curPos_ > 0)
     38         {
     39             at(curPos_, frames_) = image;
     40 
     41             if (doDeblurring_)
     42                 at(curPos_, blurrinessRates_) = calcBlurriness(image);
     43 
     44             at(curPos_ - 1, motions_) = estimateMotion();
     45 
     46             if (curPos_ >= radius_)
     47             {
     48                 curStabilizedPos_ = curPos_ - radius_;
     49                 Mat stabilizationMotion = estimateStabilizationMotion();
     50                 if (doCorrectionForInclusion_)
     51                     stabilizationMotion = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_);
     52 
     53                 at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion;
     54                 stablizedPos = curStabilizedPos_;
     55 
     56                 return stabilizationMotion;
     57             }
     58         }
     59         else
     60             setUpFrame(image);
     61 
     62         log_->print(".");
     63         return Mat();
     64     }
     65 
     66     if (curStabilizedPos_ < curPos_)
     67     {
     68         curStabilizedPos_++;
     69         stablizedPos = curStabilizedPos_;
     70         at(curStabilizedPos_ + radius_, frames_) = at(curPos_, frames_);
     71         at(curStabilizedPos_ + radius_ - 1, motions_) = Mat::eye(3, 3, CV_32F);
     72 
     73         Mat stabilizationMotion = estimateStabilizationMotion();
     74         if (doCorrectionForInclusion_)
     75             stabilizationMotion = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_);
     76 
     77         at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion;
     78 
     79         log_->print(".");
     80 
     81         return stabilizationMotion;
     82     }
     83 
     84     return Mat();
     85 }
     86 
     87 
     88 Mat
     89 OnePassVideoStabilizer::estimateMotion()
     90 {
     91 #if ENABLE_DVS_CL_PATH
     92     cv::UMat frame0 = at(curPos_ - 1, frames_).getUMat(ACCESS_READ);
     93     cv::UMat frame1 = at(curPos_, frames_).getUMat(ACCESS_READ);
     94 
     95     cv::UMat ugrayImage0;
     96     cv::UMat ugrayImage1;
     97     if ( frame0.type() != CV_8U )
     98     {
     99         cvtColor( frame0, ugrayImage0, COLOR_BGR2GRAY );
    100     }
    101     else
    102     {
    103         ugrayImage0 = frame0;
    104     }
    105 
    106     if ( frame1.type() != CV_8U )
    107     {
    108         cvtColor( frame1, ugrayImage1, COLOR_BGR2GRAY );
    109     }
    110     else
    111     {
    112         ugrayImage1 = frame1;
    113     }
    114 
    115     return motionEstimator_.dynamicCast<KeypointBasedMotionEstimator>()->estimate(ugrayImage0, ugrayImage1);
    116 #else
    117     return motionEstimator_.dynamicCast<KeypointBasedMotionEstimator>()->estimate(at(curPos_ - 1, frames_), at(curPos_, frames_));
    118 #endif
    119 }
    120 
    121 void
    122 OnePassVideoStabilizer::setUpFrame(const Mat &firstFrame)
    123 {
    124     frameSize_ = firstFrame.size();
    125     frameMask_.create(frameSize_, CV_8U);
    126     frameMask_.setTo(255);
    127 
    128     int cacheSize = 2 * radius_ + 1;
    129     frames_.resize(2);
    130     motions_.resize(cacheSize);
    131     stabilizationMotions_.resize(cacheSize);
    132 
    133     for (int i = -radius_; i < 0; ++i)
    134     {
    135         at(i, motions_) = Mat::eye(3, 3, CV_32F);
    136         at(i, frames_) = firstFrame;
    137     }
    138 
    139     at(0, frames_) = firstFrame;
    140 
    141     StabilizerBase::setUp(firstFrame);
    142 }
    143 
    144 
    145 Mat
    146 TwoPassVideoStabilizer::nextStabilizedMotion(DvsData* frame, int& stablizedPos)
    147 {
    148     if (!(frame->data.empty()))
    149     {
    150         Mat image;
    151         frame->data.getMat(ACCESS_READ).copyTo(image);
    152 
    153         curPos_++;
    154 
    155         if (curPos_ > 0)
    156         {
    157             at(curPos_, frames_) = image;
    158 
    159             if (doDeblurring_)
    160                 at(curPos_, blurrinessRates_) = calcBlurriness(image);
    161 
    162             at(curPos_ - 1, motions_) = estimateMotion();
    163 
    164             if (curPos_ >= radius_)
    165             {
    166                 curStabilizedPos_ = curPos_ - radius_;
    167                 Mat stabilizationMotion = estimateStabilizationMotion();
    168                 if (doCorrectionForInclusion_)
    169                     stabilizationMotion = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_);
    170 
    171                 at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion;
    172                 stablizedPos = curStabilizedPos_;
    173 
    174                 return stabilizationMotion;
    175             }
    176         }
    177         else
    178             setUpFrame(image);
    179 
    180         log_->print(".");
    181         return Mat();
    182     }
    183 
    184     if (curStabilizedPos_ < curPos_)
    185     {
    186         curStabilizedPos_++;
    187         stablizedPos = curStabilizedPos_;
    188         at(curStabilizedPos_ + radius_, frames_) = at(curPos_, frames_);
    189         at(curStabilizedPos_ + radius_ - 1, motions_) = Mat::eye(3, 3, CV_32F);
    190 
    191         Mat stabilizationMotion = estimateStabilizationMotion();
    192         if (doCorrectionForInclusion_)
    193             stabilizationMotion = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_);
    194 
    195         at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion;
    196 
    197         log_->print(".");
    198 
    199         return stabilizationMotion;
    200     }
    201 
    202     return Mat();
    203 }
    204 
    205 
    206 Mat
    207 TwoPassVideoStabilizer::estimateMotion()
    208 {
    209 #if ENABLE_DVS_CL_PATH
    210     cv::UMat frame0 = at(curPos_ - 1, frames_).getUMat(ACCESS_READ);
    211     cv::UMat frame1 = at(curPos_, frames_).getUMat(ACCESS_READ);
    212 
    213     cv::UMat ugrayImage0;
    214     cv::UMat ugrayImage1;
    215     if ( frame0.type() != CV_8U )
    216     {
    217         cvtColor( frame0, ugrayImage0, COLOR_BGR2GRAY );
    218     }
    219     else
    220     {
    221         ugrayImage0 = frame0;
    222     }
    223 
    224     if ( frame1.type() != CV_8U )
    225     {
    226         cvtColor( frame1, ugrayImage1, COLOR_BGR2GRAY );
    227     }
    228     else
    229     {
    230         ugrayImage1 = frame1;
    231     }
    232 
    233     return motionEstimator_.dynamicCast<KeypointBasedMotionEstimator>()->estimate(ugrayImage0, ugrayImage1);
    234 #else
    235     return motionEstimator_.dynamicCast<KeypointBasedMotionEstimator>()->estimate(at(curPos_ - 1, frames_), at(curPos_, frames_));
    236 #endif
    237 }
    238 
    239 void
    240 TwoPassVideoStabilizer::setUpFrame(const Mat &firstFrame)
    241 {
    242     //int cacheSize = 2*radius_ + 1;
    243     frames_.resize(2);
    244     stabilizedFrames_.resize(2);
    245     stabilizedMasks_.resize(2);
    246 
    247     for (int i = -1; i <= 0; ++i)
    248         at(i, frames_) = firstFrame;
    249 
    250     StabilizerBase::setUp(firstFrame);
    251 }
    252 
    253 VideoStabilizer::VideoStabilizer(
    254     bool isTwoPass,
    255     bool wobbleSuppress,
    256     bool deblur,
    257     bool inpainter)
    258     : isTwoPass_ (isTwoPass)
    259     , trimRatio_ (0.05f)
    260 {
    261     Ptr<MotionEstimatorRansacL2> est = makePtr<MotionEstimatorRansacL2>(MM_HOMOGRAPHY);
    262     Ptr<IOutlierRejector> outlierRejector = makePtr<TranslationBasedLocalOutlierRejector>();
    263     Ptr<KeypointBasedMotionEstimator> kbest = makePtr<KeypointBasedMotionEstimator>(est);
    264     kbest->setDetector(GFTTDetector::create(1000, 0.01, 15));
    265     kbest->setOutlierRejector(outlierRejector);
    266 
    267     if (isTwoPass)
    268     {
    269         Ptr<TwoPassVideoStabilizer> twoPassStabilizer = makePtr<TwoPassVideoStabilizer>();
    270         stabilizer_ = twoPassStabilizer;
    271         twoPassStabilizer->setEstimateTrimRatio(false);
    272         twoPassStabilizer->setMotionStabilizer(makePtr<GaussianMotionFilter>(15, 10));
    273 
    274         if (wobbleSuppress) {
    275             Ptr<MoreAccurateMotionWobbleSuppressorBase> ws = makePtr<MoreAccurateMotionWobbleSuppressor>();
    276 
    277             ws->setMotionEstimator(kbest);
    278             ws->setPeriod(30);
    279             twoPassStabilizer->setWobbleSuppressor(ws);
    280         }
    281     } else {
    282         Ptr<OnePassVideoStabilizer> onePassStabilizer = makePtr<OnePassVideoStabilizer>();
    283         stabilizer_ = onePassStabilizer;
    284         onePassStabilizer->setMotionFilter(makePtr<GaussianMotionFilter>(15, 10));
    285     }
    286 
    287     stabilizer_->setMotionEstimator(kbest);
    288 
    289     stabilizer_->setRadius(15);
    290 
    291     if (deblur)
    292     {
    293         Ptr<WeightingDeblurer> deblurrer = makePtr<WeightingDeblurer>();
    294         deblurrer->setRadius(3);
    295         deblurrer->setSensitivity(0.001f);
    296         stabilizer_->setDeblurer(deblurrer);
    297     }
    298 
    299     if (inpainter)
    300     {
    301         bool inpaintMosaic = true;
    302         bool inpaintColorAverage = true;
    303         bool inpaintColorNs = false;
    304         bool inpaintColorTelea = false;
    305 
    306         // init inpainter
    307         InpaintingPipeline *inpainters = new InpaintingPipeline();
    308         Ptr<InpainterBase> inpainters_(inpainters);
    309         if (true == inpaintMosaic)
    310         {
    311             Ptr<ConsistentMosaicInpainter> inp = makePtr<ConsistentMosaicInpainter>();
    312             inp->setStdevThresh(10.0f);
    313             inpainters->pushBack(inp);
    314         }
    315         if (true == inpaintColorAverage)
    316             inpainters->pushBack(makePtr<ColorAverageInpainter>());
    317         else if (true == inpaintColorNs)
    318             inpainters->pushBack(makePtr<ColorInpainter>(0, 2));
    319         else if (true == inpaintColorTelea)
    320             inpainters->pushBack(makePtr<ColorInpainter>(1, 2));
    321         if (!inpainters->empty())
    322         {
    323             inpainters->setRadius(2);
    324             stabilizer_->setInpainter(inpainters_);
    325         }
    326     }
    327 }
    328 
    329 VideoStabilizer::~VideoStabilizer() {}
    330 
    331 void
    332 VideoStabilizer::configFeatureDetector(int features, double minDistance)
    333 {
    334     Ptr<ImageMotionEstimatorBase> estimator = stabilizer_->motionEstimator();
    335     Ptr<FeatureDetector> detector = estimator.dynamicCast<KeypointBasedMotionEstimator>()->detector();
    336     if (NULL == detector) {
    337         return;
    338     }
    339 
    340     detector.dynamicCast<GFTTDetector>()->setMaxFeatures(features);
    341     detector.dynamicCast<GFTTDetector>()->setMinDistance(minDistance);
    342 }
    343 
    344 void
    345 VideoStabilizer::configMotionFilter(int radius, float stdev)
    346 {
    347     if (isTwoPass_) {
    348         Ptr<TwoPassVideoStabilizer> stab = stabilizer_.dynamicCast<TwoPassVideoStabilizer>();
    349         Ptr<IMotionStabilizer> motionStabilizer = stab->motionStabilizer();
    350         motionStabilizer.dynamicCast<GaussianMotionFilter>()->setParams(radius, stdev);
    351     } else {
    352         Ptr<OnePassVideoStabilizer> stab = stabilizer_.dynamicCast<OnePassVideoStabilizer>();
    353         Ptr<MotionFilterBase> motionFilter = stab->motionFilter();
    354         motionFilter.dynamicCast<GaussianMotionFilter>()->setParams(radius, stdev);
    355     }
    356     stabilizer_->setRadius(radius);
    357 }
    358 
    359 void
    360 VideoStabilizer::configDeblurrer(int radius, double sensitivity)
    361 {
    362     Ptr<DeblurerBase> deblurrer = stabilizer_->deblurrer();
    363     if (NULL == deblurrer) {
    364         return;
    365     }
    366 
    367     deblurrer->setRadius(radius);
    368     deblurrer.dynamicCast<WeightingDeblurer>()->setSensitivity(sensitivity);
    369 }
    370 
    371 void
    372 VideoStabilizer::setFrameSize(Size frameSize)
    373 {
    374     frameSize_ = frameSize;
    375 }
    376 
    377 Mat
    378 VideoStabilizer::nextFrame()
    379 {
    380     if (isTwoPass_) {
    381         Ptr<TwoPassVideoStabilizer> stab = stabilizer_.dynamicCast<TwoPassVideoStabilizer>();
    382         return stab->nextFrame();
    383     } else {
    384         Ptr<OnePassVideoStabilizer> stab = stabilizer_.dynamicCast<OnePassVideoStabilizer>();
    385         return stab->nextFrame();
    386     }
    387 }
    388 
    389 Mat
    390 VideoStabilizer::nextStabilizedMotion(DvsData* frame, int& stablizedPos)
    391 {
    392     Mat HMatrix;
    393 
    394     if (isTwoPass_) {
    395         Ptr<TwoPassVideoStabilizer> stab = stabilizer_.dynamicCast<TwoPassVideoStabilizer>();
    396         HMatrix = stab->nextStabilizedMotion(frame, stablizedPos);
    397     } else {
    398         Ptr<OnePassVideoStabilizer> stab = stabilizer_.dynamicCast<OnePassVideoStabilizer>();
    399         HMatrix = stab->nextStabilizedMotion(frame, stablizedPos);
    400     }
    401 
    402     return HMatrix;
    403 }
    404 
    405 Size
    406 VideoStabilizer::trimedVideoSize(Size frameSize)
    407 {
    408     Size outputFrameSize;
    409     outputFrameSize.width = ((int)((float)frameSize.width * (1 - 2 * trimRatio_)) >> 3) << 3;
    410     outputFrameSize.height = ((int)((float)frameSize.height * (1 - 2 * trimRatio_)) >> 3) << 3;
    411 
    412     return (outputFrameSize);
    413 }
    414 
    415 Mat
    416 VideoStabilizer::cropVideoFrame(Mat& frame)
    417 {
    418     Rect cropROI;
    419     Size inputFrameSize = frame.size();
    420     Size outputFrameSize = trimedVideoSize(inputFrameSize);
    421 
    422     cropROI.x = (inputFrameSize.width - outputFrameSize.width) >> 1;
    423     cropROI.y = (inputFrameSize.height - outputFrameSize.height) >> 1;
    424     cropROI.width = outputFrameSize.width;
    425     cropROI.height = outputFrameSize.height;
    426 
    427     Mat croppedFrame = frame(cropROI).clone();
    428 
    429     return croppedFrame;
    430 }
    431 
    432