目录

1 什么是曝光融合

2 曝光融合的原理

3 代码与结果

4 参考


本教程中,我们将了解使用OpenCV的Exposure Fusion(曝光融合)。

1 什么是曝光融合

曝光融合是一种将使用不同曝光设置拍摄的图像合成为一张看起来像色调映射的高动态范围(HDR)图像的图像的方法。当我们使用相机拍摄照片时,每个颜色通道只有8位来表示场景的亮度。然而,我们周围世界的亮度理论上可以从0(黑色)到几乎无限(直视太阳)。因此,傻瓜相机或移动相机根据场景决定曝光设置,以便使用相机的动态范围(0-255值)来表示图像中最有趣的部分。例如,在许多相机中,使用面部检测来查找面部并设置曝光,使得面部看起来很好。这引出了一个问题-我们可以在不同的曝光设置下拍摄多张照片并拍摄更大范围的场景亮度吗?答案是肯定的。传统上使用HDR成像然后进行色调映射的方式。具体见上篇文章:

https://blog.csdn.net/LuohenYJ/article/details/89712234

HDR成像要求我们知道精确的曝光时间。HDR图像本身看起来很暗,看起来不太漂亮。DR图像中的最小强度为0,但理论上没有最大值。所以我们需要将其值映射到0到255之间,以便我们可以显示它。将HDR图像映射到常规的每通道8位彩色图像的过程称为色调映射。如您所见,组装HDR图像和色调映射有点麻烦。我们不能不使用HDR就使用多个图像创建色调映射图像。结果证明我们可以用曝光融合来实现。

2 曝光融合的原理

应用曝光融合的步骤如下所述:

(1) 使用不同曝光拍摄多张图像

首先,我们需要在不移动相机的情况下捕获同一场景的一系列图像。如上所示,序列中的图像具有不同的曝光。这是通过改变相机的快门速度来实现的。通常,我们选择一些曝光不足的图像,一些曝光过度的图像和一个正确曝光的图像。

在“正确”曝光的图像中,选择快门速度(由相机或摄影师自动选择),以便每通道8位动态范围用于表示图像中最有趣的部分。太暗的区域被剪切为0,而太亮的区域被饱和到255。

在曝光不足的图像中,快门速度很快,图像很暗。因此,图像的8位用于捕获亮区域,而暗区域被剪切为0。在曝光过度的图像中,快门速度较慢,因此传感器捕获的光线更多,因此图像更亮。传感器的8位用于捕获暗区域的强度,而亮区域饱和到255的值。大多数单反相机都有一个称为自动曝光包围(AEB)的功能,只需按一下按钮,我们就可以在不同曝光下拍摄多张照片。当我们在iPhone中使用HDR模式时,它需要三张照片(安卓可以下载超级相机这个软件)。

(2) 图像对齐

即使使用三脚架获取序列中的图像也需要对齐,因为即使较小的相机抖动也会降低最终图像的质量。OpenCV提供了一种使用对齐这些图像的简便方法AlignMTB。该算法将所有图像转换为中值阈值位图(MTB)。通过将值1分配给比中值亮度更亮的像素来计算图像的MTB,否则为0。MTB 对曝光时间不变。因此,可以对准MTB而无需我们指定曝光时间。

(3) 图像融合

具有不同曝光的图像捕获不同范围的场景亮度。根据Tom Mertens,Jan Kautz和Frank Van Reeth 题为Exposure Fusion的论文。论文见:

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.64.7616&rep=rep1&type=pdf

曝光融合通过仅保留多重曝光图像序列中的“最佳”部分来计算所需图像。

作者提出了三个质量指标:

1曝光良好:如果序列中的图像中的像素接近零或接近255,则不应使用该图像来查找最终像素值。其值接近中间强度(128)的像素是比较合适的。

2对比度:高对比度通常意味着高品质。因此,对于该像素,给予特定像素的对比度值高的图像具有更高的权重。

3饱和度:类似地,更饱和的颜色更少被淘汰并且代表更高质量的像素。因此,特定像素的饱和度高的图像被赋予该像素的更高权重。

三种质量度量用于创建权重图,该权重图表示图像在位置处的像素的最终强度中的贡献。对权重图进行归一化,使得对于任何像素,所有图像的贡献总计为1。

结合权重图使用以下等式组合图像是很有效的:

其中,是原始图像,是输出图像。问题在于,由于像素是从不同曝光的图像中拍摄的,因此使用上述等式获得的输出图像将显示许多裂缝。该论文的作者使用拉普拉斯金字塔来混合图像。我们将在以后的文章中介绍这项技术的细节。

幸运的是使用OpenCV,这种图像曝光融合合并只是使用MergeMertens该类的两行代码。请注意,这个名字取决于Exposure Fusion论文的第一作者Tom Mertens 。

3 代码与结果

代码地址:

https://github.com/luohenyueji/OpenCV-Practical-Exercise

C++:

#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>
#include <fstream>
using namespace cv;
using namespace std; // Read Images
void readImages(vector<Mat> &images)
{
int numImages = 16;
static const char* filenames[] =
{
"image/memorial0061.jpg",
"image/memorial0062.jpg",
"image/memorial0063.jpg",
"image/memorial0064.jpg",
"image/memorial0065.jpg",
"image/memorial0066.jpg",
"image/memorial0067.jpg",
"image/memorial0068.jpg",
"image/memorial0069.jpg",
"image/memorial0070.jpg",
"image/memorial0071.jpg",
"image/memorial0072.jpg",
"image/memorial0073.jpg",
"image/memorial0074.jpg",
"image/memorial0075.jpg",
"image/memorial0076.jpg"
};
//读图
for (int i = 0; i < numImages; i++)
{
Mat im = imread(filenames[i]);
images.push_back(im);
}
} int main()
{
// Read images 读取图像
cout << "Reading images ... " << endl;
vector<Mat> images; //是否图像映射
bool needsAlignment = true; // Read example images 读取例子图像
readImages(images);
//needsAlignment = false; // Align input images
if (needsAlignment)
{
cout << "Aligning images ... " << endl;
Ptr<AlignMTB> alignMTB = createAlignMTB();
alignMTB->process(images, images);
}
else
{
cout << "Skipping alignment ... " << endl;
} // Merge using Exposure Fusion 图像融合
cout << "Merging using Exposure Fusion ... " << endl;
Mat exposureFusion;
Ptr<MergeMertens> mergeMertens = createMergeMertens();
mergeMertens->process(images, exposureFusion); // Save output image 图像保存
cout << "Saving output ... exposure-fusion.jpg" << endl;
imwrite("exposure-fusion.jpg", exposureFusion * 255); return 0;
}

Python:

import cv2
import numpy as np
import sys def readImagesAndTimes(): filenames = [
"image/memorial0061.jpg",
"image/memorial0062.jpg",
"image/memorial0063.jpg",
"image/memorial0064.jpg",
"image/memorial0065.jpg",
"image/memorial0066.jpg",
"image/memorial0067.jpg",
"image/memorial0068.jpg",
"image/memorial0069.jpg",
"image/memorial0070.jpg",
"image/memorial0071.jpg",
"image/memorial0072.jpg",
"image/memorial0073.jpg",
"image/memorial0074.jpg",
"image/memorial0075.jpg",
"image/memorial0076.jpg"
] images = []
for filename in filenames:
im = cv2.imread(filename)
images.append(im) return images if __name__ == '__main__': # Read images
print("Reading images ... ") if len(sys.argv) > 1:
# Read images from the command line
images = []
for filename in sys.argv[1:]:
im = cv2.imread(filename)
images.append(im)
needsAlignment = False
else :
# Read example images
images = readImagesAndTimes()
needsAlignment = False # Align input images
if needsAlignment:
print("Aligning images ... ")
alignMTB = cv2.createAlignMTB()
alignMTB.process(images, images)
else :
print("Skipping alignment ... ") # Merge using Exposure Fusion
print("Merging using Exposure Fusion ... ");
mergeMertens = cv2.createMergeMertens()
exposureFusion = mergeMertens.process(images) # Save output image
print("Saving output ... exposure-fusion.jpg")
cv2.imwrite("exposure-fusion.jpg", exposureFusion * 255)

本文第一张图获得的不同曝光的图像,通过这种方法所得结果如下:

在输入图像中,我们可以获得过度曝光图像中光线昏暗区域和曝光不足图像中明亮区域的细节。但是,在合并的输出图像中,像素在图像的每个部分都具有明亮的细节。我们还可以在之前的帖子中看到我们用于HDR成像的图像的这种效果。用于产生最终输出的四个图像显示在左侧,输出图像显示在右侧。结果如下图所示:

正如您在本文中所看到的,Exposure Fusion允许我们在不明确计算HDR图像的情况下实现类似于HDR + Tonemapping的效果。因此,我们不需要知道每张图像的曝光时间,但我们能够获得非常合理的结果。那么,为什么要费心去做HDR呢?好吧,在很多情况下,Exposure Fusion产生的输出可能不符合您的喜好。没有旋钮可以调整以使其变得不同或更好。另一方面,HDR图像捕获场景的原始亮度。如果您不喜欢色调映射的HDR图像,请尝试使用不同的色调映射算法。总之,Exposure Fusion代表了一种权衡。在速度和不太严格的要求下使得算法更加灵活(例如,不需要暴露时间)

4 参考

https://www.learnopencv.com/exposure-fusion-using-opencv-cpp-python/

