国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

探索OpenCV的光流算法視頻超分與源碼實現(xiàn)

這篇具有很好參考價值的文章主要介紹了探索OpenCV的光流算法視頻超分與源碼實現(xiàn)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

在OpenCV4.0以后,視頻圖像超分模塊已經(jīng)遷移到opencv_contrib獨立倉庫。在視頻超分有兩種形式:結(jié)合光流算法實現(xiàn)超分、使用CNN卷積神經(jīng)網(wǎng)絡(luò)實現(xiàn)超分。在這里主要探索光流算法實現(xiàn)視頻超分,然后進一步分析源碼實現(xiàn)。

一、視頻超分示例

1、光流算法選擇

OpenCV提供多種光流算法:farneback、tvl1、brox、pyrlk。同時支持GPU加速,示例代碼如下:

static Ptr<cv::superres::DenseOpticalFlowExt> createOptFlow(const string& name, bool useGpu)
{
    if (name == "farneback")
    {
        if (useGpu) // 開啟GPU加速,使用CUDA實現(xiàn)
            return cv::superres::createOptFlow_Farneback_CUDA();
        else
            return cv::superres::createOptFlow_Farneback();
    }
    else if (name == "tvl1")
    {
        if (useGpu)
            return cv::superres::createOptFlow_DualTVL1_CUDA();
        else
            return cv::superres::createOptFlow_DualTVL1();
    }
    else if (name == "brox")
        return cv::superres::createOptFlow_Brox_CUDA();
    else if (name == "pyrlk")
        return cv::superres::createOptFlow_PyrLK_CUDA();
    else
        cerr << "Incorrect Optical Flow algorithm - " << name << endl;

    return Ptr<cv::superres::DenseOpticalFlowExt>();
}

2、創(chuàng)建超分實例

根據(jù)是否使用CUDA進行GPU加速,來創(chuàng)建視頻超分實例:

Ptr<SuperResolution> createSuperResolution(bool useCuda)
{
    if (useCuda)
        return createSuperResolution_BTVL1_CUDA();
    else
        return createSuperResolution_BTVL1();
}

3、執(zhí)行視頻超分

在創(chuàng)建光流算法、視頻超分實例后,設(shè)置相關(guān)參數(shù),執(zhí)行視頻超分操作。示例代碼如下:

#include <iostream>
#include <string>
#include <ctype.h>

#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/superres.hpp"
#include "opencv2/superres/optical_flow.hpp"
#include "opencv2/opencv_modules.hpp"

using namespace std;
using namespace cv;
using namespace cv::superres;


int main(int argc, const char* argv[])
{
    CommandLineParser cmd(argc, argv,
        "{ v video      |           | Input video (mandatory)}"
        "{ o output     |           | Output video }"
        "{ s scale      | 4         | Scale factor }"
        "{ i iterations | 180       | Iteration count }"
        "{ t temporal   | 4         | Radius of the temporal search area }"
        "{ f flow       | farneback | Optical flow algorithm (farneback, tvl1, brox, pyrlk) }"
        "{ g gpu        | false     | CPU as default device, cuda for CUDA }"
    );
    // 解析參數(shù)
    const string inputVideoName  = cmd.get<string>("video");
    const string outputVideoName = cmd.get<string>("output");
    const int scale              = cmd.get<int>("scale");
    const int iterations         = cmd.get<int>("iterations");
    const int temporalAreaRadius = cmd.get<int>("temporal");
    const string optFlow         = cmd.get<string>("flow");
    string gpuOption             = cmd.get<string>("gpu");
    bool useCuda                 = gpuOption.compare("cuda") == 0;
    // 創(chuàng)建視頻超分實例
    Ptr<SuperResolution> superRes = createSuperResolution(useCuda);
    // 創(chuàng)建光流算法
    Ptr<cv::superres::DenseOpticalFlowExt> of = createOptFlow(optFlow, useCuda);
    // 設(shè)置光流算法、超分倍數(shù)、迭代次數(shù)、半徑系數(shù)
    superRes->setOpticalFlow(of);
    superRes->setScale(scale);
    superRes->setIterations(iterations);
    superRes->setTemporalAreaRadius(temporalAreaRadius);
    // 讀取視頻幀
    Ptr<FrameSource> frameSource;
    if (useCuda)
    {
        try
        {
            frameSource = createFrameSource_Video_CUDA(inputVideoName);
            Mat frame;
            frameSource->nextFrame(frame);
        }
        catch (const cv::Exception&)
        {
            frameSource.release();
        }
    }
    if (!frameSource)
        frameSource = createFrameSource_Video(inputVideoName);

    // 跳過第一幀
    Mat frame;
    frameSource->nextFrame(frame);
    // 設(shè)置輸入源
    superRes->setInput(frameSource);

    VideoWriter writer;

    for (int i = 0;; ++i)
    {
        Mat result;
        // 執(zhí)行視頻圖像超分
        superRes->nextFrame(result);

        if (result.empty())
            break;

        imshow("Super Resolution", result);

        if (waitKey(1000) > 0)
            break;

        // 視頻幀超分結(jié)果寫到輸出文件
        if (!outputVideoName.empty())
        {
            if (!writer.isOpened())
                writer.open(outputVideoName, VideoWriter::fourcc('X', 'V', 'I', 'D'), 25.0, result.size());
            writer << result;
        }
    }

    return 0;
}

