介绍
如今,大多数数字图像和成像设备都使用每通道 8 位,因此将设备的动态范围限制在两个数量级(实际上是 256 个级别),而人眼可以适应变化十个数量级的光照条件。当我们拍摄现实世界场景的照片时,明亮区域可能会曝光过度,而黑暗区域可能会曝光不足,因此我们无法使用单次曝光捕捉所有细节。HDR 成像适用于每通道使用超过 8 位(通常是 32 位浮点值)的图像,从而允许更宽的动态范围。
有多种方法可以获得 HDR 图像,但最常见的方法是使用以不同曝光值拍摄的场景照片。要组合这些曝光,了解相机的响应函数很有用,并且有算法可以估算它。混合 HDR 图像后,必须将其转换回 8 位才能在普通显示器上查看。此过程称为色调映射。当场景或相机中的物体在拍摄之间移动时,会出现额外的复杂性,因为必须注册和对齐具有不同曝光的图像。
在本教程中,我们将展示如何从曝光序列生成和显示 HDR 图像。在我们的案例中,图像已经对齐,并且没有移动物体。我们还演示了一种称为曝光融合的替代方法,该方法可生成低动态范围图像。HDR 管道的每个步骤都可以使用不同的算法来实现,因此请查看参考手册以了解所有算法。
曝光顺序
源代码
C++JavaPython
本教程代码如下所示。您也可以从此处下载
#include "opencv2/photo.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <vector>
#include <iostream>
#include <fstream>
using namespace cv;
using namespace std;
void loadExposureSeq(String, vector<Mat>&, vector<float>&);
int main(int argc, char**argv)
{
CommandLineParser parser( argc, argv, "{@input | | Input directory that contains images and exposure times. }" );
vector<Mat> images;
vector<float> times;
loadExposureSeq(parser.get<String>( "@input" ), images, times);
Mat response;
Ptr<CalibrateDebevec> calibrate = createCalibrateDebevec();
calibrate->process(images, response, times);
Mat hdr;
Ptr<MergeDebevec> merge_debevec = createMergeDebevec();
merge_debevec->process(images, hdr, times, response);
Mat ldr;
Ptr<Tonemap> tonemap = createTonemap(2.2f);
tonemap->process(hdr, ldr);
Mat fusion;
Ptr<MergeMertens> merge_mertens = createMergeMertens();
merge_mertens->process(images, fusion);
imwrite("fusion.png", fusion * 255);
imwrite("ldr.png", ldr * 255);
imwrite("hdr.hdr", hdr);
return 0;
}
void loadExposureSeq(String path, vector<Mat>& images, vector<float>& times)
{
path = path + "/";
ifstream list_file((path + "list.txt").c_str());
string name;
float val;
while(list_file >> name >> val) {
Mat img = imread(path + name);
images.push_back(img);
times.push_back(1 / val);
}
list_file.close();
}
示例图像
可以从这里list.txt
下载包含图像、曝光时间和文件的数据目录。
解释
- 加载图像和曝光时间
vector<Mat> images;
vector<float> times;
loadExposureSeq(parser.get<String>( "@input" ), images, times);
首先,我们从用户定义的文件夹加载输入图像和曝光时间。该文件夹应包含图像和list.txt - 包含文件名和逆曝光时间的文件。
对于我们的图像序列,列表如下:
memorial01.png 0.0625
...
memorial15.png 1024
- 估计相机响应
Mat response;
Ptr<CalibrateDebevec> calibrate = createCalibrateDebevec();
calibrate->process(images, response, times);
对于许多 HDR 构建算法来说,了解相机响应函数 (CRF) 是必需的。我们使用其中一种校准算法来估计所有 256 个像素值的逆 CRF。
- 制作 HDR 图像
我们使用 Debevec 的加权方案,利用上一项计算的响应来构建 HDR 图像。
- 色调映射 HDR 图像
由于我们希望在普通 LDR 显示器上看到结果,因此我们必须将 HDR 图像映射到 8 位范围以保留大多数细节。这是色调映射方法的主要目标。我们使用具有双边滤波的色调映射器,并将 2.2 设置为伽马校正的值。
- 执行曝光融合
如果我们不需要 HDR 图像,还有另一种方法来合并曝光。这个过程称为曝光融合,可生成不需要伽马校正的 LDR 图像。它也不使用照片的曝光值。
- 写入结果
现在是时候查看结果了。请注意,HDR 图像不能以常见的图像格式之一存储,因此我们将其保存为 Radiance 图像 (.hdr)。此外,所有 HDR 成像函数都会在 [0, 1] 范围内返回结果,因此我们应该将结果乘以 255。
您可以尝试其他色调映射算法:cv::TonemapDrago、cv::TonemapMantiuk和cv::TonemapReinhard您还可以根据自己的照片调整 HDR 校准和色调映射方法中的参数。
结果
色调映射图像
曝光融合
其他资源
- Paul E Debevec 和 Jitendra Malik。从照片中恢复高动态范围辐射图。ACM SIGGRAPH 2008 课程,第 31 页。ACM,2008 年。[68]
- Mark A Robertson、Sean Borman 和 Robert L Stevenson。通过多次曝光实现动态范围改善。《图像处理》,1999 年。ICIP 99。会议论文集。1999 年国际会议论文集,第 3 卷,第 159-163 页。IEEE,1999 年。[227]
- Tom Mertens、Jan Kautz 和 Frank Van Reeth。曝光融合。《计算机图形学与应用》,2007 年。PG'07。第 15 届太平洋会议,第 382-390 页。IEEE,2007 年。[189]
- 维基百科-HDR
- 从照片中恢复高动态范围辐射图(网页)高动态范围成像从照片中恢复高动态范围辐射图(网页)