点击下方卡片,关注“OpenCV与AI深度学习”
视觉/图像重磅干货,第一时间送达
来源:OpenCV4.5.4官方文档
翻译整理:Color Space
目前大多数数字图像和成像设备每通道使用 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 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 - 包含文件名和反向曝光时间的文件。
对于我们的图像序列,列表如下:
memorial00.png 0.03125
memorial01.png 0.0625
...
memorial15.png 1024
Mat response;
Ptr<CalibrateDebevec> calibrate = createCalibrateDebevec();
calibrate->process(images, response, times);
很多HDR构建算法都需要了解相机响应函数(CRF)。我们使用其中一种校准算法来估计所有 256 个像素值的逆 CRF。
Mat hdr;
Ptr<MergeDebevec> merge_debevec = createMergeDebevec();
merge_debevec->process(images, hdr, times, response);
我们使用 Debevec 的加权方案使用在上一项中计算的响应来构建 HDR 图像。
Mat ldr;
Ptr<Tonemap> tonemap = createTonemap(2.2f);
tonemap->process(hdr, ldr);
由于我们希望在普通 LDR 显示器上看到我们的结果,我们必须将我们的 HDR 图像映射到 8 位范围,以保留大部分细节。这是色调映射方法的主要目标。我们使用带有双边滤波的色调映射器并将 2.2 设置为伽马校正的值。
Mat fusion;
Ptr<MergeMertens> merge_mertens = createMergeMertens();
merge_mertens->process(images, fusion);
当我们不需要 HDR 图像时,有一种替代方法可以合并我们的曝光。此过程称为曝光融合,可生成不需要伽马校正的 LDR 图像。它也不使用照片的曝光值。
imwrite ( "fusion.png" , fusion * 255);
imwrite ( "ldr.png" , ldr * 255);
imwrite ( "hdr.hdr" , hdr);
现在是时候看看结果了。请注意,HDR 图像不能以一种常见的图像格式存储,因此我们将其保存为 Radiance 图像 (.hdr)。此外,所有 HDR 成像函数都返回 [0, 1] 范围内的结果,因此我们应该将结果乘以 255。
您可以尝试其他色调映射算法:cv::TonemapDrago、cv::TonemapMantiuk和cv::TonemapReinhard您还可以为自己的照片调整 HDR 校准和色调映射方法中的参数。
—版权声明—
仅用于学术分享,版权属于原作者。
如有侵权,请联系微信号:Color_Space_001 删除或修改!
本文分享自 OpenCV与AI深度学习 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!