二、視頻超分源碼

1、構(gòu)造函數(shù)

視頻圖像超分的源碼在opencv_contrib/modules/superres中,創(chuàng)建超分實例的函數(shù)位于btv_l1.cpp,其實是創(chuàng)建BTVL1()構(gòu)造函數(shù)的智能指針:

Ptr<cv::superres::SuperResolution> cv::superres::createSuperResolution_BTVL1()
{
    return makePtr<BTVL1>();
}

2、超分入口代碼

而nextFrame()是執(zhí)行超分的函數(shù),位于super_resolution.cpp:

void cv::superres::SuperResolution::nextFrame(OutputArray frame)
{
    isUmat_ = frame.isUMat() && cv::ocl::useOpenCL();

    if (firstCall_)
    {
        initImpl(frameSource_);
        firstCall_ = false;
    }

    processImpl(frameSource_, frame);
}

可以看到內(nèi)部調(diào)用processImpl()函數(shù)來執(zhí)行超分:

    void BTVL1::processImpl(Ptr<FrameSource>& frameSource, OutputArray _output)
    {
        if (outPos_ >= storePos_)
        {
            _output.release();
            return;
        }
        // 讀取下一個視頻幀
        readNextFrame(frameSource);
        // 處理視頻幀
        if (procPos_ < storePos_)
        {
            ++procPos_;
            processFrame(procPos_);
        }
        ++outPos_;
        // 調(diào)用ocl_processImpl函數(shù)執(zhí)行超分
        CV_OCL_RUN(isUmat_,
                   ocl_processImpl(frameSource, _output))

        const Mat& curOutput = at(outPos_, outputs_);

        if (_output.kind() < _InputArray::OPENGL_BUFFER || _output.isUMat())
            curOutput.convertTo(_output, CV_8U);
        else
        {
            curOutput.convertTo(finalOutput_, CV_8U);
            arrCopy(finalOutput_, _output);
        }
    }

3、光流檢測運動矢量

接著看readNextFrame()的實現(xiàn),調(diào)用光流檢測算法來計算運動矢量:

void BTVL1::readNextFrame(Ptr<FrameSource>& frameSource)
    {
        frameSource->nextFrame(curFrame_);
        if (curFrame_.empty())
            return;

        ++storePos_;

        CV_OCL_RUN(isUmat_,
                   ocl_readNextFrame(frameSource))

        curFrame_.convertTo(at(storePos_, frames_), CV_32F);
        // 結(jié)合上一幀和當前幀計算運動矢量
        if (storePos_ > 0)
        {
            opticalFlow_->calc(prevFrame_, curFrame_, at(storePos_ - 1, forwardMotions_));
            opticalFlow_->calc(curFrame_, prevFrame_, at(storePos_, backwardMotions_));
        }

        curFrame_.copyTo(prevFrame_);
    }

4、處理超分

processFrame()函數(shù)負責處理視頻幀:

