# VFX Project1 ## Members #### R10922017 許博翔 #### R10944007 曾宏鈞 ## 實作的功能 1. MTB Algorithm [Bonus] 2. HDR reconstruction (Paul Debevec's method) 3. Tone-mapping [Bonus] ## Steps ### 1. 拍攝多個不同曝光時間的照片 <img src="https://i.imgur.com/EmQYKjm.png"/> 上圖的曝光速度由左至右由上到下分別為 [1/32, 1/16, 1/8, 1/4, 1/2, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] ### 2. Image Alignment -- [MTB]: #### Functions - getExpShift: 遞迴方式比較src, dst兩張的位移 - parameters: - img1: 原始影像 - img2: 要校正的影像 - shiftBits: 縮小的層級,每遞迴一次-1 - return: 總共計算完的位移 - ImageShrink2: 影片縮小兩倍 - parameters: img - return: 縮小1/2的影像 - ComputeBitmaps: 去掉雜訊部分 - parameters: img, threshold(defalut:2) - return: - threshold_bitmap: 濾掉 < median的pixel - exclusion_bitmap: 保留接近median的pixel #### 內容 使用遞迴呼叫getExpShift的方式在影像不同大小的層級去計算位移(image pyramid的方法),參考 [MTB] p9的Overall Algorithm - 優點: 從較低resolution開始累積影像位移,執行速度比Brute-force快 - 缺點: 需要設定level參數,若影像曝光較低時縮小層級太多容易找不到,目前試最佳參數是4。 - 其他: - 每一張的光圈paper有提到建議一樣。 - 若圖片有rotate,重建後會模糊。 ### 3. Response curve recovery(Z->E) - Paul Debevec's Method #### Functions - 先將將影像縮小成10*10做取樣,丟進gsolve解Ax=b,由於A不是方陣,所以我們不使用SVD而是scipy的least-squares函式-lstsq,g即為x[:256]、lE即為x[256:] - Weight functions - Binomial: 利用0~255之間常態分布的pdf作為weight function - Distance: <img src="https://i.imgur.com/QS1SxpB.png" width="70%"/> - Uniform: 不加任何權重 - 重建 <img src="https://i.imgur.com/It8quDh.png" width="70%"/> 利用np進行array運算,可以大幅加速,**比單純使用for loop快12倍**。 ```python= def construct_radiance_map(images, B, gs, w): w_map = [w(x) for x in range(256)] shape = images[0].shape images = np.array(images) weights = np.vectorize(lambda x: w_map[x])(images) w_t = np.sum(weights, axis=0) def get_g(x): a = np.zeros(3) a[0] = gs[0][x[0]] a[1] = gs[1][x[1]] a[2] = gs[2][x[2]] return a lnE_raw = np.apply_along_axis( get_g, 3, images) - np.array([np.ones(shape) * t for t in B]) sum = np.sum(weights * lnE_raw, axis=0) return sum / w_t ``` ### 4. Tone Mapping (optional) - 利用Photoshop進行Tone Mapping <span style="display: flex; flex-direction: row; justify-content: space-around"> <img src="https://i.imgur.com/nkQpE6T.jpg" style="width: 45%; object-fit: contain;"/> <img src="https://i.imgur.com/h4pSMnm.jpg" style="width: 45%; object-fit: contain;"/> </span> ## Result | Response Curve | Radiance Map | Tone-mapped Result | |:-----------------------------------------------------------------:|:-----------------------------------------------------------------:|:-----------------------------------------------------------------:| | <img src="https://i.imgur.com/5IjDACJ.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/tQftwc0.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/2I7q8YM.jpg" style="width: 600px"/> | | <img src="https://i.imgur.com/qfgwnzZ.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/uEBHJoE.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/5UytFa2.jpg" style="width: 600px"/> | | <img src="https://i.imgur.com/UpsisIc.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/g09vbKB.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/601VUHT.jpg" style="width: 600px"/> | | <img src="https://i.imgur.com/M7azpIj.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/6rp2Zy9.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/yFVcALq.jpg" style="width: 600px"/> | | <img src="https://i.imgur.com/QHl1M8j.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/n6W9E8v.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/AWi5GEQ.jpg" style="width: 600px"/> | | <img src="https://i.imgur.com/Z3HZhop.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/vr0uF0V.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/Uun9GbC.jpg" style="width: 600px"/> | | <img src="https://i.imgur.com/mpERyP2.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/I5wHY1t.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/11rDtUb.jpg" style="width: 600px"/> | | <img src="https://i.imgur.com/a07fVMq.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/dPYphqX.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/YdioQ6P.jpg" style="width: 600px"/> | | <img src="https://i.imgur.com/3LlgPZy.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/ru0CpBf.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/wGteHm8.jpg" style="width: 600px"/> | ### Comparison | Original | Result | |:-----------------------------------------------------------------:|:-----------------------------------------------------------------:| | <img src="https://i.imgur.com/gXutCrP.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/ABLtScz.jpg" style="width: 600px"/> | | <img src="https://i.imgur.com/5I5Cftl.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/pLae7kL.jpg" style="width: 600px"/> | | <img src="https://i.imgur.com/tgASqFx.jpg" style="width: 600px"/> | <img src="https://i.imgur.com/iPTpaBr.jpg" style="width: 600px"/> | 上圖可以觀察到第一列社科院圖書館,使用hdr重建後,原本(圖左)原先影像過度曝光,使用調整後的camera response cureve可以使原本過曝的細節被呈現出來。 第二列公園涼亭的部分可以看到,這張原始影像左圖花圃較暗,多盞路燈也使得後方溜滑梯整體過量,然而使用我們的hdr方法可以呈現較接近原始的色澤 第三列拍攝防火巷,原圖左邊牆面由於後方有光線直接照射產生過曝,若使用較快的快門拍攝又會導致遠方巷尾的細節過暗,使用我們的HDR方法可以使牆面色澤較自然,同時也保留暗處的細節部分。 ## 討論 ### MTB 的 level 我們在跑mtb.py的時候發現,當level設為7(縮小7個層級)的時候,較少曝光亮(暗的)的圖片位移量會超過100個pixel,與其他張相差非常多,然而,當我們把level調小的時候每一張的位移量不會相差多,由於我們是有使用腳架拍攝,因此我們假設較暗的圖再找相似的時候參考點較少所以比對的時候容易發生位移過大導致最後產生的圖非常模糊。 ### Reconstruction 產生的 noise 我們發現當使用上述的distance weight function時,會在一些暗處出現藍色的雜訊(如左圖門上),推測是因為這種weight function會有等於零的weight出現,造成在計算radiance map時會有除以零而導致output爆掉的情況,因此我們最後採用binomial的方式(如右圖),來避免這種狀況發生。 <span style="display: flex; flex-direction: row; justify-content: space-around"> <img src="https://i.imgur.com/H3xhFlS.jpg" style="width: 45%"/> <img src="https://i.imgur.com/5eTade5.jpg" style="width: 45%"/> </span> ## 參考資料 - https://github.com/tsai-you-shin/HDR - https://ssarcandy.tw/2017/04/16/High-Dynamic-Range-Imaging/ - https://github.com/henlium/HDR/blob/master/align.py - https://github.com/qhan1028/HDR-Imaging/blob/beb4e5f713702302406fadd9ed6635b419ede035/hdr-note.ipynb [MTB]:http://www.anyhere.com/gward/papers/jgtpap2.pdf