python?使用OpenCV進(jìn)行曝光融合
1 什么是曝光融合
曝光融合是一種將使用不同曝光設(shè)置拍攝的圖像合成為一張看起來像色調(diào)映射的高動(dòng)態(tài)范圍(HDR)圖像的圖像的方法。當(dāng)我們使用相機(jī)拍攝照片時(shí),每個(gè)顏色通道只有8位來表示場景的亮度。然而,我們周圍世界的亮度理論上可以從0(黑色)到幾乎無限(直視太陽)。因此,傻瓜相機(jī)或移動(dòng)相機(jī)根據(jù)場景決定曝光設(shè)置,以便使用相機(jī)的動(dòng)態(tài)范圍(0-255值)來表示圖像中最有趣的部分。例如,在許多相機(jī)中,使用面部檢測來查找面部并設(shè)置曝光,使得面部看起來很好。這引出了一個(gè)問題-我們可以在不同的曝光設(shè)置下拍攝多張照片并拍攝更大范圍的場景亮度嗎?答案是肯定的。傳統(tǒng)上使用HDR成像然后進(jìn)行色調(diào)映射的方式。具體見上篇文章:python使用OpenCV獲取高動(dòng)態(tài)范圍成像HDR
HDR成像要求我們知道精確的曝光時(shí)間。HDR圖像本身看起來很暗,看起來不太漂亮。DR圖像中的最小強(qiáng)度為0,但理論上沒有最大值。所以我們需要將其值映射到0到255之間,以便我們可以顯示它。將HDR圖像映射到常規(guī)的每通道8位彩色圖像的過程稱為色調(diào)映射。如您所見,組裝HDR圖像和色調(diào)映射有點(diǎn)麻煩。我們不能不使用HDR就使用多個(gè)圖像創(chuàng)建色調(diào)映射圖像。結(jié)果證明我們可以用曝光融合來實(shí)現(xiàn)。
2 曝光融合的原理
應(yīng)用曝光融合的步驟如下所述:
- 使用不同曝光拍攝多張圖像

首先,我們需要在不移動(dòng)相機(jī)的情況下捕獲同一場景的一系列圖像。如上所示,序列中的圖像具有不同的曝光。這是通過改變相機(jī)的快門速度來實(shí)現(xiàn)的。通常,我們選擇一些曝光不足的圖像,一些曝光過度的圖像和一個(gè)正確曝光的圖像。
在“正確”曝光的圖像中,選擇快門速度(由相機(jī)或攝影師自動(dòng)選擇),以便每通道8位動(dòng)態(tài)范圍用于表示圖像中最有趣的部分。太暗的區(qū)域被剪切為0,而太亮的區(qū)域被飽和到255。
在曝光不足的圖像中,快門速度很快,圖像很暗。因此,圖像的8位用于捕獲亮區(qū)域,而暗區(qū)域被剪切為0。在曝光過度的圖像中,快門速度較慢,因此傳感器捕獲的光線更多,因此圖像更亮。傳感器的8位用于捕獲暗區(qū)域的強(qiáng)度,而亮區(qū)域飽和到255的值。大多數(shù)單反相機(jī)都有一個(gè)稱為自動(dòng)曝光包圍(AEB)的功能,只需按一下按鈕,我們就可以在不同曝光下拍攝多張照片。當(dāng)我們?cè)趇Phone中使用HDR模式時(shí),它需要三張照片(安卓可以下載超級(jí)相機(jī)這個(gè)軟件)。
圖像對(duì)齊:
即使使用三腳架獲取序列中的圖像也需要對(duì)齊,因?yàn)榧词馆^小的相機(jī)抖動(dòng)也會(huì)降低最終圖像的質(zhì)量。OpenCV提供了一種使用對(duì)齊這些圖像的簡便方法AlignMTB。該算法將所有圖像轉(zhuǎn)換為中值閾值位圖(MTB)。通過將值1分配給比中值亮度更亮的像素來計(jì)算圖像的MTB,否則為0。MTB 對(duì)曝光時(shí)間不變。因此,可以對(duì)準(zhǔn)MTB而無需我們指定曝光時(shí)間。
圖像融合:
具有不同曝光的圖像捕獲不同范圍的場景亮度。根據(jù)Tom Mertens,Jan Kautz和Frank Van Reeth 題為Exposure Fusion的論文。論文見:曝光融合通過僅保留多重曝光圖像序列中的“最佳”部分來計(jì)算所需圖像。
作者提出了三個(gè)質(zhì)量指標(biāo):
1曝光良好:如果序列中的圖像中的像素接近零或接近255,則不應(yīng)使用該圖像來查找最終像素值。其值接近中間強(qiáng)度(128)的像素是比較合適的。
2對(duì)比度:高對(duì)比度通常意味著高品質(zhì)。因此,對(duì)于該像素,給予特定像素的對(duì)比度值高的圖像具有更高的權(quán)重。
3飽和度:類似地,更飽和的顏色更少被淘汰并且代表更高質(zhì)量的像素。因此,特定像素的飽和度高的圖像被賦予該像素的更高權(quán)重。
三種質(zhì)量度量用于創(chuàng)建權(quán)重圖
該權(quán)重圖表示
, 圖像在位置處的像素的最終強(qiáng)度中的貢獻(xiàn)
, 對(duì)權(quán)重圖
,進(jìn)行歸一化,使得對(duì)于任何像素
所以所有圖像的貢獻(xiàn)總計(jì)為1。
結(jié)合權(quán)重圖使用以下等式組合圖像是很有效的:

其中,
,是原始圖像,
, 是輸出圖像。問題在于,由于像素是從不同曝光的圖像中拍攝的,因此
使用上述等式獲得的輸出圖像將顯示許多裂縫。該論文的作者使用拉普拉斯金字塔來混合圖像。我們將在以后的文章中介紹這項(xiàng)技術(shù)的細(xì)節(jié)。
幸運(yùn)的是使用OpenCV,這種圖像曝光融合合并只是使用MergeMertens該類的兩行代碼。請(qǐng)注意,這個(gè)名字取決于Exposure Fusion論文的第一作者Tom Mertens 。
3 代碼與結(jié)果
代碼地址:
C++:
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>
#include <fstream>
using namespace cv;
using namespace std;
// Read Images
void readImages(vector<Mat> &images)
{
int numImages = 16;
static const char* filenames[] =
{
"image/memorial0061.jpg",
"image/memorial0062.jpg",
"image/memorial0063.jpg",
"image/memorial0064.jpg",
"image/memorial0065.jpg",
"image/memorial0066.jpg",
"image/memorial0067.jpg",
"image/memorial0068.jpg",
"image/memorial0069.jpg",
"image/memorial0070.jpg",
"image/memorial0071.jpg",
"image/memorial0072.jpg",
"image/memorial0073.jpg",
"image/memorial0074.jpg",
"image/memorial0075.jpg",
"image/memorial0076.jpg"
};
//讀圖
for (int i = 0; i < numImages; i++)
{
Mat im = imread(filenames[i]);
images.push_back(im);
}
}
int main()
{
// Read images 讀取圖像
cout << "Reading images ... " << endl;
vector<Mat> images;
//是否圖像映射
bool needsAlignment = true;
// Read example images 讀取例子圖像
readImages(images);
//needsAlignment = false;
// Align input images
if (needsAlignment)
{
cout << "Aligning images ... " << endl;
Ptr<AlignMTB> alignMTB = createAlignMTB();
alignMTB->process(images, images);
}
else
{
cout << "Skipping alignment ... " << endl;
}
// Merge using Exposure Fusion 圖像融合
cout << "Merging using Exposure Fusion ... " << endl;
Mat exposureFusion;
Ptr<MergeMertens> mergeMertens = createMergeMertens();
mergeMertens->process(images, exposureFusion);
// Save output image 圖像保存
cout << "Saving output ... exposure-fusion.jpg" << endl;
imwrite("exposure-fusion.jpg", exposureFusion * 255);
return 0;
}Python:
import cv2
import numpy as np
import sys
def readImagesAndTimes():
filenames = [
"image/memorial0061.jpg",
"image/memorial0062.jpg",
"image/memorial0063.jpg",
"image/memorial0064.jpg",
"image/memorial0065.jpg",
"image/memorial0066.jpg",
"image/memorial0067.jpg",
"image/memorial0068.jpg",
"image/memorial0069.jpg",
"image/memorial0070.jpg",
"image/memorial0071.jpg",
"image/memorial0072.jpg",
"image/memorial0073.jpg",
"image/memorial0074.jpg",
"image/memorial0075.jpg",
"image/memorial0076.jpg"
]
images = []
for filename in filenames:
im = cv2.imread(filename)
images.append(im)
return images
if __name__ == '__main__':
# Read images
print("Reading images ... ")
if len(sys.argv) > 1:
# Read images from the command line
images = []
for filename in sys.argv[1:]:
im = cv2.imread(filename)
images.append(im)
needsAlignment = False
else :
# Read example images
images = readImagesAndTimes()
needsAlignment = False
# Align input images
if needsAlignment:
print("Aligning images ... ")
alignMTB = cv2.createAlignMTB()
alignMTB.process(images, images)
else :
print("Skipping alignment ... ")
# Merge using Exposure Fusion
print("Merging using Exposure Fusion ... ");
mergeMertens = cv2.createMergeMertens()
exposureFusion = mergeMertens.process(images)
# Save output image
print("Saving output ... exposure-fusion.jpg")
cv2.imwrite("exposure-fusion.jpg", exposureFusion * 255)本文第一張圖獲得的不同曝光的圖像,通過這種方法所得結(jié)果如下:

在輸入圖像中,我們可以獲得過度曝光圖像中光線昏暗區(qū)域和曝光不足圖像中明亮區(qū)域的細(xì)節(jié)。但是,在合并的輸出圖像中,像素在圖像的每個(gè)部分都具有明亮的細(xì)節(jié)。我們還可以在之前的帖子中看到我們用于HDR成像的圖像的這種效果。用于產(chǎn)生最終輸出的四個(gè)圖像顯示在左側(cè),輸出圖像顯示在右側(cè)。結(jié)果如下圖所示:

正如您在本文中所看到的,Exposure Fusion允許我們?cè)诓幻鞔_計(jì)算HDR圖像的情況下實(shí)現(xiàn)類似于HDR + Tonemapping的效果。因此,我們不需要知道每張圖像的曝光時(shí)間,但我們能夠獲得非常合理的結(jié)果。那么,為什么要費(fèi)心去做HDR呢?好吧,在很多情況下,Exposure Fusion產(chǎn)生的輸出可能不符合您的喜好。沒有旋鈕可以調(diào)整以使其變得不同或更好。另一方面,HDR圖像捕獲場景的原始亮度。如果您不喜歡色調(diào)映射的HDR圖像,請(qǐng)嘗試使用不同的色調(diào)映射算法。總之,Exposure Fusion代表了一種權(quán)衡。在速度和不太嚴(yán)格的要求下使得算法更加靈活(例如,不需要暴露時(shí)間)
到此這篇關(guān)于python 使用OpenCV進(jìn)行曝光融合的文章就介紹到這了,更多相關(guān)OpenCV曝光融合內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Python?OpenCV超詳細(xì)講解調(diào)整大小與圖像操作的實(shí)現(xiàn)
- Python?OpenCV超詳細(xì)講解讀取圖像視頻和網(wǎng)絡(luò)攝像頭
- Python中使用Opencv開發(fā)停車位計(jì)數(shù)器功能
- 關(guān)于python3?opencv?圖像二值化的問題(cv2.adaptiveThreshold函數(shù))
- Python?OpenCV實(shí)現(xiàn)圖形檢測示例詳解
- Python?OpenCV實(shí)現(xiàn)3種濾鏡效果實(shí)例
- python?OpenCV?圖像通道數(shù)判斷
- 巧妙使用python?opencv庫玩轉(zhuǎn)視頻幀率
- python+opencv實(shí)現(xiàn)堆疊圖片
相關(guān)文章
使用python實(shí)現(xiàn)自動(dòng)化控制電腦版微信
這篇文章主要為大家詳細(xì)介紹了如何通過Python去調(diào)用Windows API實(shí)現(xiàn)模擬人工操作的方式去實(shí)現(xiàn)控制微信電腦版,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-10-10
Python獲取本機(jī)IP/MAC多網(wǎng)卡方法示例
這篇文章主要為大家介紹了Python獲取本機(jī)IP/MAC多網(wǎng)卡方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
Python打印詳細(xì)報(bào)錯(cuò)日志logging問題
這篇文章主要介紹了Python打印詳細(xì)報(bào)錯(cuò)日志logging問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
error?conda:ProxyError:Conda?cannot?proceed?due?to?an?
這篇文章主要為大家介紹了error conda:ProxyError:Conda cannot proceed due to an error in your proxy configuration解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
python Django 創(chuàng)建應(yīng)用過程圖示詳解
這篇文章主要介紹了python Django 創(chuàng)建應(yīng)用過程圖示詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
利用Pandas和Numpy按時(shí)間戳將數(shù)據(jù)以Groupby方式分組
這篇文章主要介紹了利用Pandas和Numpy按時(shí)間戳將數(shù)據(jù)以Groupby方式分組,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07

