# 圖片堆疊 把一串連拍合成一張，RAW 也行

二十張變一張，不用傳二十次，也不用 RAW 轉換器。

> 把一串連拍的照片合成一張：取平均值消雜訊，取中位數把人從畫面裡去掉，取最亮做星軌，或者給微距做景深合成。CR2、NEF、ARW、DNG、RAF 和 CR3 靠讀出相機自己的預覽圖來開啟。全部在你的瀏覽器裡跑。

本頁是一個完全在你的瀏覽器裡執行的互動式工具，地址是 https://abox.tools/zh-TW/stack-images/。你交給它的任何內容都不會被上傳。下面是這個頁面用文字對該工具的全部說明；要使用它，請開啟這個地址。

## 你的照片**不會上傳**。這裡根本沒有伺服器。

每一幀的開啟、解碼、對齊、合成和寫出，全都由你自己的瀏覽器在你自己的機器上完成。二十個 60 MB 的 RAW 檔案差不多是一個 G 的照片，其中一個位元組也沒有動過。這個工具沒有任何聯網功能，檔案由一個無處可送的 worker 直接從你的硬碟讀取。

- ✗ 不上傳
- ✗ 不用註冊
- ✗ 沒有水印
- ✓ 能讀 RAW
- ✓ 斷網也能用
- ✓ 開源

## 怎麼在瀏覽器裡堆疊一組照片

1. **選幀。** 一串連拍、一組包圍曝光、一段間隔拍攝，或者一整個裝著 RAW 檔案的資料夾都行。每一個到了就開啟，那一行會告訴你從裡面讀出了什麼。RAW 檔案的話，是相機型號、裡面找到的預覽圖尺寸，以及為了找到它只需要讀多少。
2. **按你想失去的東西挑手法。** 雜訊：平均值；要是有什麼動過，Sigma 裁剪。人、車、飛過去的飛機：中位數。想變成星軌的暗夜空：最亮。沿著對焦環拍的微距：景深合成。選單下面那行字會說明，對你手上這個幀數，每種手法會做什麼。
3. **決定要不要對齊。** 手持：要，只平移。手持而且還在轉：平移加旋轉加縮放。鎖死的三腳架或者間隔拍攝：不要，而且會更快。每一幀都是拿標著基準的那一幀來量的；你不另說，基準就是第一幀。「拿它當基準」只挪那個標記，清單的順序還是你排的樣子。
4. **讀那四個數字，再按按鈕。** 在任何東西開跑之前，頁面會說清結果會有多大、大概要多少記憶體、這些幀會被解碼多少次，以及你的檔案被讀了多少。這一組要是沒法一次裝進記憶體，它也會說，並且說清換哪一檔工作解析度就夠了。

## 說得更細的版本

