nbswords
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # Handheld Mobile Photography in Very Low Light ###### tags: `paper notes` `deep learning` > Inspired from EE367 / CS448I: Computational Imaging # Intro - 這是一篇針對低光情況下去設計的手機攝影演算法,可說是純 CV 在低光攝影上的巔峰之作,來自 [Marc Levoy](https://www.techbang.com/posts/80282-marc-levoy-a-man-who-used-algorithms-to-change-the-direction-of-android-phone-photography) 的團隊 - 在此之前過去的方法通常在低光情況下會無法充分曝光以及造成顏色上的誤差 - 比如(a)的圖片亮度太低而(b)的圖片臉部有chroma noise (color noise) 使得臉部偏橘且有噪點 - 這邊的低光定義是小於 0.3 lux (勒克斯),1勒克斯=1流明/平方公尺 - 可參考 [Lux wiki](https://zh.m.wikipedia.org/zh-tw/%E7%85%A7%E5%BA%A6),辦公室的亮度通常是 300 lux ![](https://i.imgur.com/Qr3YaEP.jpg) - 他們對於噪點以及照片亮度的解法是讓手機根據目前的 scene motion 來自動調整曝光時間,若手機近乎靜止,則曝光時間就會變長,而反之則減少曝光時間減少 motion blur - 曝光時間從 0.14s 延長到了 0.33s,並從原本只有6個 frames 變為13個 frames - 至於照片的亮度則是訓練了一個可以預測白平衡的模型來針對低光場景重現現實顏色 - 除此之外也利用 local tone mapping 來增加陰影處的亮度 - 當然,這是在不影響整體對比度以及整體亮度的情況下來增加 這篇論文所解決的問題與攝影訊噪脫不了關係,所以我們先來談談這件事情吧。 ## 攝影訊噪 與攝影相關的訊噪有固定噪點的高感光度與長時間曝光訊噪,另外還有隨機噪點以及帶狀噪點,這邊我們主要討論高感光與長時間曝光訊噪 ![](https://i.imgur.com/Ezh4bU8.png) ### 高感光度訊噪 - 高感光度訊噪可分為明度訊噪(Luminance Noise)及色彩訊噪(Chroma Noise),明度訊噪通常是影像中的灰階雜質,令影像看上來不夠平滑。而色彩訊噪則是影像中純色部份出現雜色的情況,通常是洋紅色或綠色 - 明度訊噪 - 這種訊噪是沒有顏色且尺寸會根據感測器的大小、感測器中pixel的大小或是ISO而變,在高 ISO 或是長時間曝光下會被放大 - 當我們在提高相機的ISO的時候實際上是在提升感測器中每一個pixel的大小,這時若沒有控制好就會造成明度訊噪 ![](https://i.imgur.com/nBifJ7c.jpg) - 色彩訊噪 - 這種訊噪是色調與像素之間的斑點狀波動,一樣與 ISO 開太高有關,主因是有部分光線因金屬設備的反射跑進去鄰近的像素 - 相較於明度訊噪更為煩人且在圖片亮區或是暗區會特別明顯 ![](https://i.imgur.com/I2XRyZG.jpg) ### 長時間曝光噪點 - 長時間曝光會使得感光元件溫度上升,影像會於固定位置出現 hot pixels(熱噪點) - 基本上,當曝光時間超過數秒時,熱噪點才會出現;要是曝光時間愈長,熱噪點就愈明顯。由於在相近的拍攝環境下,熱噪點的出現位置是相同的,因此這種訊噪較容易處理。 ![](https://i.imgur.com/0bDGJr2.jpg) ### 如何解決訊噪 1. 影響相機訊噪表現的重要因素之一,就是相機片幅(感光元件)的尺寸 - 為減少高感光度所產生的影像訊噪,感光元件所接收的訊號必須盡量「純淨」,而提升感光點(Photosite)的訊噪比(Signal-to-noise ratio, SNR)的方法,就是使用較大面積的感光點。因為愈大的感光點,能夠接收愈多的光子(Photon),當進行訊號放大(Amplification)時,感光點仍能保持較高的訊噪比。 - 在低光環境下,感光點只能接收有限的光量,面積較細小的感光點的訊噪比會較低,影像的訊噪亦較明顯。 - 除感光點大小影響影像訊噪外,感光點的排列密度亦會影響影像的訊噪多寡。當感光點吸收光線時、感光元件通過電流後會產生熱力,這些熱力會增加訊噪的產生,要是感光元件上的感光點排列密集的話,散熱能力相對地會較低,影像便有較大機會產生訊噪。 ![](https://i.imgur.com/HTUcWCy.jpg) 2. 減少色彩訊噪 - 可以透過尋找這些相較於周圍的像素,其數值較為不正常的點來定位出色彩訊噪點的位置,然後對其做 decolorizing 來解決 - 但是這樣的方法只是把色彩訊噪轉為明度訊噪,噪點仍然在圖片上 - 另外需要注意的是如果做過頭就會導致圖片的色彩飽和度太低,所以是在照片色彩飽和度與色彩訊噪之間做 trade-off ![](https://i.imgur.com/dhkfyax.jpg) 3. 減少明度訊噪 - 常見的方法是對像素做平均然後用 filter 做平滑化,在照片細節與明度訊噪之間做 trade-off - 做過頭的話會讓圖片看起來像假的 ![](https://i.imgur.com/byuy2i0.jpg) ## Challenges of Low Light photographs - Devices - 手機的鏡頭孔徑和感測器小很多,進光量有絕對上的劣勢 ![](https://i.imgur.com/tGBWX3O.jpg) - 除此之外手機通常是用手拿著,會有手晃的問題,而移動的情況下做長曝光就會造成嚴重的 motion blur ![](https://i.imgur.com/u7oeZ9n.jpg) - 打光? - 閃光燈通常會產生出很醜的照片... ![](https://i.imgur.com/uDNRe1r.jpg) ### How to solve? 最簡單的方式就是提升 SNR,而方式通常是以下四種擇一 - 增加相機孔徑 - 延長曝光時間 - 增加光源,包含閃光燈 - 在圖片後處理中用演算法做降噪 但這些方法從手機的情境看來都有不可行的點 - 增加相機孔徑會讓手機更重更貴,手感很差 - 延長曝光時間會增加 motion blur 的可能,尤其大家通常是拿著手機拍而不是腳架 - 用閃光燈拍起來又會有過度曝光以及照片整體亮度極度不平衡的問題,拍起來的結果通常很難看 - 降噪演算法則是用照片的細節去和訊噪去做交換,當訊噪很嚴重的時候會讓照片變得很難看 結論就是,**僅僅提升 SNR 並沒有辦法解決低光攝影所遇上的挑戰。** ### 過去如何解決? 1. [連拍(burst imaging)](https://zh.wikipedia.org/zh-tw/%E9%80%A3%E6%8B%8D): 連拍好幾張圖片,融合這些圖片然後做 denoising, white balancing, tone mapping 等後處理,後來延伸出的應用就是讓人類去選擇哪張更好 - Android: 最佳鏡頭 - Iphone: Live photo 2. End2End CNN: 訓練 CNN 來幫你做所有的圖片調整 - 需大量計算資源 - 模型調整好之後就不能再微調成像結果 (end-to-end) 實際上他們在 2016 年就發過一篇[能在 0.7 Lux 做低光攝影的 burst imaging 方法](https://static.googleusercontent.com/media/hdrplusdata.org/zh-TW//hdrplus.pdf),而他們認為這種方法比 CNN 更好,所以這篇就繼續基於 burst imaging 擴展去解決 noise 與 motion blur 的問題 - 最右邊那張是當時的成果圖 ![](https://i.imgur.com/GPMGMSZ.jpg) - conventional vs no merge vs merge ![](https://i.imgur.com/Z0J2KMf.jpg) - live viewfinder 所找到的低解析度預覽圖指的就是照相時呈現在大家手機上面的那個圖片 ![](https://i.imgur.com/PM2Hy62.jpg) # Overviews 整個系統由 1.) motion metering 2.) motion-robust merge 3.) auto white balance for low light 4.) Specialized tone mapping 所組成 ![](https://i.imgur.com/OEGnh46.jpg) ![](https://i.imgur.com/Ax8TPui.png) ## Motion metering 目的是基於對未來場景和相機移動的預測來調整曝光時間和ISO ![](https://i.imgur.com/Twvsxv7.png) ![](https://i.imgur.com/IfIKAwk.jpg) ### 過去的作法 - 以前的系統通常會有這三種限制 1. 在按下快門之後固定住這一個 burst 中的所有 frame 的 gain(ISO) 和曝光時間,方便 align 和 merge burst 2. 用一個 auto-exposure system (e.g., (Schulz et al. 2007)) 來根據場景亮度決定感測器的 target sensitivity (exposure time*gain) 3. 限制住 total capture time (6 seconds) - 但這種固定的做法很可能無法在每一種情境下都得到最好的 trade-off ### 面臨的挑戰 1. 如何有效率且準確的測量移動量,因為手機的移動改變得很快速 2. 在得到移動量之後,如何使用移動量來調整曝光時間和 gain(ISO) ### 如何預估移動量 (Flow magnitudes) 簡單來說,他們設計了一種能直接計算出光流場強度 (the magnitude of the optical flow field)的演算法,其計算是根據按下快門前的$N$ 個 successive pairs of frames 來得到 1. Taylor expansion of the brightness constancy constraint (Negahdaripour and Yu 1993): ![](https://i.imgur.com/uMusFbp.png) - **光流場**就是通過一個圖片序列,利用圖像序列中像素在時間域上的變化以及相鄰幀之間的相關性來找到上一幀跟當前幀之間存在的對應關係,最後把每張圖像中每個像素的運動速度和運動方向找出來 - 兩張圖片在同一個位置(pixel location)的變化量(the change in intensity) $\triangle I_t$ 等於那個位置的梯度向量 (spatial intensity gradient) $g$ 和動作向量 (motion vector) $v$ 的 inner product > 光流參考資料: [CS231m lecture 7](https://web.stanford.edu/class/cs231m/lectures/lecture-7-optical-flow.pdf)、[CMU 16-385 Brightness Constancy](https://www.cs.cmu.edu/~16385/s17/Slides/14.1_Brightness_Constancy.pdf)、[OpenCV tutorial Optical Flow](https://docs.opencv.org/3.4/d4/dee/tutorial_optical_flow.html) 2. Apply Cauchy-Schwartz inequality then rearranged to bound the magnitude of the motion vector ![](https://i.imgur.com/GVBxWlq.png) - 光流場強度的 lower bound 可由像素變化量除以 gradient 的 norm (長度) 得到,他們稱這個為 Bounded Flow,而這個 LK 方法其實就是在求解下圖的 $I_xu+I_yv+I_t=0$,其中三個 $I$ 都可以從圖中得到(梯度),至於 u 跟 v (移動速度)就要用解的 - 這個 lower bound 其實就是 optical flow magnitude ([Lucas-Kanade](https://zh.wikipedia.org/zh-tw/%E5%8D%A2%E5%8D%A1%E6%96%AF-%E5%8D%A1%E7%BA%B3%E5%BE%B7%E6%96%B9%E6%B3%95)) - 等號成立的時候代表移動方向和 gradient 平行(也就是移動方向跟 edge 垂直),反之的話就會有孔徑問題(The Aperture Problem)的特性,下圖就是孔徑問題的展示,當梯度變化為沿著 y 軸而移動卻是沿著 x 軸的時候就只能算出 y軸的速度 $v$ ![](https://i.imgur.com/7MjNVuv.png) - $I_x(3,3)=0$ 是因為 x 軸的數值都是 3,沒有梯度變化,$I_y(3,3)=1$ 是因為 y 軸變化幅度為 1,此時會發現我們只能算出 y 軸速度 v,無法算出 x 軸速度 u,這就是孔徑問題 - 順帶一提,LK 解決孔徑問題的方法是盡量去抓角點來判斷![](https://i.imgur.com/hadNVIR.png) > 參考資料:[经典光流算法Lucas-Kanade](https://blog.csdn.net/leviopku/article/details/121773298)、[CMU 16-385 Lucas-Kanade Optical Flow](http://www.cs.cmu.edu/~16385/s15/lectures/Lecture21.pdf) - 現在假設你已經抓到角點來判斷光流,而取的 window size = 5x5,且 window 中的每一個點都假設有同樣的移動,這樣就可以寫出 25 個算式 ![](https://i.imgur.com/r4RK7yM.png) - 把它寫成矩陣形式 ![](https://i.imgur.com/shHeM73.png) - 只要找一組 (u,v) 滿足 ![](https://i.imgur.com/Z8EFQV6.png) - 接下來就可以用[最小平方法](https://zh.wikipedia.org/wiki/%E6%9C%80%E5%B0%8F%E4%BA%8C%E4%B9%98%E6%B3%95)來求解,求出偏導數為0的點就是最佳解 ,下圖就是 LK 法的公式 ![](https://i.imgur.com/DmlYAKz.png) 3. The linearity of the signal enables the effcient modeling of pixel noise variance, where the variance is a linear function of the signal level (Nakamura 2016) ![](https://i.imgur.com/nLNlutq.png) - K=2.5,noise variance 是已知的 - 他們利用這個特性把 gradient $||g||$ 小於噪音標準差的區域中的動作掩蓋掉(masking out) - 這是因為在低光場景下會有非常多的 noise 去干擾光流估計所以需要去過濾掉這些 gradient 很小的區域 ![](https://i.imgur.com/S4MiF3g.png) Intermediate results of “motion metering” - (a) 輸入為一對 downsampled linear images with a known noise variance - (b) 用灰階值(white/black levels)和相對曝光度 來 normalize 圖片來算出光流,這張圖就是灰階圖中的 motion magnitude (white = 10 pixels of motion) - (c ) 由於 gradient 低的地方會過度估計移動量(光流),這邊用 noise mask 去過濾掉這些區域 - (d) 最後他們會 downsampling with outlier rejection,然後取每一個 bin 中的第90%的 motion (90th-percentile motion in each bin),輸出一張 16x12 的結果圖 ### Comparison of different optical flow algorithms - Dataset 是 MPI-Sintel opticalflow dataset - run time 是用 Intel Xeon E5-2690 v4 CPU 以 single-thread 跑出來的 - 他們展示了即使不使用 NN 也可以做得跟 NN 一樣好,而且他們的 bounded flow 還比較快 ![](https://i.imgur.com/pzCRguF.png) ### 如何根據移動量預測未來的移動 (future motion prediction ) 將每個算出來的 flow magnitude 做 center-weighted average,然後把這一串平均值丟入一個預測 motion profile 的機率模型。再用跑出來的結果來計算下 K 個 frames 中的最小移動量的上限 (upper bound of the minimum motion) - K 是用來讓合併的連拍圖片的 motion blur 低於某一個 threshold - Center-weighted 是常用的方法,這會讓場景中央的動作權重較高,中央以外的動作權重較低。這是因為人在看圖片的時候會比較關注於人臉是否模糊而非其他區域,因此偵測到人臉的時候人臉區域權重高會比較好,同理也可應用在使用者自己選取一個想拍的區域上的時候 - 換成數學的說法就是: Given motion samples $v_i=1,2,...,N$ before the shutter press, what is the min motion $v_{min}$ within the next K frame ? 為什麼想選出最小移動量的上限? - 因為他們可以透過這個值去抽出想要的 "reference frame",這個 frame 的 motion blur 理論上會是最小的,只要把這個 frame 當成整個 burst 中最 sharpest 的 frame 就可以針對他作 denoise 來解決來自搖晃或是場景造成的模糊 - [Hasinoff et al. 2016](http://graphics.stanford.edu/papers/hdrp/hasinoff-hdrplus-sigasia16-preprint.pdf)、[Lucky Imaging](https://en.wikipedia.org/wiki/Lucky_imaging) ![](https://i.imgur.com/mEaDjRK.jpg) 可能的作法: FIR Filter - 使用一個有限脈波響應濾波器(finite impulse response, FIR filter) 來預測 ![](https://i.imgur.com/QQFFKXQ.png) ![](https://i.imgur.com/OkWAHJ0.png) - 簡單來說,RNN - 缺點: 1.) not robust to outlier, but solvable 2.) 當 K 改變的時候,就要重 tune,失去彈性 - 什麼叫做失去彈性? K 變大的時候,最大的曝光時間就要變長,因為這樣才能增加從更大的 pool of frames 中抽出清晰(sharp)的 frame 的機會,但如果要因此而重 tune FIR filter 去 fit 的話就很不直覺 他們的作法: 基於一個 CDF 去預測出 $v_{min}$ ![](https://i.imgur.com/n2BUfGC.png) ``` # 快速複習 CDF 試驗: 連續擲一銅板三次 = {HHH, HHT, HTH, HTT, TTT, TTH, THT, THH}. X = 每個 outcome 正面的次數. P(0) = P(X = 0) = P({TTT}) = 1/8. P(1) = P(X = 1) = P({HTT, THT, TTH}) = 3/8. P(2) = P(X = 2) = P({HHT, HTH, THH}) = 3/8. P(3) = P(X = 3) = P({HHH}) = 1/8. X的累積分佈函數 F(x): 若 x < 0, F(x) = 0. 若 0 <= x < 1, F(x) = 1/8. 若 1 <= x < 2, F(x) = 1/2. 若 2 <= x < 3, F(x) = 7/8. 若 x >= 3, F(x) = 1. 如: F(-1) = 0, F(0) = 1/8, F(1) = 1/2, F(2) = 7/8, F(3) = F(4) = ... = 1. ``` - $P_{conf}$: degree of confidence - 算式的意思: $v_{min}$ 為 next K frames 中那個最小的 motion 的 upper bound 的機率是大於等於信心水準的 - 為了實際去 model 他,他們又假設所有的 future motion 服從同一個機率分布然後對這些按下快門前的樣本 fit 一個 three-cluster GMM (Gaussian Mixture Model),用 EM 演算法來算出結果 (fit 出來的結果就是對每個樣本給一個權重) - 可以再舉另一個例子,比如你今天從多個籃子裡抽球,然後把這件事情 model 成 GMM + EM 就會推論得到每顆球來自第 n 個籃子的機率是多少,同理可想成是在找出符合算式限制的 v_min 到底是多少 - 推導教學請見 [機器學習: EM 演算法(Expectation-Maximization Algorithm, EM)、高斯混合模型(Gaussian Mixture Model, GMM)和GMM-EM詳細推導](https://chih-sheng-huang821.medium.com/%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-em-%E6%BC%94%E7%AE%97%E6%B3%95-expectation-maximization-algorithm-em-%E9%AB%98%E6%96%AF%E6%B7%B7%E5%90%88%E6%A8%A1%E5%9E%8B-gaussian-mixture-model-gmm-%E5%92%8Cgmm-em%E8%A9%B3%E7%B4%B0%E6%8E%A8%E5%B0%8E-c6f634410483) 然後,再假設所有 $v_k$ 都是從 GMM 中獨立抽樣出來,就會變成 ![](https://i.imgur.com/8yTgN8R.png) - 這樣就可以[查表](https://zscoregeek.com/using-z-score-table/)(因為 v 是 1D GMM)去算出每一個 Gaussian cluster 的 Pr[v_min <= v_k] 是多少 - 同時,由於這是一個單調函數,他們可以用 binary search 去快速找出要找的 v_min,時間複雜度 [O(logN)](https://matthung0807.blogspot.com/2018/04/binary-search-ologn.html) 實驗結果 - N=10, K=4 - 三個模型: averaging of 5 motion samples, FIR, GMM ![](https://i.imgur.com/66Jec19.png) ### Camera stability detection 在低光環境下,專業的攝影師會把相機固定在三腳架上,他們也有支援手機固定的情境,此時曝光時間可以最多 1s,但偵測到手機是手持的話,曝光時間就會被設定在最多 333 ms ![](https://i.imgur.com/puYpThh.png) ![](https://i.imgur.com/wRRlt8b.png) ![](https://i.imgur.com/SVFWt8n.png) 首先為了確認使用者是手持還是放在三腳架上,他們得先用陀螺儀去偵測這件事情。為此,他們對按下快門前所接收到的所有角速度做時間上的平滑平均,取按下快門前的 t0=1.466s 來得到 - 接下來他們去觀察固定在三腳架上面的手機的角速度,他們發現在按下快門前都會有一個很大的角速度這個量值甚至會超過手持的角速度,通常會持續幾百毫秒,而且在越小的三腳架上面越大,這個角速度是來自腳架上面的快門按鈕 - 又因為物理上按下快門以及軟體接收到訊號後按下快門之間有一些延遲,有些角速度會被算成是 pre-shutter angular speed,也就是會有真正的角速度與按下快門前的角速度這兩種,這造成了在判斷手持與固定上的困難 - 為了這個延遲,他們又濾掉了 t1=0.400 s 的角速度 (也就是距離按下快門 0.4 s以內的全部不考慮) - 最後,相機的移動就會是從 -t0 <= t <= -t1 這個時間點角速度的平均值,t=0 就是實際開始拍照的時間,因此才會是負數 ![](https://i.imgur.com/uCwtFWK.png) ### Exposure time selection 在得到了對未來運動的預測和相機穩定度之後,他們要用來算出一個能達成最好 SNR 的 exposure time 和 gain,這是一個 trade-off - 如果曝光時間太短,就會造成額外的 noise - 如果曝光時間太長,就會有很多 motion blur 為此他們設計了一個動態的 schedule,而非靜態的 schedule (下圖藍線) - 用相機穩定度來計算最大曝光時間 - 用運動預測來來計算用來限制模糊的曝光時間(blur-limiting exposure time),然後將 motion blur 的像素限制為 B - 當場景越暗的時候,需要更高的 gain 才能把曝光時間限制住,此時又會引入更多的 noise,因此**不能單單只提高 gain,而是要把 gain 和曝光時間一起提升**。這雖然會造成圖片可能會超過設定好的 blur threshold,但最後出來的結果 noise 並不高。 ![](https://i.imgur.com/BJeJSo0.png) ![](https://i.imgur.com/n5xD6Oj.png) 靜態跟動態的差別? - 差別在於光照的程度 - 在明亮的場景 (>100 lux),即使曝光時間很短,SNR也可以很高,因此 gain 在靜態跟動態都會維持在最低值。而在黑暗的場景 (< 0.3 lux),動態跟靜態都會選擇最大的曝光時間,至於介在這兩種 lux 中間的話是動態表現會比較好。 - 下圖比較了靜態(左)和動態(右)在靜止(上)以及移動(下)的差別,ET 就是曝光時間 ![](https://i.imgur.com/jM7DpQF.jpg) ## 甚麼是 RAW image? ![](https://i.imgur.com/aV8VG9H.png) ![](https://i.imgur.com/KVOpbJ1.png) RAW image 就是攝影機 sensor 將捕捉到的光源資訊轉換為數字訊號的原始資料 - 一般是採用 Bayer filter 的排列方式來呈現,包含 50% 的綠色(人眼對綠色頻段比較敏感)跟各 25% 的紅色跟藍色資訊 - 這個 filter 一次只能通過紅藍綠其中一種顏色 ![](https://i.imgur.com/35JkTjE.png) ![](https://i.imgur.com/LwNj33p.jpg) 完全沒經過後處理的 RAW 會長這樣 ![](https://i.imgur.com/sxWqQ9X.jpg) 經過猜色(根據filter的規則猜)之後的 RAW 會變成 ![](https://i.imgur.com/ePwldDE.jpg) 之後我們當然還會再過許多許多的後處理得到好看的圖片,而那又是有緣再講的故事了 ## MOTION-ADAPTIVE BURST MERGING Aligning and merging a burst of frames 是計算攝影中做圖片降噪最有效的方法,這邊提到很多過去的 align 方法不是太慢(CNN)就是不夠 robust(SynthCam會有 motion artifact),另外也有提到 super-resolution 則對於暗光降噪 align and merge 的時候很有用 ### 簡介他們的方法 - 考慮到速度與 robustness 他們選擇基於 [Hasinoff et al. 2016](https://people.csail.mit.edu/hasinoff/pubs/HasinoffEtAl16-hdrplus.pdf) 中提出的 Fourier domain temporal merging technique 來做更進一步的改善 - 雖然也有其他方法可用,但他們大多是在 tone-mapped (JEPG) 圖片上去做操作而非原圖 - 原圖是 10bit,tone-mapped 圖是 8bit,在原圖上做處理的資訊量更多 (increased dynamic range) - 原圖跟場景亮度成正比,tone-mapped 圖則是包含了非線性的 tone mapping操作,這會讓圖片失去了線性。而他們認為線性會讓他們的模型對於噪音的檢測更準確,進而讓 alignment 和 merging 更可靠,也可以讓 auto-exposure 更簡單 - 由於這個方法不是在ISP裡面做,而是在進入ISP前對原圖做,所以可以用在各種方法上,擁有 Portability - Fourier domain merging 的這個方法實際上是在降噪強度跟motion artifacts 之中做 trade off,如果場景中包含了 motion 就會很難 align 不同的 frames,假如直接對這些 aligned frames 取平均的話會造成鬼影 (ghosting) 和 motion blur - Hasinoff 那篇裡面的解決辦法是調一個超參數去調整 weighted average 的 weighting,降低 merging 的強度,但這樣就會丟失靜態區域的降噪能力,算是一個為了避免出現鬼影的權衡方法 ![](https://i.imgur.com/zYnvJwP.png) - 為了解決這兩個問題(鬼影跟丟失的靜態區域降噪能力),他們在頻域合併之前增加了一個空間域的相似度計算(in the form of “mismatch maps”) - 這個不匹配圖 (mismatch maps) 可以讓我們去決定哪一塊區域要做更強烈的 merging 而哪一塊要更保守 - 這樣做可以增加靜態區域合併的 temporal,也可以透過減少動態區域的合併來避免 artifacts 總之他們基於 Hasinoff et al. 的改進有三點 1. 計算出不匹配圖,動態區域會有高度的不匹配,靜態區域則是高度匹配 2. 利用第一點的不匹配圖來針對動態與靜態區域做不同程度的 spatially varying Fourier-domain burst merging,使得在靜態區域會有較強的 merging,而動態區域則有較弱的 merging 3. 加入空間域去噪來補強為了解決鬼影問題而被減少的時域去噪能力 ### Alignment - alignment 跟 merging 都是以參考禎 (reference frame) 為基準下去做的 - alignment 他們一樣是基於 Hansinoff et al. 中的 tile-based alignment algo 去針對低光場景和 high noise 情境做更多的改進 tile-based alignment algo - 在 Hansinoff et al. 中,他們使用 coarse-to-fine algorithm on four-level Gaussian pyramids of the raw input 來做 alignment - 首先是他們從前三個 frames 中選出最清楚的當成參考禎,然後對這張圖片(RAW)中的每一個 RGGB 的 Bayer 採樣(2x2 blocks)做平均,這樣就可以得到下採樣四倍的灰階圖片 (12 Mpix RAW image to 3 Mpix grayscale image) - Mpix = mega pixel ![](https://i.imgur.com/jWUcqjV.png) - $T$ = a tile of reference image - $I$ = larger search area of the alternate image - $p$ = power of the norm used for alignment (1 or 2) - $n$ = the size of the tile (8 or 16) - $(u_0, v_0)$ is the initial alignment inherited by the tile from the coarser level of the pyramid. 在比較 corase 的層數上使用 L2 residuals(搜索半徑大),在比較 fine 的層數上使用 L1 residuals 去優化(搜索半徑小) - 原論文還有提到他對 L2 做修改進一步加速運算,但這邊就不多提了 - 他在每一層的金字塔中都使用 tile-based alignment,且每一層的初始估計值都是上一層 alignment 的結果,如下圖 ![](https://i.imgur.com/WBr4arV.png) - 所謂的金字塔融合就是指對圖片做下採樣,產生出不同的 level 來融合圖片 - [高斯金字塔与拉普拉斯金字塔](https://jiangren.work/2019/08/10/%E9%AB%98%E6%96%AF%E9%87%91%E5%AD%97%E5%A1%94%E4%B8%8E%E6%8B%89%E6%99%AE%E6%8B%89%E6%96%AF%E9%87%91%E5%AD%97%E5%A1%94/)、[CMU 15-463](http://graphics.cs.cmu.edu/courses/15-463/2005_fall/www/Lectures/Pyramids.pdf) - 高斯金字塔: 最基本的金字塔,對同一張圖片進行多次的高斯模糊跟下採樣來產生金字塔 ![](https://i.imgur.com/XyFGBkp.png) - 拉普拉斯(殘差)金字塔: 每一層的圖都是同一層的高斯金字塔減去進行過高斯模糊跟上採樣的上一層圖的結果 (用來儲存下採樣後圖片與原圖的差異,因為下採樣後的損失無法從上採樣來得到完全恢復) ![](https://i.imgur.com/0qjNFiw.png) ![](https://i.imgur.com/9sIuLAK.png) ![](https://i.imgur.com/XaMgizm.jpg) ![](https://i.imgur.com/vzmSW6V.jpg) 他們的改進 - 當圖片的 noise 越大, tiles 的大小就會越大,因此他們把原本的 8 or 16 pixels square tiles 改為 16, 32, pixels,noise 越大就越大 ### Spatially varying temporal merging - 做完 alignment 之後會得到一群 16x16 的 tiles,他們對這些 tiles 在 Fourier domain 做 weighted average (Hasinoff et al.) - 每個 frame $z$ 在 tile t 貢獻的權重正比於 1- $A_{tz}$。如果這個 frame 中的 tiles 之間的差異小於 noise 的話,$A_{tz}$ 會減少且發生很多次的 merging。反之,若 tiles 之間的差異大,$A_{tz}$ 就會趨近於 1, 這個 frame 中 tile 的貢獻就會變少 ![](https://i.imgur.com/uOOvewg.png) - $D_tz$ 是 tiles 的 Fourier band $\omega$ 之間的差 (Hasinoff et al. 2016), - $\sigma_{tz^2}$ 是已知的 noise variance - c 是用來 scaling noise variance 的常數 - 可以用來在 denoise strength 跟 robustness to motion and alignment-error artifacts 之中做 trade off - 他們把這個參數稱為 tmporal strength,c=0 代表沒有任何 temporal denoising,若 c 趨近於無限大就代表 averaging without any motion robustness,見下圖(a)~(d) ![](https://i.imgur.com/0dQAj0g.png) 經過實驗,他們發現在低光場景下 c 必須要增加很多來增加每個 frame 的貢獻並以此來降低 noise,但這樣做會提高 tiles 在融合的時候的 mismatch,進而引入 artifacts ![](https://i.imgur.com/pZ9bqoE.jpg) 所以他們多引入一個線性分段函數 $f_{tz}(m_{tz})$ (上圖 f) 讓他們可以在 high-mataching 的區域增加 temporal denoising,然後再 high-mismatching 的區域減少 denoising,多保留一些細節 ![](https://i.imgur.com/86J7NqW.png) - $m_{tz}$ 是 mismatach 的程度,是從當前 frame $z$ 跟 reference frame 中每一個 tiles 的 L1 差 $d_{tz}$ 以及 scaling constant $s$ 跟已知的 noise variance 算出來的 - $m_{tz}$=0 代表 no mismatch,$m_{tz}$=1 代表 high masmatch - $s$=0.5,他們實驗出能用來在偵測到運動的時候壓制噪音的數值 ![](https://i.imgur.com/c0jo6sW.png) 做個總結,原本的方法中是以 16x16 個 tiles 中某一個傅立葉 band 來計算他們之間的差異,而現在修改後的方法則是通過對齊 mismatch 最高的 tiles (且 tiles 有多個尺寸) 來在空間域中跨頻帶去計算差異 ### Spatially varying denoising 這一部分一樣是改 Hasnoff et al. 的方法,在圖片經過融合之後去做降噪 - 原本的方法是針對所有 frame 去根據各自的 noise variance 給予不同的降噪強度 - 現在他們改為使用上一個階段所得到的 mismatch map 來針對 ![](https://i.imgur.com/D6VsJL7.jpg) ![](https://i.imgur.com/jmHHGPp.jpg) ## LOW-LIGHT AUTO WHITE BALANCE ### 甚麼是自動白平衡 (Automatic White Balance, AWB)? ISP from [ICCV19](https://www.eecs.yorku.ca/~mbrown/ICCV19_Tutorial_MSBrown.pdf) ![](https://i.imgur.com/LLbDQt0.png) 自動白平衡就是根據偵測到的[色溫](https://zh.wikipedia.org/zh-tw/%E8%89%B2%E6%B8%A9)自動調整拍攝出來的圖片色調,是任何的相機設備必備的功能之一 ![](https://i.imgur.com/VpPo04x.jpg) ![](https://i.imgur.com/XSmsllL.jpg) 以數學上來看,AWB 就是去找出一個轉換矩陣來轉換 sensor 的 RGB ![](https://i.imgur.com/dnkdzM4.png) 假如直接取 R,G,B 的平均來轉換的話 ![](https://i.imgur.com/T92aTqW.png) ### 他們的方法 基於 [Fast Fourier Color Constancy(FFCC), 2017](https://openaccess.thecvf.com/content_cvpr_2017/papers/Barron_Fast_Fourier_Color_CVPR_2017_paper.pdf) 在低光場景下去做修改 - 這是一個 CNN 方法,所以當然需要資料去學習。但是當時的資料集都很中性,缺少低光場景的資料 - 所以他們就自己用帶有校準器的手機收集了大約 5000 張低光場景的資料,並且找專業的攝影師幫忙標註每一個場景中最好的白平衡設定 ### 誤差指標 (Error metrics) 傳統的指標是基於色彩恆常性,也就是即使左右兩圖的背景光源完全不同,也不影響你對物件的色彩判斷,這是因為人的大腦也會進行自動白平衡 ![](https://i.imgur.com/6AfyrwW.jpg) 但是這樣的指標在低光場景下不穩定,所以他們得自己設計一個低光場景用的指標 - 正常的環境下都會有燈泡或是太陽等光源點亮,這種光源的真實顏色大多接近白色 - 低光環境下的光源則是由顏色比較深的光源來點亮(例如夜店、營火),光源顏色較深這就表示真實顏色有可能會有 color channel 為 0 或是非常接近 0 的情況發生,此時訓練就會出現問題 (因為0乘以任何數字都是0,根本沒做到縮放,會讓圖片在不同場景下的那一個 color channel 幾乎一樣),而自動白平衡的演算法通常都是根據能恢復多少光源的所有 color channel 程度來評估 這會有以下三個缺點導致原本的 FFCC 無法使用 1. 收集真實的光源資料的時候不知道怎麼設置光源的缺失通道 2. 對這種顏色較深的圖片做評估的時候,估計色彩通道會因為這些缺失通道造成的 irrelevant "mistakes" 導致準確率可能會看起來很低 3. 因為這是基於學習的演算法,他會嘗試去最小化這些缺失通道中沒有意義的跟光源顏色相關的 loss,模型很可能就會浪費時間在學習這種無法確定且無關的光源顏色上面 首先來看看 The canonical metric for color constancy - 計算的是真正光源和恢復後光源的 RGB 向量之間的角度,算出來的結果就是對恢復光源的誤差估計 - $l_p$ 為恢復光源(預測光源)、$l_t$ 為真實光源的 RGB 向量 ![](https://i.imgur.com/3tRn15G.png) 但是他們想要的是將輸入的圖片除以恢復光源時所得到的白平衡圖像外觀,而不是光源恢復之間的差異,所以這個不太合用 後來又有人提出了 The reproduction error (重現誤差) ![](https://i.imgur.com/oOKJiH5.png) - 除法為 element-wise - 考慮了與真實光源相比在恢復光源下 "white patch" 外觀的誤差,但若要用在低光場景這種會缺少一兩個顏色通道的情況下,"white patch" 又難以定義。 最後,為了符合低光場景下的需求,他們提出了 Anisotropic Reproduction Erro(ARE) ![](https://i.imgur.com/1xzNNMl.png) - ARE 把真實光源和恢復光源的 inverse (也就是一個 white patch 在真實和恢復光源下的外觀)投影到一個由真實白平衡圖片的平均顏色 $\mu_t$ 縮放過去的3D空間,然後就會在3D空間去算 reproduction error - $\mu_t$ 中某一個通道越小,$\triangle_a$ 就會對 $l_p$ 中的這一個通道的誤差就越不敏感,若是 $\mu_t$ 的這個色彩通道為0,就會對其誤差完全不敏感 - 假如圖片中缺少了兩個色彩通道,ARE就會永遠都是0,這樣的特性可以準確地反映無法用每一個色彩通道的增減來改變場景的色彩組成的事實,所以此時ARE會變成標準的 reproduction error ![](https://i.imgur.com/KrrBw9g.png) 在他們的資料集中大多數場景的平均真實顏色都接近灰色,因此 ARE 在這些圖片中算出來的數值跟 reproduction error 很像,但如果是在暗光場景下,這兩個指標的差異就會很大 ![](https://i.imgur.com/Ra7Tp0C.png) - 從實驗可知,使用 ARE 訓練的模型在他們的資料中不管是 Mean error 還是 Worst Error 都比較低,因此就算不是暗光場景,只想使用角度誤差或是重現誤差的話還是可以用 ARE ## Tone mapping Tone mapping 是為了在一個有限的範圍中(圖片)顯示動態範圍成像(HDR)而去計算這兩者之間的映射 - 動態範圍指的是影像中最亮和最暗部分的比例,從純黑色到最亮的白色,這會根據你所使用的攝影機 sensor 不同而不同,目前最厲害的 sensor 也只能抓取到大約人眼一半的動態範圍 - tone mapping 的過程就是要 1.)先根據當前的場景推算出場景的平均亮度,2.)再根據這個平均亮度選取一個合適的亮度域,3.)再將整個場景對映到這個亮度域得到正確的結果 - tone mapping 通常是作為 HDR 演算法的一部分而存在 (HDR->LDR),在這篇就是為了在低光場景下也能顯示出盡可能真實的顏色而做 - 下圖是人類在不同光照下的視力,其實你從一個明亮的環境進入到比較黑暗的環境的時候,人眼也會開始做 tone mapping 來調高你的亮度域去適應 ![](https://i.imgur.com/rptA3tN.png) Without tone mapping (above) vs With tone mapping (below) ![](https://i.imgur.com/7k8tiDS.jpg) 通常會分為全域(global)和區域(local)映射 - 全域映射:對圖片所有的像素做一樣的映射,相同的像素值會映射到相同的值,映射過程不受其他因素(如鄰近像素值或影像平均值等)所影響,一旦映射規則建立,輸出值只與當時的輸入值有關。 - 優點為計算效率較為快速,因此可快速知道影像中的內容為何,且可用於即時裝置,其缺點是忽略了人類視覺系統的真正感受。 - 區域映射:將圖片中相同的像素值可能映射到不同的值,也就是其映射的結果常需要參考到鄰近像素的光源資訊。 - 優點可得到較多的細節;相對的缺點為計算量很大,而且會造成一些很明顯的不自然光暈(Halo)副效應。 針對低光場景的 tone mapping,他們有以下幾個想法: 1. 以顯示 noise 為代價,允許對圖片增加更多的 gain 來渲染出更亮的圖片 2. 抑制陰影的增強,使圖片中最暗的的區域接近黑色,保持全局對比度的同時看起來有夜間的感覺 3. 允許壓縮到更高的動態範圍,可以在困難的低光場景下產生更鮮艷的顏色 4. **用跟場景亮度成反比的方式來提高色彩的飽和度** 他們所使用的是 local tone mapping,基於 Mertens et al. 2007 的方法 - 這個方法會將整個色調範圍分為短曝光(highlights)跟長曝光(shadows),以此來確定每次要加多少 ISO,然後把這些從高動態範圍融合到 8-bit 範圍 - 在照度 $E_v$ 低於 threshold $L_{min}$ 的場景,就會逐漸增加陰影區域的增益 $A_s$ (以lux為單位),當對數超過1的時候,就會撞到 threshold,變成只增加 2.2 lux - $L_{min}$ 和 $L{max}$ 就對應 0.1lux 和 200lux 的場景亮度 ![](https://i.imgur.com/0eQigPM.png) - 把 20% 的額外陰影增益的一部分也用在 highlight 上面去,這會跟場景的高動態範圍 D 成反比,不然的話會導致強度分布變太窄,喪失對比度 - 同時他們還把跟場景的 log-lux 成反比的顏色飽和度增加20%,有助於人臉皮膚的重現 ![](https://i.imgur.com/1YKSowr.png) baseline 是 Hansinoff et al. ![](https://i.imgur.com/OndmYBy.png) ## Result Hansinoff et al. 2016 vs 這篇 ![](https://i.imgur.com/1wqMPl8.jpg) ![](https://i.imgur.com/Es0suep.jpg) ![](https://i.imgur.com/P29yJZR.jpg) 這篇 vs End2End CNN (Chen et al. 2018) ![](https://i.imgur.com/SqPNZ1z.jpg) 偷臭 ![](https://i.imgur.com/FPFyFtx.jpg) ## 不足的地方 他們詳細列出了這整個流程方法的缺點 1. 暗光場景難以自動對焦 2. 流程太長無法做到 real-time,會造成 preview 並非實時的 3. 快門響應慢,會有 shutter lag,因為他們沒有一直在拿 viewfinder 的資訊 4. 黑得不夠黑 (Black level 的數值無法完整呈現 sensor 的黑色) 5. 晚上天空的前景色調跟背景會重疊 (後來谷歌在一年後有發了[另一篇](https://arxiv.org/abs/2006.10172)專門討論天文攝影) # References https://ai.googleblog.com/2018/11/night-sight-seeing-in-dark-on-pixel.html http://photo.popart.hk/newweb/archives/88313 https://contrastly.com/understanding-noise-reduction/ https://capturetheatlas.com/noise-in-photography/ https://blueeyes.com.tw/LearningHub/whitepaper/wp_Common-camera-parameters.pdf https://zhuanlan.zhihu.com/p/386158280 https://blog.csdn.net/qq_42261630/article/details/102922737

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully