opencv 下的 Mertens et al. (2009-hdr) 算法剖析

这篇具有很好参考价值的文章主要介绍了opencv 下的 Mertens et al. (2009-hdr) 算法剖析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.简介

Mertens et al. (2009)算法通过考虑图像的亮度、对比度和细节来融合曝光时间不同的图像。它能够有效地处理高对比度场景,并在合成图像中保留细节和阴影细节。

2.Mertens算法原理

  1. 图像预处理:

    • 去除暗角效应(vignetting):通过校正图像的亮度不均匀性来去除暗角效应,可以使用高斯模糊或均值滤波等方法。
    • 白平衡校准:使用灰度世界假设或基于灰度世界的方法来校正图像的颜色偏移,使其具有更准确的颜色平衡。
    • 响应函数校准:根据相机的响应函数,对图像进行校准,从而消除曝光时间不同引起的响应差异。
  2. 曝光融合:

    • 图像对齐:使用图像对齐算法将不同曝光的图像进行对齐,以使特征点对齐。可以使用特征点匹配算法,如SIFT、SURF、ORB等来实现。
    • 多尺度图像融合:使用拉普拉斯金字塔实现多尺度图像融合。对于每个曝光的图像,生成一系列金字塔图像,然后将对应层的图像进行融合,得到一系列融合后的图像。
    • 融合权重计算:通过计算每个像素的融合权重来确定不同曝光图像的贡献度。权重可以根据像素的亮度、对比度和细节等进行计算。
  3. 色调映射:

    • 色调映射函数:根据用户的偏好和显示设备的约束,选择合适的色调映射函数,如线性映射、曲线映射、全局映射或局部映射等。
    • 色调映射操作:将HDR图像通过选定的色调映射函数进行映射,得到最终的输出图像。在映射过程中,可以调整图像的亮度、对比度和颜色饱和度等。

3.opencv中的单通道图像的Mertens算法实现

void cjhdr::process(cv::InputArrayOfArrays src, cv::OutputArray dst)
{
    std::vector<cv::Mat> images;
    src.getMatVector(images);

    cv::Size size = images[0].size();
    int CV_32FCC = CV_MAKETYPE(CV_32F, 1);

    std::vector<cv::Mat> weights(images.size());
    cv::Mat weight_sum = cv::Mat::zeros(size, CV_32F);
    std::vector<cv::Mat> gray(3);

    for(size_t i = 0; i < images.size(); i++)
    {
        images[i].convertTo(gray[i], CV_32F, 1.0f/255.0f);//3.859
    }

    for(size_t i = 0; i < images.size(); i++)
    {
        cv::Mat contrast, wellexp;
        std::vector<cv::Mat> splitted(1);

        cv::Laplacian(gray[i], contrast, CV_32F);    

        contrast = cv::abs(contrast);                
        cv::pow(contrast, 2.0f, contrast);           

        wellexp = cv::Mat::ones(size, CV_32F);      
        cv::split(gray[i], splitted);                
        cv::Mat expo = splitted[0] - 0.5f;           
        cv::pow(expo, 2.0f, expo);                  
        expo = -expo / 0.08f;                     
        cv::exp(expo, expo);
        wellexp = wellexp.mul(expo);                 
        cv::pow(wellexp, 3.0f, wellexp);            

        weights[i] = contrast;
        weights[i] = weights[i].mul(wellexp);        
        weight_sum += weights[i];                  
    }

    int maxlevel = static_cast<int>(logf(static_cast<float>(cv::min(size.width, size.height))) / logf(2.0f));//7us
    std::vector<cv::Mat> res_pyr(maxlevel + 1);

    for(size_t i = 0; i < images.size(); i++)
    {
        weights[i] /= weight_sum;

        std::vector<cv::Mat> img_pyr, weight_pyr;
        cv::buildPyramid(gray[i], img_pyr, maxlevel);
        cv::buildPyramid(weights[i], weight_pyr, maxlevel);

        for(int lvl = 0; lvl < maxlevel; lvl++)
        {
            cv::Mat up;
            cv::pyrUp(img_pyr[lvl + 1], up, img_pyr[lvl].size());
            img_pyr[lvl] -= up;
        }
        for(int lvl = 0; lvl <= maxlevel; lvl++)
        {
            std::vector<cv::Mat> splitted(1);
            cv::split(img_pyr[lvl], splitted);
            splitted[0] = splitted[0].mul(weight_pyr[lvl]);
            cv::merge(splitted, img_pyr[lvl]);
            if(res_pyr[lvl].empty())
            {
                res_pyr[lvl] = img_pyr[lvl];
            }
            else
            {
                res_pyr[lvl] += img_pyr[lvl];
            }
        }
    }

    for(int lvl = maxlevel; lvl > 0; lvl--)
    {
        cv::Mat up;
        cv::pyrUp(res_pyr[lvl], up, res_pyr[lvl - 1].size());
        res_pyr[lvl - 1] += up;
    }
    dst.create(size, CV_32FCC);
    res_pyr[0].copyTo(dst);
}

