HDR图像合成及边缘检测(opencv 和 c++)

本文主要是记录个人的开发过程,及过程中遇到的问题及解决方法,对个人工作的一个总结。

一、HDR图像合成

由不同曝光设置拍摄的多张图像创建高动态范围High Dynamic Range(HDR)图像。
使用的是c++和OpenCV4.x。

主程序主要参考对象:使用 OpenCV 进行高动态范围(HDR)成像

1.捕获不同曝光度的多张图像

使用相机拍摄三张曝光时间不同的图像

  1. 曝光不足的图像:该图像比正确曝光的图像更暗。 目标是捕捉非常明亮的图像部分。
  2. 正确曝光的图像:这是相机将根据其估计的照明拍摄的常规图像。
  3. 曝光过度的图像:该图像比正确曝光的图像更亮。 目标是拍摄非常黑暗的图像部分。

如果场景的动态范围很大,我们可以拍摄三张以上的图片来合成 HDR 图像。

读取不同曝光时间的图像:

void readImagesAndTimes(vector<Mat> &images, vector<float> &times)      
{
   
  
  int numImages = 3;
  
  static const float timesArray[] = {
    0.000038, 0.000304, 0.003432 };    // 单位秒
  times.assign(timesArray, timesArray + numImages);         // 将timesArray里的值全部赋给times
  
  static const char* filenames[] = {
    "./pic/welding/10013_2_38.jpg",  "./pic/welding/10013_0_304.jpg", "./pic/welding/10013_1_3432.jpg" };
  for(int i=0; i < numImages; i++)
  {
   
    Mat im = imread(filenames[i]);  //默认读取BGR格式
    images.push_back(im);   //全部存储在images
  }
}

2.对齐图像

合成 HDR 图像时使用的图像如果未对齐可能会导致严重的伪影。

OpenCV 提供了一种简单的方法,使用 AlignMTB 对齐这些图像。 该算法将所有图像转换为中值阈值位图median threshold bitmaps(MTB)。 图像的 MTB 生成方式为将比中值亮度的更亮的分配为 1,其余为 0。 MTB 不随曝光时间的改变而改变。 因此不需要我们指定曝光时间就可以对齐 MTB。

  // Align input images 中值阈值位图MTB方式 对齐图片
  cout << "Aligning images ... " << endl;
  Ptr<AlignMTB> alignMTB = createAlignMTB();
  alignMTB->process(images, images);

3.提取相机响应函数

典型相机的响应与场景亮度不成线性关系。

假设有两个物体由同一个相机拍摄,在现实世界中其中一个物体是另一个物体亮度的两倍。 当您测量照片中两个物体的像素亮度时,较亮物体的像素值将不会是较暗物体的两倍。 在不估计相机响应函数Camera Response Function(CRF)的情况下,我们将无法将图像合并到一个HDR图像中。

如果我们知道每个图像的曝光时间,则可以从图像估计 CRF。

使用 OpenCV 的 CalibrateDebevec 或者 CalibrateRobertson 就可以用 2 行代码找到 CRF。本篇使用 CalibrateDebevec。

// Obtain Camera Response Function (CRF)  提取相机响应函数
cout << "Calculating Camera Response Function (CRF) ... " << endl;
Mat responseDebevec;
Ptr<CalibrateDebevec> calibrateDebevec = createCalibrateDebevec();
calibrateDebevec->process(images, responseDebevec, times);

4.合并图像

一旦 CRF 评估结束,可以曝光图像合并成一个HDR图像。
分别使用了两种方法合成HDR图像。

  • Debevec方法合并图像
  • 输入图片、曝光时间、响应函数
// Debevec方法合并图像
Mat Merging_Debevec(vector<Mat>& images, vector<float>& times, Mat& responseDebevec)    
{
   
    cout << "Merging images into one HDR image ... " << endl;
    Mat hdrDebevec;
    Ptr<MergeDebevec> mergeDebevec = createMergeDebevec();
    mergeDebevec->process(images, hdrDebevec, times, responseDebevec);
    // Save HDR image.    保存图像
    imwrite("./pic/welding/hdrDebevec.hdr", hdrDebevec);
    cout << "saved hdrDebevec.hdr " << endl;
    return hdrDebevec;
}

