數(shù)據(jù)準(zhǔn)備
首先踩蔚,我們準(zhǔn)備三張不同曝光的圖像,如下圖所示。
曝光時間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
預(yù)處理
由于上面的三張圖像在拍攝的時候存在一定的抖動和位移情況,可以用SIFT算法對其配準(zhǔn)Python進(jìn)行SIFT圖像對準(zhǔn)解虱。在配準(zhǔn)的時候攘须,首先需要找到一張曝光最好的照片作為基準(zhǔn)照片,下面的一個函數(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進(jìn)行SIFT圖像對準(zhǔn)中提供的siftImageAlignment進(jìn)行配準(zhǔn)悍汛,并且返回已經(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圖像,首先要擬合相機(jī)響應(yīng)函數(shù)(Camera Response Function员凝,CRF),關(guān)于擬合CRF的算法奋献,后續(xù)博客中將詳細(xì)介紹健霹,這里,我們先關(guān)注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個糖埋,采樣方式為隨機(jī),一般而言窃这,采用點數(shù)越多瞳别,采樣方式越隨機(jī),最后的CRF曲線會越加平滑
responseDebevec = calibrateDebevec.process(images, exposTimes) #獲得CRF
mergeDebevec = cv2.createMergeDebevec()
hdrDebevec = mergeDebevec.process(images, exposTimes, responseDebevec) #
# Save HDR image.
cv2.imwrite("hdrDebevec.hdr", hdrDebevec)