數(shù)據(jù)準備
首先,我們準備三張不同曝光的圖像,如下圖所示。
![]() 曝光時間0.05
|
![]() 曝光時間0.0125
|
![]() 曝光時間0.003125
|
|---|
利用幾個helper函數(shù)來從文件夾里讀取圖像和圖像的曝光時間。
import PIL.ExifTags
from PIL import Image
import cv2
import numpy as np
from libtiff import TIFF
from os import listdir
from os.path import isfile, isdir, join
#讀取文件夾下文件
def ListFiles(FilePath):
onlyfiles = [f for f in listdir(FilePath) if isfile(join(FilePath, f))]
return onlyfiles
#獲得圖像文件屬性
def get_exif(fn):
img = Image.open(fn)
exif = {PIL.ExifTags.TAGS[k]: v
for k, v in img._getexif().items()
if k in PIL.ExifTags.TAGS
}
return exif
#獲得圖像曝光時間
def get_exposure_time(fn):
exif = get_exif(fn)
exposure_time = exif.get('ExposureTime')
return exposure_time[0]/exposure_time[1]
#獲取圖像曝光時間序列和圖像
def getImageStackAndExpos(folderPath):
files = ListFiles(folderPath)
exposTimes = []
imageStack = []
for file in files:
filePath = join(folderPath,file)
exposTime = get_exposure_time(filePath)
currImage = cv2.imread(filePath)
exposTimes.append(exposTime)
imageStack.append(currImage)
#根據(jù)曝光時間長短,對圖像序列和曝光時間序列重新排序
index = sorted(range(len(exposTimes)), key=lambda k: exposTimes[k])
exposTimes = [exposTimes[i] for i in index]
imageStack = [imageStack[i] for i in index]
return exposTimes,imageStack
預處理
由于上面的三張圖像在拍攝的時候存在一定的抖動和位移情況,可以用SIFT算法對其配準Python進行SIFT圖像對準。在配準的時候,首先需要找到一張曝光最好的照片作為基準照片,下面的一個函數(shù)計算照片中曝光不足和曝光過量的像素個數(shù),把曝光不足和曝光過量像素最少的圖像作為參考圖像。
def getSaturNum(img):
gray_image = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
underExpos=np.count_nonzero(gray_image==0)
overExpos = np.count_nonzero(gray_image==255)
return underExpos + overExpos
def getRefImage(imgStack):
saturNum = imgStack[0].shape[0]*imgStack[0].shape[1]
for imgIndex in np.arange(len(imgStack)):
curImg = imgStack[imgIndex]
curSaturNum = getSaturNum(curImg)
print(curSaturNum)
if curSaturNum <= saturNum:
saturNum = curSaturNum
refIndex = imgIndex
return refIndex
在獲得參考圖像以后,使用Python進行SIFT圖像對準中提供的siftImageAlignment進行配準,并且返回已經(jīng)對其的圖像序列。
def siftAlignment(imgStack,refIndex):
refImg = imgStack[refIndex]
outStack = []
for index in np.arange(len(imgStack)):
if index == refIndex:
outStack.append(refImg)
else:
currImg = imgStack[index]
outImg,_,_ = siftImageAlignment(refImg,currImg)
outStack.append(outImg)
return outStack
HDR合成
為了合成HDR圖像,首先要擬合相機響應函數(shù)(Camera Response Function,CRF),關于擬合CRF的算法,后續(xù)博客中將詳細介紹,這里,我們先關注Opencv-Python的實現(xiàn)。
import numpy as np
import cv2
import Utility #Utility為前面函數(shù)所在的模塊
exposTimes,images = Utility.getImageStackAndExpos('stack_alignment')
refImgIndex= Utility.getRefImage(images)
images = Utility.siftAlignment(images,refImgIndex)
exposTimes = np.array(exposTimes,dtype=np.float32) #需要轉(zhuǎn)化為numpy浮點數(shù)組
calibrateDebevec = cv2.createCalibrateDebevec(samples=120,random=True)
###采樣點數(shù)120個,采樣方式為隨機,一般而言,采用點數(shù)越多,采樣方式越隨機,最后的CRF曲線會越加平滑
responseDebevec = calibrateDebevec.process(images, exposTimes) #獲得CRF
mergeDebevec = cv2.createMergeDebevec()
hdrDebevec = mergeDebevec.process(images, exposTimes, responseDebevec) #
# Save HDR image.
cv2.imwrite("hdrDebevec.hdr", hdrDebevec)


