探索OpenCV的AI实现视频超分

news2024/11/18 1:46:19

OpenCV除了使用光流算法与普通插值实现图像视频超分,还提供AI深度学习实现视频超分。算法模型包括:edsr、espcn、fsrcnn、lapsrn,实现超分的倍数有2、3、4、8。通过AI实现的视频超分比传统算法的效果更好,图像更清晰。

1、超分算法对比

在opencv_contrib外置库的dnn_superres模块,就是用AI实现的图像/视频超分。接下来,我们对比AI算法、双三次插值、最近邻插值、Lanczos插值的超分效果。通过计算图像的PSNR、SSIM来评估超分质量。

#include <iostream>
#include <opencv2/opencv_modules.hpp>
#include <opencv2/dnn_superres.hpp>
#include <opencv2/quality.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;
using namespace dnn_superres;

static Vec2d getQualityValues(Mat orig, Mat upsampled)
{
    double psnr = PSNR(upsampled, orig);
    Scalar q = quality::QualitySSIM::compute(upsampled, orig, noArray());
    double ssim = mean(Vec3d((q[0]), q[1], q[2]))[0];
    return Vec2d(psnr, ssim);
}

int main(int argc, char *argv[])
{
    if (argc < 4) {
        cout << "usage:";
        cout << "Arg 1: image path  | Path to image\n";
        cout << "Arg 2: algorithm | edsr, espcn, fsrcnn or lapsrn\n";
        cout << "Arg 3: path to model file \n";
        cout << "Arg 4: scale  | 2, 3, 4 or 8 \n";
        cout << "-----------------------------------------------" << endl;
        return -1;
    }
    string path = string(argv[1]);
    string algorithm = string(argv[2]);
    string model = string(argv[3]);
    int scale = atoi(argv[4]);

    Mat img = imread(path);
    if (img.empty()) {
        cerr << "Couldn't load image: " << img << "\n";
        return -2;
    }

    // 裁剪图像
    int width = img.cols - (img.cols % scale);
    int height = img.rows - (img.rows % scale);
    Mat cropped = img(Rect(0, 0, width, height));

    Mat img_downscaled;
    resize(cropped, img_downscaled, Size(), 1.0 / scale, 1.0 / scale);

    Mat img_new;
    DnnSuperResImpl sr;
    vector <Mat> allImages;

    // 读取模型:以ESPCN为例,"models/ESPCN_x2.pb"
    sr.readModel(model);
    // 设置超分算法、超分倍数
    sr.setModel(algorithm, scale);
    sr.upsample(img_downscaled, img_new);

    vector<double> psnrValues = vector<double>();
    vector<double> ssimValues = vector<double>();

    // 1、深度学习模型
    Vec2f quality = getQualityValues(cropped, img_new);

    psnrValues.push_back(quality[0]);
    ssimValues.push_back(quality[1]);

    cout << sr.getAlgorithm() << ":" << endl;
    cout << "PSNR: " << quality[0] << " SSIM: " << quality[1] << endl;

    // 2、双三次插值
    Mat bicubic;
    resize(img_downscaled, bicubic, Size(), scale, scale, INTER_CUBIC);
    quality = getQualityValues(cropped, bicubic);

    psnrValues.push_back(quality[0]);
    ssimValues.push_back(quality[1]);

    cout << "Bicubic " << endl;
    cout << "PSNR: " << quality[0] << " SSIM: " << quality[1] << endl;

    // 3、最近邻插值
    Mat nearest;
    resize(img_downscaled, nearest, Size(), scale, scale, INTER_NEAREST);
    quality = getQualityValues(cropped, nearest);

    psnrValues.push_back(quality[0]);
    ssimValues.push_back(quality[1]);

    cout << "Nearest neighbor" << endl;
    cout << "PSNR: " << quality[0] << " SSIM: " << quality[1] << endl;

    // 4、LANCZOS插值
    Mat lanczos;
    resize(img_downscaled, lanczos, Size(), scale, scale, INTER_LANCZOS4);
    quality = getQualityValues(cropped, lanczos);

    psnrValues.push_back(quality[0]);
    ssimValues.push_back(quality[1]);

    cout << "Lanczos" << endl;
    cout << "PSNR: " << quality[0] << " SSIM: " << quality[1] << endl;

    return 0;
}