void BTVL1::processFrame(int idx)
    {
        CV_OCL_RUN(isUmat_,
                   ocl_processFrame(idx))

        const int startIdx = std::max(idx - temporalAreaRadius_, 0);
        const int procIdx = idx;
        const int endIdx = std::min(startIdx + 2 * temporalAreaRadius_, storePos_);

        const int count = endIdx - startIdx + 1;

        srcFrames_.resize(count);
        srcForwardMotions_.resize(count);
        srcBackwardMotions_.resize(count);

        int baseIdx = -1;

        for (int i = startIdx, k = 0; i <= endIdx; ++i, ++k)
        {
            if (i == procIdx)
                baseIdx = k;

            srcFrames_[k] = at(i, frames_);

            if (i < endIdx)
                srcForwardMotions_[k] = at(i, forwardMotions_);
            if (i > startIdx)
                srcBackwardMotions_[k] = at(i, backwardMotions_);
        }
        // 根據(jù)前后方向的運動矢量來處理視頻幀
        process(srcFrames_, at(idx, outputs_), srcForwardMotions_, srcBackwardMotions_, baseIdx);
    }
}

在計算得到前后方向的運動矢量后,調(diào)用BTVL1_Base基類的process()函數(shù)來處理:

    void BTVL1_Base::process(InputArrayOfArrays _src, OutputArray _dst, InputArrayOfArrays _forwardMotions,
                             InputArrayOfArrays _backwardMotions, int baseIdx)
    {
        CV_OCL_RUN(_src.isUMatVector() && _dst.isUMat() && _forwardMotions.isUMatVector() &&
                   _backwardMotions.isUMatVector(),
                   ocl_process(_src, _dst, _forwardMotions, _backwardMotions, baseIdx))

        std::vector<Mat> & src = *(std::vector<Mat> *)_src.getObj(),
                & forwardMotions = *(std::vector<Mat> *)_forwardMotions.getObj(),
                & backwardMotions = *(std::vector<Mat> *)_backwardMotions.getObj();

        // 更新運動模糊(高斯濾波)、 btv權(quán)重
        if (blurKernelSize_ != curBlurKernelSize_ || blurSigma_ != curBlurSigma_ || src[0].type() != curSrcType_)
        {
            //filter_ = createGaussianFilter(src[0].type(), Size(blurKernelSize_, blurKernelSize_), blurSigma_);
            curBlurKernelSize_ = blurKernelSize_;
            curBlurSigma_ = blurSigma_;
            curSrcType_ = src[0].type();
        }

        if (btvWeights_.empty() || btvKernelSize_ != curBtvKernelSize_ || alpha_ != curAlpha_)
        {
            calcBtvWeights(btvKernelSize_, alpha_, btvWeights_);
            curBtvKernelSize_ = btvKernelSize_;
            curAlpha_ = alpha_;
        }

        // 計算相對運動
        calcRelativeMotions(forwardMotions, backwardMotions, lowResForwardMotions_, lowResBackwardMotions_, baseIdx, src[0].size());
        // 對運動矢量進行放大
        upscaleMotions(lowResForwardMotions_, highResForwardMotions_, scale_);
        upscaleMotions(lowResBackwardMotions_, highResBackwardMotions_, scale_);

        forwardMaps_.resize(highResForwardMotions_.size());
        backwardMaps_.resize(highResForwardMotions_.size());
        for (size_t i = 0; i < highResForwardMotions_.size(); ++i)
            buildMotionMaps(highResForwardMotions_[i], highResBackwardMotions_[i], forwardMaps_[i], backwardMaps_[i]);


        const Size lowResSize = src[0].size();
        const Size highResSize(lowResSize.width * scale_, lowResSize.height * scale_);

        resize(src[baseIdx], highRes_, highResSize, 0, 0, INTER_CUBIC);

        diffTerm_.create(highResSize, highRes_.type());
        a_.create(highResSize, highRes_.type());
        b_.create(highResSize, highRes_.type());
        c_.create(lowResSize, highRes_.type());

        for (int i = 0; i < iterations_; ++i)
        {
            diffTerm_.setTo(Scalar::all(0));

            for (size_t k = 0; k < src.size(); ++k)
            {
                // a = M * Ih
                remap(highRes_, a_, backwardMaps_[k], noArray(), INTER_NEAREST);
                // 高斯模糊 b = HM * Ih
                GaussianBlur(a_, b_, Size(blurKernelSize_, blurKernelSize_), blurSigma_);
                // c = DHM * Ih
                resize(b_, c_, lowResSize, 0, 0, INTER_NEAREST);

                diffSign(src[k], c_, c_);

                // 超分運算 a = Dt * diff
                upscale(c_, a_, scale_);
                // b = HtDt * diff
                GaussianBlur(a_, b_, Size(blurKernelSize_, blurKernelSize_), blurSigma_);
                // a = MtHtDt * diff
                remap(b_, a_, forwardMaps_[k], noArray(), INTER_NEAREST);

                add(diffTerm_, a_, diffTerm_);
            }

            if (lambda_ > 0)
            {
                calcBtvRegularization(highRes_, regTerm_, btvKernelSize_, btvWeights_, ubtvWeights_);
                addWeighted(diffTerm_, 1.0, regTerm_, -lambda_, 0.0, diffTerm_);
            }

            addWeighted(highRes_, 1.0, diffTerm_, tau_, 0.0, highRes_);
        }

        Rect inner(btvKernelSize_, btvKernelSize_, highRes_.cols - 2 * btvKernelSize_, highRes_.rows - 2 * btvKernelSize_);
        highRes_(inner).copyTo(_dst);
    }