// Robertson方法合并图像
Mat Merging_Robertson(vector<Mat>& images, vector<float>& times, Mat& responseDebevec)     
{
   
    Mat hdrRobertson;
    Ptr<MergeRobertson> mergeRobertson = createMergeRobertson();
    mergeRobertson->process(images, hdrRobertson, times, responseDebevec);
    // Save HDR image.    保存图像
    imwrite("./pic/welding/hdrRobertson.hdr", hdrRobertson);
    cout << "saved hdrRobertson.hdr " << endl;
    return hdrRobertson;
}

保存的 HDR 图像可以在 Photoshop 中加载并进行色调映射。

5.色调映射

将高动态范围(HDR)图像转换为 8 位单通道图像的过程称为色调映射。这个过程的同时还需要保留尽可能多的细节。

有几种色调映射算法,OpenCV 实现了其中的四个。

没有一个绝对正确的方法来做色调映射。 通常,我们希望在色调映射图像中看到比任何一个曝光图像更多的细节。 有时色调映射的目标是产生逼真的图像,而且往往是产生超现实图像的目标。 在 OpenCV 中实现的算法倾向于产生现实的并不那么生动的结果。

来看看各种选项。 以下列出了不同色调映射算法的一些常见参数。

  1. 伽马gamma:该参数通过应用伽马校正来压缩动态范围。 当伽马等于 1 时,不应用修正。 小于 1 的伽玛会使图像变暗,而大于 1 的伽马会使图像变亮。
  2. 饱和度saturation:该参数用于增加或减少饱和度。 饱和度高时,色彩更丰富,更浓。 饱和度值接近零,使颜色逐渐消失为灰度。
  3. 对比度contrast:控制输出图像的对比度(即 log(maxPixelValue/minPixelValue))。

(1)Drago 色调映射

Drago 色调映射的参数如下

createTonemapDrago(
		float gamma = 1.0f,
		float saturation = 1.0f,
		float bias = 0.85f
)

bias 是 [0, 1] 范围内偏差函数的值。 从 0.7 到 0.9 的值通常效果较好。 默认值是 0.85。

下面是使用方式。
最后的结果乘以 3 只是因为它给出了最令人满意的结果。

// Drago算法色调映射
Mat Tonemap_DDrago(Mat& hdr)
{
   
    cout << "Tonemaping using Drago's method ... " << endl;
    Mat ldrDDrago;
    Ptr<TonemapDrago> tonemapDrago = createTonemapDrago(1.0, 0.7);
    tonemapDrago->process(hdr, ldrDDrago);
    ldrDDrago = 3 * ldrDDrago;
    imwrite("./pic/welding/ldrD-Drago.jpg", ldrDDrago * 255);
    cout << "saved ldr-Drago.jpg" << endl;
    return ldrDDrago;
}

(2)Durand 色调映射

该算法需付费,这里没有使用。

算法参数及使用在参考文章有。

(3)Reinhard 色调映射

Reinhard 色调映射的参数如下所示。

createTonemapReinhard(
		float gamma = 1.0f,
		float intensity = 0.0f,
		float light_adapt = 1.0f,
		float color_adapt = 0.0f
)

参数说明:

  1. intensity 参数应在 [-8, 8] 范围内。 更高的亮度值会产生更明亮的结果。
  2. light_adapt 控制灯光,范围为 [0, 1]。 值 1 表示仅基于像素值的自适应,而值 0 表示全局自适应。 中间值可以用于两者的加权组合。
  3. 参数 color_adapt 控制色彩,范围为 [0, 1]。 如果值被设置为 1,则通道被独立处理,如果该值被设置为 0,则每个通道的适应级别相同。中间值可以用于两者的加权组合。

下面是使用方式。

// Reinhard算法色调映射
Mat Tonemap_DReinhard(Mat&
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值