[OpenCV实战]24 使用OpenCV进行曝光融合的更多相关文章

  1. [OpenCV实战]50 用OpenCV制作低成本立体相机

    本文主要讲述利用OpenCV制作低成本立体相机以及如何使用OpenCV创建3D视频,准确来说是模仿双目立体相机,我们通常说立体相机一般是指双目立体相机,就是带两个摄像头的那种(目就是指眼睛,双目就是两 ...

  2. [OpenCV实战]48 基于OpenCV实现图像质量评价

    本文主要介绍基于OpenCV contrib中的quality模块实现图像质量评价.图像质量评估Image Quality Analysis简称IQA,主要通过数学度量方法来评价图像质量的好坏. 本文 ...

  3. [OpenCV实战]45 基于OpenCV实现图像哈希算法

    目前有许多算法来衡量两幅图像的相似性,本文主要介绍在工程领域最常用的图像相似性算法评价算法:图像哈希算法(img hash).图像哈希算法通过获取图像的哈希值并比较两幅图像的哈希值的汉明距离来衡量两幅 ...

  4. [OpenCV实战]47 基于OpenCV实现视觉显著性检测

    人类具有一种视觉注意机制,即当面对一个场景时,会选择性地忽略不感兴趣的区域,聚焦于感兴趣的区域.这些感兴趣的区域称为显著性区域.视觉显著性检测(Visual Saliency Detection,VS ...

  5. [OpenCV实战]46 在OpenCV下应用图像强度变换实现图像对比度均衡

    本文主要介绍基于图像强度变换算法来实现图像对比度均衡.通过图像对比度均衡能够抑制图像中的无效信息,使图像转换为更符合计算机或人处理分析的形式,以提高图像的视觉价值和使用价值.本文主要通过OpenCV ...

  6. [OpenCV实战]44 使用OpenCV进行图像超分放大

    图像超分辨率(Image Super Resolution)是指从低分辨率图像或图像序列得到高分辨率图像.图像超分辨率是计算机视觉领域中一个非常重要的研究问题,广泛应用于医学图像分析.生物识别.视频监 ...

  7. [OpenCV实战]23 使用OpenCV获取高动态范围成像HDR

    目录 1 背景 1.1 什么是高动态范围(HDR)成像? 1.2 高动态范围(HDR)成像如何工作? 2 代码 2.1 运行环境配置 2.2 读取图像和曝光时间 2.3 图像对齐 2.4 恢复相机响应 ...

  8. [OpenCV实战]25 使用OpenCV进行泊松克隆

    目录 1 Seamless Cloning实现 1.1 Seamless Cloning实例 1.2 正常克隆(NORMAL_CLONE)与混合克隆(MIXED_CLONE) 1.2.1 Normal ...

  9. [OpenCV实战]52 在OpenCV中使用颜色直方图

    颜色直方图是一种常见的图像特征,顾名思义颜色直方图就是用来反映图像颜色组成分布的直方图.颜色直方图的横轴表示像素值或像素值范围,纵轴表示该像素值范围内像素点的个数或出现频率.颜色直方图属于计算机视觉中 ...

随机推荐

  1. GitLab私有化部署 - CI/CD - 持续集成/交付/部署 - 源代码托管 & 自动化部署

    预期目标 源代码管理 借助GitLab实现源代码托管,私有化部署版本,创建项目,创建用户组,分配权限,项目的签入/牵出等. 自动化部署 源代码产生变更时(如签入),自动化编译并发布到指定服务器中部署, ...

  2. 鸟哥linux私房菜习题总结

    第零章 1.请找出世界上跑得最快的超级计算机的相关信息? 系统名称:天河二号. 所在位置:中国广州中山大学超算中心. 使用的cpu型号与规格:采用的是Intel的Ivy Bridge处理器与Xeon ...

  3. Mysql知识点整理

    索引相关 abcd联合索引搜索ba会走索引么 会,重排 索引的底层实现是B+树,为何不采用红黑树,B树? (1):B+Tree非叶子节点只存储键值信息,降低B+Tree的高度,所有叶子节点之间都有一个 ...

  4. hyperf-搭建初始化

    官方文档* https://hyperf.wiki/2.0/#/README 初步搭建1. 安装项目 composer create-project hyperf/hyperf-skeleton 2. ...

  5. python 矩阵切片

    假设n是一个numpy或者torch.tensor张量,那么 n[a:b,c:d]则代表从a到b行(不含b行),c到d列(不含d列)的切片 当然,ab.cd中的数是可以省略掉,只要abcd中有一个数即 ...

  6. Sentinel 介绍与下载使用

    sentinel 前方参考 计算QPS-Sentinel限流算法 https://www.cnblogs.com/yizhiamumu/p/16819497.html Sentinel 介绍与下载使用 ...

  7. 「MySQL高级篇」explain分析SQL,索引失效&&常见优化场景

    大家好,我是melo,一名大三后台练习生 专栏回顾 索引的原理&&设计原则 欢迎关注本专栏:MySQL高级篇 本篇速览 在我们上一篇文章中,讲到了索引的原理&&设计原则 ...

  8. .NET 7 中 LINQ 的疯狂性能提升

    LINQ 是 Language INtegrated Query 单词的首字母缩写,翻译过来是语言集成查询.它为查询跨各种数据源和格式的数据提供了一致的模型,所以叫集成查询.由于这种查询并没有制造新的 ...

  9. 论文笔记 - MetaICL: Learning to Learn In Context

    Motivation Facebook 的 MetaICL,牛逼就对了: 对 LM 针对 ICL 进行微调(而不是特定的任务): 去除了自然语言的 Template,使用更直接的方式,排除了 Temp ...

  10. Oracle:ORA-39006、ORA-39213解决办法

    执行Oracle数据库导入,遇到报错ORA-39006: internal error.ORA-39213: Metadata processing is not available.这还是第一次遇到 ...