蚊章汇 - HDR
type: channel
link: https://linuxcn.bwsl.wang/tag/HDR/
items: 使用 OpenCV 进行高动态范围（HDR）成像

使用 OpenCV 进行高动态范围（HDR）成像
type: item
date: 2018-06-17T07:52:00+08:00
description: 在本教程中，我们将学习如何使用由不同曝光设置拍摄的多张图像创建 高动态范围 High Dynamic Range （HDR）图像。 我们将以 C++ 和 Python 两种形式分享代码。什么是高动态范围成像？大多数数码相机和显示器都是按照 24 位矩阵捕获或者显示彩色图像。 每个颜色通道有 8 位，因此每个通道的像素值在 0-255 范围内。 换句话说，普通的相机或者显示器的动态范围是有限的。但是，我们周围世界动态范围极大。 在车库内关灯就会变黑，直接看着太阳就会变得非常亮。 即使不考虑这些极端，在日常情况下，8 位的通道勉强可以捕捉到现场场景。 因此，相机会尝试去评估光照并且自动设置曝光，这样图像的最关注区域就会有良好的动态范围，并且太暗和太亮的部分会被相应截取为 0 和 255。在下图中，左侧的图像是正常曝光的图像。 请注意，由于相机决定使用拍摄主体（我的儿子）的设置，所以背景中的天空已经完全流失了，但是明亮的天空也因此被刷掉了。 右侧的图像是由 iPhone 生成的HDR图像。iPhone 是如何拍摄 HDR 图像的呢？ 它实际上采用三种不同的曝光度拍摄了 3 张图像，3 张图像拍摄非常迅速，在 3 张图像之间几乎没有产生位移。然后组合三幅图像来产生 HDR 图像。 我们将在下一节看到一些细节。将在不同曝光设置下获取的相同场景的不同图像组合的过程称为高动态范围（HDR）成像。高动态范围（HDR）成像是如何工作的？在本节中，我们来看下使用 OpenCV 创建 HDR 图像的步骤。要想轻松学习本教程，请点击此处下载 C++ 和 Python 代码还有图像。 如果您有兴趣了解更多关于人工智能，计算机视觉和机器学习的信息，请订阅我们的电子杂志。第 1 步：捕获不同曝光度的多张图像当我们使用相机拍照时，每个通道只有 8 位来表示场景的动态范围（亮度范围）。 但是，通过改变快门速度，我们可以在不同的曝光条件下拍摄多个场景图像。 大多数单反相机（SLR）有一个功能称为 自动包围式曝光 Auto Exposure Bracketing （AEB），只需按一下按钮，我们就可以在不同的曝光下拍摄多张照片。 如果你正在使用 iPhone，你可以使用这个自动包围式 HDR 应用程序，如果你是一个 Android 用户，你可以尝试一个更好的相机应用程序。场景没有变化时，在相机上使用自动包围式曝光或在手机上使用自动包围式应用程序，我们可以一张接一张地快速拍摄多张照片。 当我们在 iPhone 中使用 HDR 模式时，会拍摄三张照片。曝光不足的图像：该图像比正确曝光的图像更暗。 目标是捕捉非常明亮的图像部分。正确曝光的图像：这是相机将根据其估计的照明拍摄的常规图像。曝光过度的图像：该图像比正确曝光的图像更亮。 目标是拍摄非常黑暗的图像部分。但是，如果场景的动态范围很大，我们可以拍摄三张以上的图片来合成 HDR 图像。 在本教程中，我们将使用曝光时间为1/30 秒，0.25 秒，2.5 秒和 15 秒的 4 张图像。 缩略图如下所示。单反相机或手机的曝光时间和其他设置的信息通常存储在 JPEG 文件的 EXIF 元数据中。 查看此链接可在 Windows 和 Mac 中查看存储在 JPEG 文件中的 EXIF 元数据。 或者，您可以使用我最喜欢的名为 EXIFTOOL 的查看 EXIF 的命令行工具。我们先从读取分配到不同曝光时间的图像开始。C++void readImagesAndTimes(vector<Mat> &images, vector<float> &times) { int numImages = 4; // 曝光时间列表 static const float timesArray[] = {1/30.0f,0.25,2.5,15.0}; times.assign(timesArray, timesArray + numImages); // 图像文件名称列表 static const char* filenames[] = {"img_0.033.jpg", "img_0.25.jpg", "img_2.5.jpg", "img_15.jpg"}; for(int i=0; i < numImages; i++) { Mat im = imread(filenames[i]); images.push_back(im); } } Pythondef readImagesAndTimes(): # 曝光时间列表 times = np.array([ 1/30.0, 0.25, 2.5, 15.0 ], dtype=np.float32) # 图像文件名称列表 filenames = ["img_0.033.jpg", "img_0.25…