4.说明

首先,从输入数组src中获取图像数据,并将其转换为CV_32F格式的灰度图像。然后,对每个图像进行以下处理步骤:

  1. 计算图像的拉普拉斯算子
  2. 对拉普拉斯算子结果取绝对值并进行平方处理
  3. 创建一个与图像相同大小的全1矩阵,并对图像进行减法操作,得到expo矩阵
  4. expo矩阵进行平方和指数运算,得到wellexp矩阵
  5. 将计算得到的拉普拉斯平方结果和wellexp矩阵相乘,得到每个图像的权重矩阵
  6. 将所有权重矩阵相加,得到总的权重和矩阵weight_sum

接下来,根据图像的大小计算出金字塔的最大层数maxlevel,并创建一个保存处理结果的金字塔数组res_pyr

然后,对每个图像进行以下处理步骤:

  1. 将权重矩阵除以总的权重和矩阵,得到归一化的权重矩阵
  2. 使用cv::buildPyramid函数分别构建原图像和归一化权重矩阵的金字塔
  3. 对金字塔层级进行循环,从较高层级往下操作
    • 使用cv::pyrUp函数对原图像金字塔进行上采样操作,并与下一层级的金字塔图像做差
    • 将差值结果与对应层级的归一化权重矩阵相乘,并合并通道
    • 将合并后的结果与之前层级的结果进行累加操作

最后,对金字塔进行反向操作,使用cv::pyrUp函数对金字塔图像进行上采样,并与较低层级的金字塔图像累加。

最终,将处理结果保存在输出数组dst中。文章来源地址https://www.toymoban.com/news/detail-508351.html