[怎麼堆疊照片來壓雜訊，或者把人去掉](https://abox.tools/zh-TW/guides/stack-photos-to-reduce-noise/): 堆疊把一串連拍合成一張。用哪種手法，取決於你想失去什麼：雜訊、路人，還是微距那淺得可憐的景深。每種手法怎麼運作、代價是什麼，以及 RAW 檔案在這裡是什麼位置。

## 工具箱裡還有

- [圖片塗黑與打碼](https://abox.tools/zh-TW/redact-image/): 你遮住的那塊是從檔案裡刪掉的，不是藏在檔案裡。
- [EXIF 檢視與清除](https://abox.tools/zh-TW/exif-editor/): 看看一張照片把你交代了多少，然後刪掉。
- [DICOM 閱片器](https://abox.tools/zh-TW/dicom-viewer/): CT、MR、X 光和超音波，連窗寬窗位、頭資訊和測量一起。
- [圖片轉 ICO](https://abox.tools/zh-TW/image-to-ico/): 進去一張圖，出來的是瀏覽器、Windows 和 Mac 各自要的每一個尺寸。

## 常見問題

### 我的照片會被上傳嗎？

不會。每一幀的開啟、解碼、對齊、堆疊和寫出，全都由你自己的瀏覽器在你自己的硬體上完成。這個工具沒有任何聯網功能，從不取東西，也從不發東西，頁面的 `Content-Security-Policy` 裡寫著它能聯絡的每一個地址，沒有一個屬於本站。把頁面載入一次，斷網，它照樣能用。這件事在這裡比在多數工具上更要緊，單純是因為量：二十個 RAW 幀差不多一個 G，而為了讓別人算一次平均值就上傳一個 G 的照片，正是這個工具存在的意義所要避開的事。

### 它能讀哪些 RAW 格式？怎麼讀的？

CR2、CR3、NEF、NRW、ARW、SR2、SRF、DNG、ORF、RAF、RW2、PEF、SRW、3FR、IIQ、DCR、KDC、MRW、MEF、RWL 等等，也就是相機會寫的絕大多數。從裡面讀出來的是相機自己在按下快門那一刻渲染好的原尺寸 JPEG 預覽圖，也就是相機背後螢幕上顯示的那張，以及你的作業系統拿來當縮圖畫的那張。它是靠走檔案的目錄結構找到的，代價是幾次每次幾十 KB 的讀取，然後取其中一段。**這不是對感測器資料做去馬賽克。**結果帶的是相機自己的白平衡和照片風格，每通道八位，而不是 RAW 轉換器會給你的那十二位或者十四位線性感測器資料。

### 那為什麼不好好解碼感測器資料？

因為那意味著要把 LibRaw 或者 dcraw 隨包帶上：為了一個格式家族多背一個幾十兆的引擎，而其中大半還是各家廠商自己的壓縮方案。這筆帳在本站原始碼的 `docs/what-can-be-built-here.md` 裡算過，相機 RAW 早在這個工具出現之前就在排除名單上了。變的不是那個問題的答案，而是我們發現堆疊根本不需要它：預覽圖是全解析度的，本來也就是相機會給你的那張 JPEG，而讀它比去馬賽克快大約一百倍。你要是要感測器資料，先在 RAW 轉換器裡衝一遍，再把它給出的 TIFF 或者 JPEG 拿來堆疊，這個工具也收那些。

### 它能處理多少幀？多大的？

七種手法裡有六種是流式的：只留一個累加器，每一幀恰好讀一次，所以一百幀跟兩幀佔一樣的記憶體，長的只有時間。中位數是例外，因為一組數的中間那個值，不把整組拿全就無從知道，於是它得同時抱著每一幀。二十張 2400 萬畫素差不多是 1.4 GB，沒有哪個瀏覽器給得起。碰上這種情況，圖會被切成橫條，一條一條地堆，代價是每條都要把這些幀重讀一遍。這些頁面在你按下按鈕之前就全算好並且寫出來了，所以跑得慢從來不會是個意外。

### 對齊到底做了什麼？

它算出每一幀相對基準幀偏了多少，再把它挪回去，精度到一個畫素的幾分之一。用的方法是相位相關：兩張圖之間的位移，在它們的頻譜之間表現為一個相位差，所以各做一次傅立葉變換，找兩百畫素的偏移和找兩畫素的一樣便宜。第二檔設定把同一個把戲用在對數極座標下的頻譜上，連旋轉和縮放也一起還原。這些都是全域性的，整幀一個位移、一個角度、一個縮放。所以它能糾正動了的相機，糾正不了動了的被攝體，也糾正不了往左挪了一步再拍的那一張。有一個看得見的後果：往左挪了二十畫素的一幀，右邊緣夠不到了，所以結果會裁到每一幀都覆蓋到的那塊。對齊過的堆疊比進去的幀略小一點，原因就在這裡，而這也是不讓畫面出現一圈由缺幀造成的黑邊的唯一辦法。

### 我該用哪種手法？

什麼都沒動的一組，要消雜訊就用**平均值**，它把隨機雜訊大約按幀數的平方根壓下去。要去掉只在一部分時間裡出現過的東西，用**中位數**，最經典的用法就是把一個人來人往的廣場拍上十幾張，然後得到一個空廣場。兩樣都想要，用 **Sigma 裁剪**：它先學出每個畫素通常是什麼，再只對跟這個說法一致的數值取平均，於是既有中位數那種對開過去的車的免疫，也有平均值那種消噪能力。星軌、煙花和光繪用**最亮**。要去掉任何動過的亮東西，用**最暗**。要模擬一次長曝光，用**相加**。沿著對焦環拍的微距，用**景深合成**。

### 我的 RAW 是十四位的，為什麼結果是八位？

因為被堆的是相機自己的預覽圖，而那是一張 JPEG。不過值得說一句：堆疊能把這筆代價找回來一部分。十六張八位的幀取平均，得到的層次確實比其中任何一張都細，因為正是那個讓每一幀四捨五入得不一樣的雜訊，才讓平均值能落在兩級之間。這裡的算術是用浮點做的，只在最後一步取整一次，所以中間沒有丟掉任何東西。它終究還是不等於堆疊線性的感測器資料，這個工具也不裝作是。

### 尺寸不同的幀，或者不同相機的幀，能堆嗎？

能，不過那通常是個誤會，值得確認一下你真是這個意思。結果的尺寸取最大的那一幀，其餘每一幀都縮放到能放進去並居中。混相機也就混了色彩的解釋，所以兩者的平均值，是對同一束光的兩種不同解釋的平均值。真正用得上的場合，是一組用兩種解析度拍的，或者同一幀的 RAW 檔案和 JPEG。

### 它說這一次會分條跑，什麼意思？

意思是這種手法需要的工作記憶體，超過了這個工具願意一次性申請的量，所以圖會被切成橫條，一條一條地堆。結果完全一樣，只是每條都要把這些幀重讀一遍，所以更慢，而頁面會告訴你那會是多少次解碼。把工作解析度降一檔，記憶體就變成四分之一，幾乎總能把分條跑變回一遍跑完，而且提示裡也寫了換哪一檔就行。

### 為什麼只有這個工具用 Worker，別的都不用？

因為只有它的工作是按分鐘算的。本站其他每一個工具做的事都是一兩秒的量，把活挪出主執行緒只是走個過場。堆二十張大幀是在幾百 MB 上做紮實的算術，放在主執行緒上就意味著一個卡死的頁面：進度條不動，取消按鈕不應，最後瀏覽器出來問要不要關掉這個分頁。Worker 是同一個瀏覽器裡的第二條執行緒，跑的是同一個資料夾裡的檔案，受的是同一套策略。它不是伺服器，也不是聯網功能。

### 免費嗎？要註冊嗎？

免費，沒有帳號，不用登入，沒有試用期，也沒有水印。堆多少幀、幀有多大都沒有限制，因為根本沒有伺服器在為它掏錢，工作是在你自己的機器上乾的，天花板只有你自己的記憶體。本站靠廣告養活，廣告那邊拿不到關於你照片的任何東西。

## 這條隱私承諾怎麼核實

- **你的照片沒有地方可去。** Content-Security-Policy 裡寫著這一頁能聯絡的每一個地址，沒有一個屬於本站。這裡沒有一個能收集你檔案的介面，就算有，程式碼裡也沒有任何東西會把它們送出去。`src/` 裡沒有，worker 裡也沒有 `fetch`、`XMLHttpRequest` 或者 `sendBeacon`。
- **RAW 檔案是被讀，不是被上傳，而且只讀了一點點。** 相機的 RAW 檔案裡本來就有一張相機在按下快門那一刻渲染好的原尺寸 JPEG。這個工具走幾條目錄項把它找出來，然後只要其中一段，在一個 60 MB 的檔案上通常不到一百 KB。你運作的時候，頁面會一直把這個數字擺在你檔案的大小旁邊。感測器資料根本一次都沒讀過。
- **工作是在這臺機器的 Worker 裡乾的，不是在伺服器上。** 這是本站唯一用 worker 的工具，因為堆疊是幾分鐘的算術而不是幾秒，而一個卡死的頁面既顯示不了進度也沒法被取消。Worker 是同一個瀏覽器裡的第二條執行緒，看 `src/worker.js`。交給它的是檔案本身，這不花什麼代價，因為檔案控制代碼不是那些位元組；而它受著和頁面完全一樣的 Content-Security-Policy，也就是說無處可送。
- **關於這一組，沒有向任何地方報告過什麼。** 你堆了幾幀、是哪臺相機寫的、每一幀偏了多少、你選了哪種手法、花了多久，這些都留在這一頁的記憶體裡，直到你關掉它。本儲存庫裡沒有任何一個自定義分析事件會帶走其中一星半點，而本站在下載之後問的那一個問題，送出去的是一個大拇指的方向和工具的名字，別的什麼都沒有。
- **斷網也能用。** 把網路斷掉，這個工具一點不變，因為它裡面從來就沒有聯網那一步。worker 和它載入的每一個模組都由這一頁自己的 service worker 快取著，所以裝下來的那一份，拔了網線照樣能堆 RAW 檔案。

**你可以自己核對。**上面這些不用你信。這個頁面是儲存庫裡的模板和配置產生出來的，構建指令碼你能讀，也能自己跑一遍，跑出來的結果就提交在 `dist` 分支上。拿實際發給你的內容，跟你自己從原始碼構建出來的結果對一遍就知道了： https://github.com/A-Box-of-Tools/website

最值得先讀的幾個檔案：`config/site.toml` 裡是 Content-Security-Policy，RAW 檔案是怎麼只讀幾十 KB 而不是幾十 MB 就開啟的，看 `src/raw.js`；每種手法的算術在 `src/stack.js`；頁面上那些記憶體和解碼次數的數字是從哪來的，看 `src/plan.js`。那些是那個檔案算出來的答案，不是估計。
