理论
今天,大多数数字图像和成像设备每通道使用8位,因此将设备的动态范围限制为两个数量级(实际上是256级),而人眼可以适应变化十个数量级的照明条件。 当我们拍摄现实世界场景的照片时,明亮区域可能会曝光过度,而暗区域可能会曝光不足,因此我们无法使用单次曝光捕获所有细节。 HDR成像适用于每通道使用8位以上(通常为32位浮点值)的图像,从而允许更宽的动态范围。
获取HDR图像的方法有很多种,但最常见的方法是使用不同曝光值拍摄的场景照片。 要结合这种曝光,了解相机的响应函数是有用的,并且有估算它的算法。 混合HDR图像后,必须将其转换回8位以在常规显示器上查看。 此过程称为色调映射。 当场景或相机的物体在镜头之间移动时会出现额外的复杂性,因为应该注册和对齐具有不同曝光的图像。
我们将展示如何从曝光序列生成和显示HDR图像。 在我们的例子中,图像已经对齐,没有移动的物体。 我们还展示了一种称为曝光融合的替代方法,可产生低动态范围图像。 HDR管道的每个步骤都可以使用不同的算法实现,因此请查看参考手册以查看所有步骤。
曝光序列
代码
#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, char**argv)
{
vector<Mat> images;
vector<float> times;
loadExposureSeq(argv[1], 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<TonemapDurand> tonemap = createTonemapDurand(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 + std::string("/");
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();
}
解释
加载图像和曝光时间
首先,我们从用户定义的文件夹加载输入图像和曝光时间。 该文件夹应包含images和list.txt - 包含文件名和反向曝光时间的文件。
对于我们的图像序列,列表如下:
估计相机响应
有必要知道许多HDR构造算法的相机响应函数(CRF)。 我们使用其中一种校准算法来估算所有256个像素值的逆CRF。
制作HDR图像
我们使用Debevec的加权方案,使用前一项中计算的响应构建HDR图像。
色调映射HDR图像
由于我们希望在常见的LDR显示器上看到我们的结果,因此我们必须将HDR图像映射到8位范围,以保留大部分细节。 这是色调映射方法的主要目标。 我们使用带有双边滤波的tonemapper,并将2.2设置为伽马校正的值。
进行曝光融合
如果我们不需要HDR图像,可以使用另一种方法合并曝光。 该过程称为曝光融合,并产生不需要伽马校正的LDR图像。 它也不使用照片的曝光值。
写结果
现在是时候看看结果了。 请注意,HDR图像无法以常见图像格式之一存储,因此我们将其保存为Radiance图像(.hdr)。 此外,所有HDR成像函数都会在[0,1]范围内返回结果,因此我们应将结果乘以255。