2、超分效果对比

以4倍超分为例,各个算法实现超分的效果如下图所示。可以看到双三次插值、最近邻插值、Lanczos插值的图像有马赛克方块,而通过AI实现超分的图像比较清晰。

 具体的耗时、PSNR、SSIM数据,如下表所示。可以看到,传统算法的耗时很少,PSNR值在26左右。而AI算法的耗时比较高,其中EDSR模型的耗时有1.6s,PSNR值最高(超过28)。

 3、AI视频超分

通过VideoCapture来读取视频帧,然后使用DnnSuperResImpl实现逐帧超分,接着用VideoWriter写视频文件。完整的示例代码如下:

int main(int argc, char *argv[])
{
    if (argc < 4) {
        cout << "usage:   Arg 1: input video path" << endl;
        cout << "\t Arg 2: output video path" << endl;
        cout << "\t Arg 3: algorithm | edsr, espcn, fsrcnn or lapsrn" << endl;
        cout << "\t Arg 4: scale     | 2, 3, 4 or 8 \n";
        cout << "\t Arg 5: path to model file \n";
        return -1;
    }

    string input_path = string(argv[1]);
    string output_path = string(argv[2]);
    string algorithm = string(argv[3]);
    int scale = atoi(argv[4]);
    string path = string(argv[5]);

    VideoCapture input_video(input_path);
    int ex = static_cast<int>(input_video.get(CAP_PROP_FOURCC));
    Size S = Size((int) input_video.get(CAP_PROP_FRAME_WIDTH) * scale,
                  (int) input_video.get(CAP_PROP_FRAME_HEIGHT) * scale);

    VideoWriter output_video;
    output_video.open(output_path, ex, input_video.get(CAP_PROP_FPS), S, true);

    if (!input_video.isOpened())
    {
        std::cerr << "Could not open the video." << std::endl;
        return -1;
    }
    // 读取超分模型、设置超分倍数
    DnnSuperResImpl sr;
    sr.readModel(path);
    sr.setModel(algorithm, scale);

    for(;;)
    {
        Mat frame, output_frame;
        // 读取视频帧
        input_video >> frame;

        if ( frame.empty() )
            break;
        // 执行超分
        sr.upsample(frame, output_frame);
        // 写入超分后的视频帧
        output_video << output_frame;

        char c=(char)waitKey(25);
        if(c==27)
            break;
    }

    input_video.release();
    output_video.release();

    return 0;
}

4、AI超分源码

首先把图像转换为浮点格式,然后拆分YCbCr通道,传入深度学习网络进行超分,最后重建图像。源码如下:

void DnnSuperResImpl::upsample(InputArray img, OutputArray result)
{
    if (net.empty())
        CV_Error(Error::StsError, "Model not specified. Please set model via setModel().");

    if (this->alg == "espcn" || this->alg == "lapsrn" || this->alg == "fsrcnn")
    {
        // 预处理: 转成浮点格式
        Mat preproc_img;
        preprocess_YCrCb(img, preproc_img);

        // 拆分通道,仅用Y通道进行推理
        Mat ycbcr_channels[3];
        split(preproc_img, ycbcr_channels);

        Mat Y = ycbcr_channels[0];

        // 创建blob
        cv::Mat blob;
        dnn::blobFromImage(Y, blob, 1.0);

        // 使用神经网络进行超分
        this->net.setInput(blob);
        Mat blob_output = this->net.forward();

        // 从blob转换回image
        std::vector <Mat> model_outs;
        dnn::imagesFromBlob(blob_output, model_outs);
        Mat out_img = model_outs[0];

        // 重建图像: 对Cr、Cb进行超分,融合第三层网络
        reconstruct_YCrCb(out_img, preproc_img, result, this->sc);
    }
    else if (this->alg == "edsr")
    {
        // Div2K数据集的平均值
        Scalar mean = Scalar(103.1545782, 111.561547, 114.35629928);

        // 转成浮点格式
        Mat float_img;
        img.getMat().convertTo(float_img, CV_32F, 1.0);

        // 创建blob、抽取数据集的平均值
        cv::Mat blob;
        dnn::blobFromImage(float_img, blob, 1.0, Size(), mean);

        // 使用神经网络进行超分
        this->net.setInput(blob);
        Mat blob_output = this->net.forward();

        // 从blob转换回image
        std::vector <Mat> model_outs;
        dnn::imagesFromBlob(blob_output, model_outs);

        // 后处理: 添加平均值
        Mat(model_outs[0] + mean).convertTo(result, CV_8U);
    }
    else
    {
        CV_Error(cv::Error::StsNotImplemented, String("Unknown/unsupported superres algorithm: ") + this->alg);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/694994.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据面试题之Mysql:每日三题(五)

大数据面试题之Mysql:每日三题 1.MySQL索引存储结构(六种)2.on和where的区别3.mysql是怎么查重的&#xff1f;(重点掌握3种&#xff0c;distinct&#xff0c;group by&#xff0c;row_number) 很开心写完上一篇&#xff0c;就立刻找到了我入职的第二家公司&#xff0c;所以我还…

Gitlab保护分支与合并请求

目录 引言 1、成员角色指定 1、保护分支设置 2、合并请求 引言 熟悉了Git工作流之后&#xff0c;有几个重要的分支&#xff0c;如Master(改名为Main)、Develop、Release分支等&#xff0c;是禁止开发成员随意合并和提交的&#xff0c;在此分支上的提交和推送权限仅限项目负责…

电商假货品牌如何应对

随着电商的逐步发展&#xff0c;不同渠道首的产品上架数量呈明显增长&#xff0c;这些链接里会有经销商店铺&#xff0c;或者是非授权店铺&#xff0c;同时伴随的还会有低价、窜货、假货产品。假货大多是低价链接&#xff0c;面对线上逐渐增多的假货链接&#xff0c;品牌又该如…

C++ / QT 旅游产品管理系统

一、项目介绍 旅游产品管理系统 你是一家旅行社的 IT 主管&#xff0c;现在需要你设计并实现一个旅游产品管理系统。 1 &#xff09; 基本功能要求 * 实现基础界面&#xff1a; 参照现有的旅游产品管理系统&#xff1a;查看产品、选择产品、使用说明等内容 * 支持旅游产品…

【每日一题】Leetcode - 283. 移动零

题目 Leetcode - 283. 移动零 解题思路 从右向左遍历&#xff0c;遇到0&#xff0c;就将后面所有元素前移&#xff0c;同时更新长度&#xff0c;使其减1&#xff0c;因为移动n次&#xff0c;倒数n位就被0占据&#xff0c;后续操作可忽略 class Solution {public void moveZ…

G1吊舱全面升级,新增软件驱动库,支持多平台使用

G1吊舱&#xff0c;是我们去年推出的一款自研的云台产品&#xff0c;体积小巧&#xff0c;功能强大&#xff0c;上市后得到了很多朋友的支持。在上市后的一年期间&#xff0c;我们多方收集用户反馈&#xff0c;并基于用户的宝贵建议对G1吊舱进行了软硬件上的升级。 ​ 一、软件…

【ubuntu】【vmware tools】解决重启后看不到共享目录的问题

1、现象 ubuntu 22 vmware 16&#xff0c;安装后会发现 “Reinstall VMware Tools…” 灰色不可用。如图&#xff1a; 2、原因分析 ubuntu 22 ISO 内不再提供 VMware Tools 的安装包&#xff0c;未检测到所以灰色不可用 在 Ubuntu 22 上挂载 Windows HGFS 共享目录&#xff…

点成分享丨实验室磁力搅拌器的原理及应用

磁力搅拌器概述 磁力搅拌器是一种广泛应用于化学实验室、生物技术、制药和其他研究领域的实验室设备。在实验中&#xff0c;溶液需要混合均匀才能进行下一步的反应或测量。传统的方法是通过手动搅拌或机械搅拌来实现&#xff0c;但这些方法都有一定的缺陷&#xff0c;如不均匀、…

图解平衡二叉搜索树

gitee仓库&#xff1a;https://gitee.com/WangZihao64/data-structure-and-algorithm/tree/master/avl 有如下一棵树(采用加入左结点平衡因子-1&#xff0c;加入右结点平衡因子1的方式)&#xff1a; 插入有以下几种情况&#xff1a; 1.平衡因子变为2 2.平衡因子变为0 3.平衡因…

一个基于 SpringCloud 微服务架构的前后端分离博客系统

项目介绍 蘑菇博客( MoguBlog )&#xff0c;一个基于微服务架构的前后端分离博客系统。Web 端使用 Vue ElementUi , 移动端使用 uniapp 和 ColorUI。 后端使用 SpringCloud SpringBoot Mybatis-plus进行开发&#xff0c;使用 Jwt SpringSecurity 做登录验证和权限校验&am…

统计机器学习第十三章极大似然估计的性质——图解MLE的渐进正态性

n10; t10000; s1/12/n; xlinspace(-0.4,0.4,100); y1/sqrt(2*pi*s)*exp(-x.^2/(2*s)); zmean(rand(t,n)-0.5,2);figure(1); clf; hold on b20; hist(z,b); hplot(x,y*t/b*(max(z)-min(z)),r-);这段代码的功能是生成随机数并进行直方图和曲线的可视化。下面是每行代码的解释&…

[算法前沿]--028-基于Hugging Face -Transformers的预训练模型微调

1. 简介 本章节将使用 Hugging Face 生态系统中的库——🤗 Transformers来进行自然语言处理工作(NLP)。 Transformers的历史 以下是 Transformer 模型(简短)历史中的一些参考点: Transformer 架构于 2017 年 6 月推出。原始研究的重点是翻译任务。随后推出了几个有影响…

Chrome/Edge 浏览器多账号登录,测试同一业务系统的不同账号角色

文章目录 如何使用多账户&#xff1f;ChromeEdge 虽然说用不同浏览器测试也比较方便、还能顺带测试多浏览器兼容问题…… 但我是开发呀&#xff0c;我只想用我最习惯的谷歌浏览器完成快速开发&#xff0c;把功能铺上&#xff0c;专注于业务逻辑的开发 这些浏览器差异等只会给我…

RTSP/Onvif协议视频平台EasyNVR硬件无法进入服务器该如何解决?

EasyNVR是基于RTSP/Onvif协议的视频接入、处理及分发的安防视频云平台&#xff0c;可提供的视频能力包括&#xff1a;设备接入、实时视频直播、录像、云存储、录像回放与检索、告警、级联等&#xff0c;平台可支持将接入的视频流进行全平台、全终端的分发&#xff0c;分发的视频…

占空比任意方波的傅里叶级数展开

目录 傅里叶级数的复数形式占空比任意方波的傅里叶级数展开 常见的方波信号傅里叶级数展开都是占空比为50%&#xff0c;如方波信号傅里叶级数展开&#xff0c;但有的时候信号的占空比不一定是50%的信号&#xff0c;这时我们要对其进行傅里叶变换或者频谱推导的时候&#xff0c;…

Android应用权限请求步骤

1.在AndroidManifest.xml中配置请求权限 <uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE"/> 2.在onCreate(Bundle savedInstanceStat…

ffmpeg之linux编译

文章目录 一、下载源码二、选项说明三、依赖库四、编译安装 一、下载源码 上官网https://ffmpeg.org/download.html下载源码 二、选项说明 --disable-static&#xff1a;禁止构建静态库&#xff0c;默认关闭&#xff08;即默认构建的是静态库&#xff09;--enable-shared&a…

脉冲离子风棒的工作原理、特点及其应用

脉冲离子风棒是一种独特的清洁工具&#xff0c;它利用高能离子风的冲击力&#xff0c;可以快速而彻底地清洁物体表面静电。本文将介绍脉冲离子风棒的工作原理、特点以及其在清洁领域的应用。 脉冲离子风棒的工作原理是利用高能脉冲电场将气体中的分子电离&#xff0c;并产生离子…

OpenText 企业内容管理平台的亮点及优势

OpenText Extended ECM 平台 将内容服务与领先应用程序集成&#xff0c;以弥合内容孤岛、加快信息流并扩大治理 什么是内容服务集成&#xff1f; 内容服务集成通过将内容管理平台与处于流程核心的独立应用程序和系统连接起来&#xff0c;支持并扩展了 ECM 的传统优势。 最好的…

Itext 7 生成pdf带有背景图

Itext 7 生成pdf带有背景图并下载PDF到本地 引入jar包 <dependency><groupId>com.itextpdf</groupId><artifactId>itext7-core</artifactId><version>7.0.3</version><type>pom</type></dependency>代码实现 Get…