[OpenCV实战]24 使用OpenCV进行曝光融合
目录
本教程中,我们将了解使用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进行曝光融合的更多相关文章
- [OpenCV实战]50 用OpenCV制作低成本立体相机
本文主要讲述利用OpenCV制作低成本立体相机以及如何使用OpenCV创建3D视频,准确来说是模仿双目立体相机,我们通常说立体相机一般是指双目立体相机,就是带两个摄像头的那种(目就是指眼睛,双目就是两 ...
- [OpenCV实战]48 基于OpenCV实现图像质量评价
本文主要介绍基于OpenCV contrib中的quality模块实现图像质量评价.图像质量评估Image Quality Analysis简称IQA,主要通过数学度量方法来评价图像质量的好坏. 本文 ...
- [OpenCV实战]45 基于OpenCV实现图像哈希算法
目前有许多算法来衡量两幅图像的相似性,本文主要介绍在工程领域最常用的图像相似性算法评价算法:图像哈希算法(img hash).图像哈希算法通过获取图像的哈希值并比较两幅图像的哈希值的汉明距离来衡量两幅 ...
- [OpenCV实战]47 基于OpenCV实现视觉显著性检测
人类具有一种视觉注意机制,即当面对一个场景时,会选择性地忽略不感兴趣的区域,聚焦于感兴趣的区域.这些感兴趣的区域称为显著性区域.视觉显著性检测(Visual Saliency Detection,VS ...
- [OpenCV实战]46 在OpenCV下应用图像强度变换实现图像对比度均衡
本文主要介绍基于图像强度变换算法来实现图像对比度均衡.通过图像对比度均衡能够抑制图像中的无效信息,使图像转换为更符合计算机或人处理分析的形式,以提高图像的视觉价值和使用价值.本文主要通过OpenCV ...
- [OpenCV实战]44 使用OpenCV进行图像超分放大
图像超分辨率(Image Super Resolution)是指从低分辨率图像或图像序列得到高分辨率图像.图像超分辨率是计算机视觉领域中一个非常重要的研究问题,广泛应用于医学图像分析.生物识别.视频监 ...
- [OpenCV实战]23 使用OpenCV获取高动态范围成像HDR
目录 1 背景 1.1 什么是高动态范围(HDR)成像? 1.2 高动态范围(HDR)成像如何工作? 2 代码 2.1 运行环境配置 2.2 读取图像和曝光时间 2.3 图像对齐 2.4 恢复相机响应 ...
- [OpenCV实战]25 使用OpenCV进行泊松克隆
目录 1 Seamless Cloning实现 1.1 Seamless Cloning实例 1.2 正常克隆(NORMAL_CLONE)与混合克隆(MIXED_CLONE) 1.2.1 Normal ...
- [OpenCV实战]52 在OpenCV中使用颜色直方图
颜色直方图是一种常见的图像特征,顾名思义颜色直方图就是用来反映图像颜色组成分布的直方图.颜色直方图的横轴表示像素值或像素值范围,纵轴表示该像素值范围内像素点的个数或出现频率.颜色直方图属于计算机视觉中 ...
随机推荐
- 齐博x1如果把万能表单直接插入到内容中去
很多时候,你创建了一个万能表单可能像下面这个情况,在文章中加一个链接叫别人点击填表,其实这个很不人性化,用户也容易忽略. 其实你完全可以像下面这样,把表单直接引用到文章中来.给用户更直观的感觉 那是如 ...
- 14.api根路由
我们可以通过使用超链接来提高我们APi的内聚力和可发现性 一.为我们的API创建一个根路径 我们的视图有很多个url,但是没有一个入口点,可以使用@api_view创建一个根路径 #views.p ...
- The XOR Largest Pair(字典树)
题目描述 在给定的 N 个整数 A1,A2,-,AN 中选出两个进行异或运算,得到的结果最大是多少? 输入格式 第一行一个整数 N. 第二行 N 个整数 Ai. 输出格式 一个整数表示答案. 样例 ...
- CSS基础知识筑基
01.CSS 简介 CSS 指层叠样式表 (Cascading Style Sheets),对HTML网页内容进行统一外观样式设计和管理,给网页进行各种装饰,让她变得美观,是HTML的化妆师.(Cas ...
- Codeforces Global Round 18 B. And It's Non-Zero(按位前缀和)
题目大意:求一段数(l到r)的按位与结果不为零需要删除中间元素的最小个数 思路:按位与使得结果不为0只要有某一位全是1即可,所以只要统计每一位1的个数,用总个数减去1的个数就是某一位0的个数 删除包含 ...
- nginx安装及相关操作
工作中经常用到nginx,今天写个自动部署nginx的脚本.nginx版本选用:1.20.2 1.创建nginx安装脚本(nginx.sh) [root@iZ2ze7uphtapcv51egcm7rZ ...
- docker安装消息队列(rabbitmq)及数据库(mongo、mysql)
解决ipv6 访问问题 nohup socat TCP6-LISTEN:36001,reuseaddr,fork TCP4:127.0.0.1:36000 > /root/ip6to4.log ...
- luoguP1505旅游(处理边权的树剖)
/* luogu1505 非常简单的处理边权的树剖题. 在树上将一条边定向,把这条边的权值赋给这条边的出点 树剖的时候不计算lca权值即可 */ #include<bits/stdc++.h&g ...
- 【题解】P7860 [COCI2015-2016#2] ARTUR
题面传送门 好题. 主要思路和另一位巨佬差不多,详细讲一下判断的部分. 解决思路: 首先考虑本题与拓扑排序有和关系.可以想到,某些棍子的先后移动顺序是有限制的.比如: 这里红色的必须比蓝色的先移动,因 ...
- MLP(SGD or Adam) Perceptron Neural Network Working by Pytorch(including data preprocessing)
通过MLP多层感知机神经网络训练模型,使之能够根据sonar的六十个特征成功预测物体是金属还是石头.由于是简单的linearr线性仿射层,所以网络模型的匹配度并不高. 这是我的第一篇随笔,就拿这个来练 ...