到了这里,关于opencv 下的 Mertens et al. (2009-hdr) 算法剖析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【推荐系统入门到项目实战】(三):矩阵分解和ALS算法

    🌸个人主页:JOJO数据科学 📝个人介绍: 统计学top3 高校统计学硕士在读 💌如果文章对你有帮助,欢迎✌ 关注 、👍 点赞 、✌ 收藏 、👍 订阅 专栏 ✨本文收录于【推荐系统入门到项目实战】 本系列主要分享一些学习推荐系统领域的方法和代码实现。 之前我们介绍了推荐

    2024年02月06日
    浏览(43)
  • 基于大数据和ALS算法实现的房源智能推荐系统

    收藏和点赞,您的关注是我创作的动力   目前,现有的房源信息不够透明化大多中介混淆市场,内含不为人知的商业链。有经验的租客们会通过周边房价走势和走访周边房源对比调研、筛选适合自己的房源。 同时,对于用户工作地点需求和各种人群类型如大学生群体,年

    2024年02月07日
    浏览(36)
  • 大数据课程K18——Spark的ALS算法与显式矩阵分解

    文章作者邮箱:yugongshiye@sina.cn              地址:广东惠州 ⚪ 掌握Spark的ALS算法与显式矩阵分解; ⚪ 掌握Spark的ALS算法原理; 我们在实现推荐系统时,当要处理的那些数据是由用户所提供的自身的偏好数据,这些数据被称作显式偏好数据,由显示偏好数据建立的矩阵称

    2024年02月09日
    浏览(31)
  • QuantitativeFinance:量化金融之金融时间序列分析之ES/ETS/GARCH模型的简介、Box-Jenkins方法-AR/MA/ARMA/ARIMA模型的简介及其建模四大步骤之详细攻略

    ML之TS:量化金融之金融时间序列分析之ES/ETS/GARCH模型的简介、Box-Jenkins方法-AR/MA/ARMA/ARIMA模型的简介及其建模四大步骤之详细攻略 目录 时间序列预测模型之ES/HLES/HWES模型/ETS模型/GARCH模型的简介 1、ES/HLES/HWES模型的概述

    2024年02月12日
    浏览(49)
  • 大数据Flink简介与架构剖析并搭建基础运行环境

    前面我们分别介绍了大数据计算框架Hadoop与Spark,虽然他们有的有着良好的分布式文件系统和分布式计算引擎,有的有着分布式数据集和基于内存的分布式计算引擎,但是却不能对无边界数据流进行有效处理,今天我们就分享一个第四代大数据分布式计算框架Flink简介与架构剖

    2024年02月10日
    浏览(48)
  • 【OpenCV学习】第16课:图像边缘提取 - Sobel算子详细剖析(图像梯度)

    理论 卷积的应用 - 图像边缘提取: 边缘是什么:是像素值发生跃迁的地方, 是图像的显著特征之一, 再图像特征提取丶对象检测丶模式识别等方面都有重要作用 如何捕捉/提取边缘:对图像求它的一阶导数,delta = f(x) - f(x-1), delta值越大, 说明像素在x方向变化越大,边缘信

    2024年02月04日
    浏览(47)
  • Windows下的CodeBlocks配置Opencv环境

    目录 1.Opencv下载 2.CodeBlocks下载 3.Cmake编译工具下载 4.编译Opencv源码 5.编译OpenCV库文件  (1)方式一  (2)方式二 6.动态链接库文件环境配置 7.CodeBlocks配置 8.编写使用OpenCV例子 9.程序异常终止解决 拓展 提示:建议读者安装或者配置环境变量的路径中最好不要包含任何的特殊

    2024年02月03日
    浏览(44)
  • 算法沉淀——贪心算法一(leetcode真题剖析)

    贪心算法(Greedy Algorithm)是一种基于贪心策略的优化算法,它通常用于求解最优化问题,每一步都选择当前状态下的最优解,以期望通过局部最优的选择最终达到全局最优。贪心算法的思想是在每一步都做出在当前状态下局部最优的选择,而不考虑未来可能造成的影响。 在

    2024年03月08日
    浏览(48)
  • 算法沉淀——贪心算法六(leetcode真题剖析)

    题目链接:https://leetcode.cn/problems/broken-calculator/ 在显示着数字 startValue 的坏计算器上,我们可以执行以下两种操作: **双倍(Double):**将显示屏上的数字乘 2; **递减(Decrement):**将显示屏上的数字减 1 。 给定两个整数 startValue 和 target 。返回显示数字 target 所需的最小操

    2024年04月11日
    浏览(43)
  • 算法沉淀——贪心算法七(leetcode真题剖析)

    题目链接:https://leetcode.cn/problems/integer-replacement/ 给定一个正整数 n ,你可以做如下操作: 如果 n 是偶数,则用 n / 2 替换 n 。 如果 n 是奇数,则可以用 n + 1 或 n - 1 替换 n 。 返回 n 变为 1 所需的 最小替换次数 。 示例 1: 示例 2: 示例 3: 提示: 1 = n = 2^31 - 1 思路 这里我们

    2024年03月23日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包