# 第四堂社課 | 電研X天文聯合社課
## 卷積&去卷積&天文影像處理
---
## 時(空)域、頻域(頻譜圖)
:::info
一張照片的兩個面向
:::
我們平常看到的像素照片,每一個像素都記錄了RGB的值 (相機記錄到的光能)
將RGB值作為Y軸畫成折線圖後,即是時(空)域,他具有這樣一個特徵:
* 時(空)域的訊號是雜亂的
而為了使電腦可以更好的理解這個無規律的訊號,我們需要對照片進行一些處理,把它表示成 "多個有規律的訊號的疊加",此過程即是傅立葉轉換。
* 傅立葉轉換(Fourier Transfrom)(公式如圖一)
任何一個有規律的函數,都可以表示成其他有規律的函數的疊加 (圖二 ab)
也就是說透過把一堆有規律的函數相疊加
就能得出一個更複雜且有規律的函數
$$f(x)=\frac{a_0}{2}+\sum^{\infty}_{n=1}(a_ncos{\frac{2\pi nx}{t}}+b_nsin{\frac{2\pi nx}{t}})$$
$$a_0=\frac{1}{\frac{t}{2}}\int^{\frac{t}{2}}_{-\frac{t}{2}}f(x)dx$$
$$a_0=\frac{1}{\frac{t}{2}}\int^{\frac{t}{2}}_{-\frac{t}{2}}\cos\frac{2\pi nx}{t}dx$$
$$a_0=\frac{1}{\frac{t}{2}}\int^{\frac{t}{2}}_{-\frac{t}{2}}sin\frac{2\pi nx}{t}dx$$
$$(圖一:傅立葉級數的公式)$$
![image](https://hackmd.io/_uploads/r1I_cPkGC.png)
(圖二:將一個雜亂的函數表示成很多個有規律的sin/cos函數的疊加)
* 那沒規律的函數呢?
把一個無規律的函數圖形看成是有規律的,只是它的週期是無限大
然後把這個 "週期無限大" 的函數拆解成很多個$\sin$和$\cos$函數的疊加
$\sin$和$\cos$都是有規律的,所以電腦可以比較輕鬆的理解這段函數
* 頻域(頻譜圖)
圖一 b的左邊可以看到紅色的標記
此紅色的標記就是各個$\sin$ or $\cos$函數的振幅
一個$\sin$函數會有一種頻率,同時會對應到一個振幅
如果我們把各個$\sin$函數的頻率作為x軸,振幅作為y軸
這樣畫出來的圖,就是頻譜圖(頻域) (圖二 c)
![image](https://hackmd.io/_uploads/rJSRBPJfC.png)
$$(圖三:時域與頻域的對照圖) (source:改編自二十四橋KG)$$
* 光譜學上的用處
光譜即是一張時(空)域,我們對其進行傅立葉轉換後
便可得到許多不同頻率的$\sin$和$\cos$波形
如此一來,我們便可以輕鬆將一些特定頻率的訊號(例如:光害的訊號)去掉
然後再把剩下的訊號(天體發出的訊號)重新疊合在一起
即可得到乾淨的天體訊號(沒有大氣影響或光害的)
---
## 卷積(Convolution)
### 卷積的定義
:::info
卷積是將訊號疊加
在影像處理上類似於套用濾鏡
:::
有一間工廠生產麵包
遵循以下兩條規則
$$
\begin{aligned}
&f(x)=隨時間麵包的產量\\
&g(x)=隨時間麵包未腐壞率
\end{aligned}
$$
那如果想知道在第$t$個時間單位共有多少麵包呢?
我們可以先思考一下
在第0個時間單位生產的麵包數量為
$$f(0)g(t)$$
::: success
因為第0秒有$f(0)$個麵包被生產出來
又在$t$時間後
第0秒生產的麵包的未腐壞率為$g(t)$
:::
所以在第$x$秒生產的麵包數量為
$$f(x)g(t-x)$$
如果我們要求$t$秒內共有多少麵包
那就是
$$\sum^t_{x=0}f(x)g(t-x)$$
如果把時間當作連續
則變成
$$\int_0^t f(x)g(t-x)dx$$
這就是我們說的
**卷積是在做訊號疊加**
我們有兩個函數(訊號)$f(x)、g(x)$
就能藉由卷積將兩個函數疊加在一起
$$(f\ast g)(t)=\int_0^t f(\tau)g(t-\tau)d\tau$$
另一個例子
我們有原訊號及系統響應(也就是訊號隨時間會不斷衰減)
![image](https://hackmd.io/_uploads/SJa6SjJGR.png =80%x)
所以我們如果想求出實際訊號值
就必須將輸入訊號與系統響應疊加
那在時間$t$後
第0秒的訊號就會變成$f(0)g(t)$
又因為訊號是不停地被輸入
所以第$t$秒時的總訊號就是在$t$秒內的所有乘積和
即
$$\int_0^t f(x)g(t-x)dx$$
這樣應該就能理解為什麼算卷積時要將其中一個函數翻轉了
![image](https://hackmd.io/_uploads/B1hohIxG0.png =80%x)
### 練習:用陣列算卷積
我們可以把陣列$[4,5,6]當作[f(1),f(2),f(3)]$
這樣就能用離散的方式練習卷積了
現在要算出
$[1,2,3]\ast[4,5,6]$
**算法如下:**
先把其中一個陣列反轉
然後依序移動做對應項的乘積和
![IMG_0711](https://hackmd.io/_uploads/HkSXL4QPp.jpg =40%x)
目前答案: [**1*4**, , , , ]
![IMG_0712](https://hackmd.io/_uploads/SyxnLEmPT.jpg =32%x)
目前答案: [4, **1\*5+2\*4**, , , ]
![IMG_0713](https://hackmd.io/_uploads/Hy1gwNmw6.jpg =25%x)
目前答案: [4, 13, **1\*6+2\*5+3\*4**, , ]
![IMG_0714](https://hackmd.io/_uploads/SyMBPVXDp.jpg =32%x)
目前答案: [4, 13, 28, **2\*6+3\*5**, ]
![IMG_0715](https://hackmd.io/_uploads/ry_wDN7wa.jpg =40%x)
目前答案: [4, 13, 28, 27, **3\*6**]
所以最後得出$[1,2,3]\ast[4,5,6]=[4, 13, 28, 27, 18]$
## 影像卷積(二維卷積)
### 圖的數值化
![234562345](https://hackmd.io/_uploads/BkhnWI9ZA.png =70%x)
在圖像中會以8個bit儲存顏色資訊
也就是說每個像素可以調整出256種不同的顏色強度
彩色圖片則可以分為RGB三個channel
一樣以8bit分別儲存顏色資訊
![螢幕擷取畫面 2024-04-27 182344](https://hackmd.io/_uploads/BkUIzIc-R.png)
因為圖被數值化了,所以我們可以對圖做二維卷積。
### 二維卷積
![螢幕擷取畫面 2023-12-23 161649](https://hackmd.io/_uploads/rkUPtfED6.png =70%x)
我們先前講過卷積其實是在計算輸入訊號受到系統響應的影響
所以圖片同理
我們要決定每個像素值對最終結果的影響大小
也可以說是要決定每個像素的權重
這些權重稱作卷積核(kernel,又稱為filter weight)
其大小和值是由使用者決定的
不同卷積核對圖片又會有不同影響
類似於圖片的濾鏡(下面有範例)
接著將kernel放在圖上計算對應格子的乘積
再像sliding window那樣將kernel滑過去,再計算
重複至整張圖都被跑過為止
![20170516153849928](https://hackmd.io/_uploads/SkosPamPp.png =70%x)
## 影像卷積效果展示
![e605d15861fd88bac0fbc984b370a0ff](https://hackmd.io/_uploads/rkz-OKVPp.png =98%x)
>原圖
:::info
還要更快
:::
![下載 (4)](https://hackmd.io/_uploads/S1ccOtVv6.png =98%x)
>```python=
>kernel = np.array([0])
>```
>:::info
>不意外的整張變黑了,因為每個像素都被*0
>:::
![image](https://hackmd.io/_uploads/HyOZ5brv6.png =98%x)
>```python=
>kernel = np.array([[1/81 for _ in range(9)] for __ in range(9)])
>```
>:::info
>使用9*9的kernel,每格的值都是1/81,所以整張圖被模糊了9倍
>:::
![output](https://hackmd.io/_uploads/BkosshZMA.jpg =98%x)
>```python=
>kernel = np.array(
>[[0,1,1,2,2,2,1,1,0],
>[1,2,4,5,5,5,4,2,1],
>[1,4,5,3,0,3,5,4,1],
>[2,5,3,-12,-24,-12,3,5,2],
>[2,5,0,-24,-40,-24,0,5,2],
>[2,5,3,-12,-24,-12,3,5,2],
>[1,4,5,3,0,3,4,4,1],
>[1,2,4,5,5,5,4,2,1],
>[0,1,1,2,2,2,1,1,0]])
>```
>:::info
>高斯拉普拉斯算子,可以偵測物體邊緣
>:::
![output](https://hackmd.io/_uploads/BJEKa2ZMA.jpg)
>```python=
>kernel = np.array([[-1,-2,-1],[-2,13,-2],[-1,-2,-1]])
>```
>:::info
>銳利化
>:::
## 遊樂場
環境自己架
gui.py是主程式
https://github.com/ChiuDeYuan/conv_playground
## 去卷積(Deconvolution)
:::info
把圖片還原回來
:::
既然卷積是如此運算
可以把一張圖片變模糊
$$P\ast K=L$$
![c8763kuhuikh](https://hackmd.io/_uploads/HywGfJR-C.png)
那能不能這樣做
就能恢復成清楚的照片了
$$P=L*K^{-1}$$
![c8763kuhuikhuhihu](https://hackmd.io/_uploads/HyVUGkRbC.png)
:::info
這裡卷積核右上方的-1表示這個卷積核是做反操作
:::
這個把圖片變清楚的過程就稱為**去卷積(Deconvolution)**
如果去卷積可以被計算出來
就能夠修復模糊的圖片了
這在天文照片的處理有很大的用處
因為天文照片時常受到大氣、光害等干擾
使用去卷積就能修復出較真實的圖像
:::warning
:warning: 還有其他因素可能會使照片失真
* 相機抖動
* 鏡頭缺陷(如球面像差)
* 光的繞射(Diffraction)
* 物體移動
* 景深限制
* 後期處理的干擾
:::
### 如何執行去卷積?
$$\begin{aligned}我們這樣&表示卷積\\x\;\ast\ &c=b\end{aligned}$$
$$\begin{aligned}空域中的卷積相當&於頻域中的乘法\\F(x)\;\cdot\ F(&c)=F(b)\end{aligned}$$
$$\begin{aligned}除法就相當&於去卷積\\F(x_{deconv})=&\;F(b)/F(c)\end{aligned}$$
$$\begin{aligned}再對結果作反傅立葉轉&換就能得到原圖了\\x_{deconv}=\;F^{-1}&(F(b)/F(c))\end{aligned}$$
<br>
### 點擴散函數(Point Spread Function, PSF)
::: info
用來描述光線的擴散、模糊程度
:::
![image](https://hackmd.io/_uploads/Hkd-8GA-A.png)
:::success
PSF與物體的卷積就會是我們所看到的影像
:::
由於一些擾動(如鏡頭缺陷、光的繞射),
導致影像與理想值有差距,
所以我們用PSF來描述影像的擴展斑點(影像光線的特徵)
![image](https://hackmd.io/_uploads/SJ2Vzb1MA.png =80%x)
你也可以說PSF就是$x_{deconv}=F^{-1}(F(b)/F(c))中的c$
只要知道一張模糊圖像的PSF
就能以去卷積還原圖像
---
## 非盲去卷積(Non-blind Deconvolution)
非盲卷積是指知道PSF的情況下的去卷積
### 維納濾波
由於圖像中可能會有噪聲
$$b=x\ast c+n$$
所以沒辦法直接用$x_{deconv}=F^{-1}(F(b)/F(c))$算出來
因為算出來只會是一片噪聲
所以Norbert Wiener在1942年提出了一個算法
公式如下
$$x_{deconv}=F^{-1}(\frac{\vert F(c)\vert^2}{\vert F(c)\vert^2+1/SNR(\omega)}{\cdot}\frac{F(b)}{F(c)})$$
:::info
$SNR(\omega)$是信噪比,當圖片失真越小,信噪比越大
:::
這個公式是通過最小化期望誤差而來
$$min_H E[\Vert X-H\tilde{B}\Vert^2]$$
:::info
$X=F(x)$
$H$是一個執行去卷積的函數
算出來也就是維納濾波的公式
最後公式是
$$x_{deconv}=F^{-1}(HB)=F^{-1}(\frac{\vert F(c)\vert^2}{\vert F(c)\vert^2+1/SNR(\omega)}{\cdot}\frac{F(b)}{F(c)})$$
:::
### Richardson-Lucy方法
這是用迭代方法算反卷積
$$\hat{f}_{k+1}(x)=\hat{f}_k(x,y)[h(-x,-y)\ast\frac{g(x,y)}{h(x,y)\ast \hat{f}_k(x,y)}]$$
---
## 盲去卷積(Blind Deconvolution)
>圖片來源&參考
>https://zhuanlan.zhihu.com/p/105500403
盲去卷積是在不知道PSF的情況下做去卷積
但其實就是先算出PSF後再用非盲去卷積
### 什麼是我們要的結果?
一般照片像素的顏色梯度分布是這樣的
因為邊界很清楚
所以會有許多梯度較大的區域
這種梯度分布叫做**Heavy-Tail**
![image](https://hackmd.io/_uploads/HyiVikfGA.png =80%x)
:::info
梯度:你可以想像是顏色的變化量
:::
而比較模糊的照片的梯度分布可能會長這樣
因為色塊都糊在一起了(顏色邊界不清楚)
所以會有很多小梯度
![image](https://hackmd.io/_uploads/BkDaiyzGR.png =80%x)
### 計算PSF
![image](https://hackmd.io/_uploads/ByK2nyfGR.png =80%x)
現在我們可以構造估計PSF的式子
$$argmax_K\;p(K|P)$$
:::info
K是模糊核
P是模糊圖像
:::
再用 **變分貝葉斯(Variational Bayesian)** 來求取近似條件機率
### 整體流程
1. 預處理圖像:因為變分貝葉斯計算量大,所以要先選取一小塊圖像
2. 估計模糊核:使用變分貝葉斯
3. 重建圖像:知道PSF後,用非盲去卷積算法
---
## 天文照片處理
* 預處理(第一步)
1. 下載Siril (https://siril.org/)
1. 從USB中下載各個檔案資料夾,並把資料夾名稱中的-IC434去掉
(你的資料夾應該會變成lights、flats、darks、biases)
![image](https://hackmd.io/_uploads/S1ytdoyM0.png)
1. 打開Siril,點擊左上角藍色的房子圖案
1. 然後選取你下載的資料夾所在的位置(假設你下載在D槽,那就選D槽)
![image](https://hackmd.io/_uploads/rkgDdsJMA.png)
1. 點擊上方中間偏左的"Scripts",然後點擊"OSC_Preprocessing"
(這一步驟叫做預處理",通常需要一點時間)
![image](https://hackmd.io/_uploads/Bkh3djkGA.png)
1. 點擊左上角的"Open",然後找到你剛剛預處理完的檔案,打開它
(通常檔案名會叫 "result+一串數字" ,副檔名是.fit檔)
![image](https://hackmd.io/_uploads/BkCC_okGC.png)
* 線性處理(第二步)
1. 點擊下方中間偏左的"Linear",然後改成"Auto Stretch"![image](https://hackmd.io/_uploads/SJxI5iyG0.png)
1. 將鼠標移至畫面中左的照片上,按住左鍵,框選照片
1. 選取好你要的照片範圍後,在照片上按右鍵,然後點擊"crop"
(此步驟可以裁切照片,去除掉照片邊緣一些暗角之類的雜訊)
![螢幕擷取畫面 2024-05-01 194428 (1)](https://hackmd.io/_uploads/ByuOijJMR.png)
1. 對照片中看起來是背景星空的地方點選左鍵,生成紅色的點
(注意不要點到目標天體(中間的馬頭星雲和火焰星雲))
1. 按"compute background",:warning: 然後按"apply",再關閉"Background Extraction"的介面
![螢幕擷取畫面 2024-05-01 195902](https://hackmd.io/_uploads/HJSTX3kfA.png)
1. 一樣是點擊上方的"Image Processing",然後選取"Color Calibration"
1. 一樣按住右鍵,框選照片中看起來最暗的部分(最黑),然後點擊上面的"use current section"(框選的部分不用很大)
1. 重複上面的步驟,但改成選取照片中最亮的部分,然後點擊下方的"use current section",然後按"apply"
![螢幕擷取畫面 2024-05-01 201830](https://hackmd.io/_uploads/rkPnQhyM0.png)
* 去卷積(第2.5步)
1. 一樣點擊上方的"Image Processing",然後選取"Noise Reduction"
1. 將"Secondary denoising algorithm"改成"Anscombe VST",並將下方的"Modulatuion"調到0.5~0.6之間,然後按"apply"
1. 接著,將照片的右下角框起來,然後像之前一樣,點右鍵,然後按"Crop"
1. 按右上角一個像"三"的符號,然後點"image information",再按最下面的"Dynamic PSF"
1. 將左下角的"Profile Type"改為"Moffat",然後按右下角那一排最左邊,三顆星星的符號
(此步驟會幫你偵測受大氣擾動後變模糊的星點,並生成它們的平均PSF)
1. 接著,點選上方的"Image Processing",然後選取"Deconvolution"
1. 點擊上半部分的"PSF from stars",看看PSF review是不是有出現一個點擴散函數的圖片
1. 將下半部分(non-blind deconvolution)的模式改為"Richardson-Lucy methods",然後將"Gradient Descent"改成"multiplicative"
1. 更改"Iteration",試試看星點去卷積後有什麼不一樣
(試完一次後,可以按左上角的Redo,再重新試一次)
1. 當你覺得去卷積後的星點看起來足夠像圓形後,你可以按Redo,把照片回復成大張的(未Crop成一小張之前的樣子)
1. 然後用你剛剛覺得滿意的去卷積參數對整張照片去卷積
![螢幕擷取畫面 2024-05-03 102752 (1)](https://hackmd.io/_uploads/H1t0spbG0.png)
* 非線性處理(第三步)
1. 將下方的"Auto Stretch"改回"Linear"
1. 點擊上方的"Image Processing",然後選取"Asinh Transformation"
1. 介面中,調高"Stretch factor"會讓照片變亮,調高"Black point"會讓照片變暗
1. 你們要讓照片中馬頭星雲稍微出現,然後背景不能出現反白(過曝)的感覺,:warning:然後記得按"apply"
![螢幕擷取畫面 2024-05-01 202952 (1)](https://hackmd.io/_uploads/r1wx83yfA.png)
1. 一樣點擊上方的"Image Processing",然後選取"Histogram Transformation"
1. 然後點擊介面中間偏右的齒輪,:warning:然後一樣記得按"apply"
![螢幕擷取畫面 2024-05-01 205854 (1)](https://hackmd.io/_uploads/S1Sx6hkMC.png)
1. 一樣點擊上方的"Image Processing",然後選取"Remove Green Noise",然後直接按apply
![螢幕擷取畫面 2024-05-01 210623 (1)](https://hackmd.io/_uploads/SyWKAnJG0.png)
1. 一樣點擊上方的"Image Processing",然後選取"Color Saturation"
1. 然後調整成自己喜歡你 yeah的顏色
![螢幕擷取畫面 2024-05-01 210758 (1)](https://hackmd.io/_uploads/S1T00h1z0.png)
### 就這樣!
## 參考
https://zhuanlan.zhihu.com/p/104340592
https://zhuanlan.zhihu.com/p/105500403