我們再看下upscaleMotions()函數(shù)的實現(xiàn):

void upscaleMotions(InputArrayOfArrays _lowResMotions, OutputArrayOfArrays _highResMotions, int scale)
    {
        CV_OCL_RUN(_lowResMotions.isUMatVector() && _highResMotions.isUMatVector(),
                   ocl_upscaleMotions(_lowResMotions, _highResMotions, scale))

        std::vector<Mat> & lowResMotions = *(std::vector<Mat> *)_lowResMotions.getObj(),
                & highResMotions = *(std::vector<Mat> *)_highResMotions.getObj();

        highResMotions.resize(lowResMotions.size());

        for (size_t i = 0; i < lowResMotions.size(); ++i)
        {
            // 三次樣條差值
            resize(lowResMotions[i], highResMotions[i], Size(), scale, scale, INTER_CUBIC);
            // 運動矢量與縮放因子相乘
            multiply(highResMotions[i], Scalar::all(scale), highResMotions[i]);
        }
    }

接著是upscale()超分函數(shù)的實現(xiàn):

    void upscale(InputArray _src, OutputArray _dst, int scale)
    {
        int cn = _src.channels();
        CV_Assert( cn == 1 || cn == 3 || cn == 4 );

        CV_OCL_RUN(_dst.isUMat(),
                   ocl_upscale(_src, _dst, scale))

        typedef void (*func_t)(InputArray src, OutputArray dst, int scale);
        static const func_t funcs[] =
        {
            0, upscaleImpl<float>, 0, upscaleImpl<Point3f>, upscaleImpl<Point4f>
        };

        const func_t func = funcs[cn];
        CV_Assert(func != 0);
        func(_src, _dst, scale);
    }

最終是調(diào)用upscaleImpl()進行超分運算,屬于模板函數(shù):文章來源地址http://www.zghlxwxcb.cn/news/detail-495246.html

    template <typename T>
    void upscaleImpl(InputArray _src, OutputArray _dst, int scale)
    {
        Mat src = _src.getMat();
        _dst.create(src.rows * scale, src.cols * scale, src.type());
        _dst.setTo(Scalar::all(0));
        Mat dst = _dst.getMat();

        for (int y = 0, Y = 0; y < src.rows; ++y, Y += scale)
        {
            const T * const srcRow = src.ptr<T>(y);
            T * const dstRow = dst.ptr<T>(Y);

            for (int x = 0, X = 0; x < src.cols; ++x, X += scale)
                dstRow[X] = srcRow[x];
        }
    }

到了這里,關(guān)于探索OpenCV的光流算法視頻超分與源碼實現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 常用視頻目標跟蹤算法仿真對比:幀間差分法,背景差分法,光流法,Meanshift

    目錄 1.軟件版本 2.本算法理論知識 幀差法? 背景差分法 光流法

    2023年04月08日
    瀏覽(22)
  • SRGAN圖像超分重建算法Python實現(xiàn)(含數(shù)據(jù)集代碼)

    SRGAN圖像超分重建算法Python實現(xiàn)(含數(shù)據(jù)集代碼)

    摘要:本文介紹深度學習的SRGAN圖像超分重建算法,使用 P y t h o n 以及 P y t o r c h 框架實現(xiàn),包含完整訓練、測試代碼,以及訓練數(shù)據(jù)集文件。博文介紹圖像超分算法的原理,包括生成對抗網(wǎng)絡(luò)和SRGAN模型原理和實現(xiàn)的代碼,同時結(jié)合具體內(nèi)容進行解釋說明,完整代碼資源文

    2024年02月12日
    瀏覽(28)
  • 使用Python基于opencv實現(xiàn)多視頻畫面拼接融合算法demo

    單個相機視頻畫面尺寸有限,在需要全景展示的場景下,就需要將多個相機視頻進行拼接融合,得到一張全景圖。本文基于opencv實現(xiàn)一個視頻拼接的demo,熟悉視頻拼接流程和opencv接口。 直接上代碼吧,注釋還是比較清楚的: 該demo使用ORB算法檢測關(guān)鍵點,使用BFMatcher進行特征

    2024年02月04日
    瀏覽(33)
  • OpenCV | 光流估計

    OpenCV | 光流估計

    光流估計 光流是空間運動物體在觀測成像平面上的像素運動的“瞬時速度”,根據(jù)各個像素點的速度的速度矢量特征,可以對圖像進行動態(tài)分析,例如目標跟蹤 高度恒定:同一點隨著時間的變化,其亮度不會發(fā)生改變。 小運動:隨著時間的變化不會引起位置的劇烈變化,只

    2024年02月02日
    瀏覽(21)
  • OpenCV實戰(zhàn)(28)——光流估計

    OpenCV實戰(zhàn)(28)——光流估計

    當相機進行拍攝時,拍攝到的亮度圖案會投射到圖像傳感器上,從而形成圖像。在視頻序列中,我們通常需要捕捉運動模式,即不同場景元素的 3D 運動在圖像平面上的投影,這種投影 3D 運動矢量的圖像稱為運動場 ( motion field )。但是,我們無法從相機傳感器直接測量場景點的

    2024年02月13日
    瀏覽(18)
  • python使用opencv提取光流

    python使用opencv提取光流

    光流flow特征中包含了一個視頻當中運動相關(guān)的信息,在視頻動作定位當中光流特征使用的比較多,所以記錄一下提取光流特征的方法。 使用的方法是TVL1方法,最終提取的光流圖片還可以配合I3D模型進行特征的提取。光流的計算先需要將視頻一幀一幀提取出來,然后再通過連

    2024年02月05日
    瀏覽(29)
  • OpenCV 中的光流 (C++/Python)

    OpenCV 中的光流 (C++/Python)

    光流是一項視頻中兩個連續(xù)幀之間每像素運動估計的任務(wù)。基本上,光流任務(wù)意味著計算像素的位移矢量作為兩個相鄰圖像之間的對象位移差。光流的主要思想是估計物體由其運動或相機運動引起的位移矢量。 理論基礎(chǔ) 假設(shè)我們有一個灰度圖像——具有像素強度的矩陣。我

    2024年02月13日
    瀏覽(25)
  • 常用的超分算法

    超分算法(Super-resolution algorithm)是一種圖像處理算法,旨在從低分辨率(Low-resolution,LR)圖像重建出高分辨率(High-resolution,HR)圖像。它通過利用圖像中的信息和先驗知識,推測和還原圖像中丟失的細節(jié),從而增加圖像的清晰度和細節(jié)級別。 以下是幾種常見的超分算法:

    2024年02月04日
    瀏覽(15)
  • 18.Lucas-Kanade光流及OpenCV中的calcOpticalFlowPyrLK

    18.Lucas-Kanade光流及OpenCV中的calcOpticalFlowPyrLK

    歡迎訪問個人網(wǎng)絡(luò)日志????知行空間???? 光流描述了像素在圖像中的運動,就像彗星?劃過天空中流動圖像。同一個像素,隨著時間的流逝,會在圖像中運動,光流法就是追蹤它的運動過程。 光流法根據(jù)追蹤的像素數(shù)又可以分成 稀疏光流法 和 稠密光流法 。 稀疏光流法

    2024年02月13日
    瀏覽(20)
  • FPGA多路視頻疊加融合 HLS算法實現(xiàn) 提供2套工程源碼和技術(shù)支持

    FPGA多路視頻疊加融合 HLS算法實現(xiàn) 提供2套工程源碼和技術(shù)支持

    視頻疊加和融合在FPGA圖像處理領(lǐng)域有著廣泛應用,但其復雜的內(nèi)存訪問機制和視頻疊加透明度的融合,使得實現(xiàn)難度很大,讓很多FPGA工程師望而卻步,在目前的技術(shù)條件下,使用HLS實現(xiàn)視頻疊加融合是最簡單方便的實現(xiàn)方式,本設(shè)計也是基于此實現(xiàn)。 本設(shè)計提供2套vivado工程

    2024年02月12日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包