# 이미지 스택 — 연사를 합치기, RAW 파일까지

스무 장을 한 장으로. 스무 번의 업로드도, RAW 변환기도 없이.

> 연사로 찍은 사진을 한 장으로 합칩니다. 평균을 내서 노이즈를 죽이고, 중앙값으로 장면에서 사람을 지우고, 밝게 합쳐 별 궤적을 만들고, 접사를 포커스 스태킹합니다. CR2, NEF, ARW, DNG, RAF, CR3은 카메라가 넣어 둔 미리보기를 꺼내어 읽습니다. 전부 브라우저 안에서 돌아갑니다.

이 페이지는 브라우저 안에서만 동작하는 대화형 도구입니다(https://abox.tools/ko/이미지-스택/). 도구에 넘긴 어떤 것도 업로드되지 않습니다. 아래는 이 페이지가 도구에 대해 글로 설명하는 내용 전부입니다. 도구를 쓰려면 이 주소를 여세요.

## 사진은 **절대 업로드되지 않습니다**. 서버가 아예 없으니까요.

프레임을 열고, 디코딩하고, 정렬하고, 합치고, 쓰는 일은 모두 이 브라우저가 이 기기에서 합니다. 60 MB짜리 RAW 파일 스무 장이면 사진 1기가바이트쯤인데, 그 가운데 한 바이트도 움직이지 않습니다. 이 도구에는 네트워크 기능이 아예 없고, 파일은 어디로도 보낼 곳이 없는 worker가 디스크에서 바로 읽습니다.

- ✗ 업로드 없음
- ✗ 계정 없음
- ✗ 워터마크 없음
- ✓ RAW 읽기
- ✓ 오프라인 작동
- ✓ 오픈 소스

## 브라우저에서 여러 장의 사진을 스택하는 법

1. **프레임을 고르십시오.** 연사든, 브래킷 묶음이든, 인터벌 촬영이든, RAW 파일이 든 폴더든 좋습니다. 들어오는 대로 하나씩 열고, 그 줄이 무엇이 나왔는지 말해 줍니다. RAW 파일이라면 카메라 기종, 안에서 찾은 미리보기의 크기, 그리고 그것을 찾는 데 파일을 얼마나 조금 읽었는지입니다.
2. **무엇을 잃고 싶은지에 맞는 방법을 고르십시오.** 노이즈라면 평균, 무언가 움직였다면 시그마 클리핑입니다. 사람이나 자동차나 지나가는 비행기라면 중앙값입니다. 어두운 하늘을 별 궤적으로 만들고 싶다면 밝게입니다. 포커스 링을 돌려 가며 찍은 접사라면 포커스 스태킹입니다. 메뉴 아래의 설명이 당신이 가진 장수에 대해 각 방법이 무엇을 하는지 말해 줍니다.
3. **프레임을 정렬해야 하는지 정하십시오.** 손으로 들고 찍었다면 예, 이동만입니다. 손으로 들고 돌리기까지 했다면 이동과 회전과 배율입니다. 고정된 삼각대나 인터벌 촬영이라면 아니오이고, 그쪽이 빠릅니다. 모든 프레임은 기준으로 표시된 장에 견주어 재고, 달리 말하기 전까지는 첫 장이 그 기준입니다. “기준으로 삼기”는 표시만 옮기고 목록의 순서는 그대로 둡니다.
4. **네 숫자를 읽고 버튼을 누르십시오.** 무엇이 돌기 전에 페이지가 결과가 얼마나 클지, 메모리가 대략 얼마나 들지, 프레임을 몇 번 디코딩할지, 파일을 얼마나 읽었는지를 말해 줍니다. 이 묶음이 메모리에 한 번에 들어가지 않으면 그렇다고 말하고, 어느 작업 해상도면 해결되는지도 말해 줍니다.

## 자세한 설명

[노이즈를 줄이거나 사람을 없애려고 사진을 스택하는 법](https://abox.tools/ko/가이드/사진-스택으로-노이즈-줄이기/): 스택은 연사로 찍은 여러 장을 한 장으로 합칩니다. 어느 방법을 쓸지는 무엇을 잃고 싶은지에 달렸습니다. 노이즈인지, 지나가는 사람인지, 접사의 얕은 심도인지. 각 방법이 어떻게 돌아가고, 무엇을 치르며, RAW 파일은 어디에 들어맞는지.

## 상자 속 다른 도구

- [이미지 가리기](https://abox.tools/ko/이미지-가리기/): 가린 부분은 파일에서 지워집니다. 파일 안에 숨겨 두는 것이 아닙니다.
- [EXIF 확인 및 제거](https://abox.tools/ko/exif-정보-삭제/): 사진이 나에 대해 뭘 흘리고 있는지 확인하고, 빼냅니다.
- [DICOM 뷰어](https://abox.tools/ko/dicom-뷰어/): CT, MRI, 엑스레이, 초음파를 창과 헤더와 계측까지.
- [이미지를 ICO로](https://abox.tools/ko/파비콘-만들기/): 그림 하나를 넣으면, 브라우저와 윈도우와 맥이 요구하는 모든 크기가 나옵니다.

## 자주 묻는 질문

### 제 사진이 어딘가로 업로드되나요?

아닙니다. 프레임을 열고 디코딩하고 정렬하고 스택하고 쓰는 일은 모두 이 브라우저가 이 기기의 하드웨어에서 합니다. 이 도구에는 네트워크 기능이 아예 없어서 무엇을 가져오지도, 보내지도 않습니다. 그리고 페이지의 `Content-Security-Policy`에는 접속할 수 있는 주소가 모두 적혀 있는데 그중 이 사이트의 것은 하나도 없습니다. 페이지를 한 번 불러온 다음 인터넷을 끊어도 그대로 동작합니다. 여기서 그것이 다른 도구들보다 더 중요한 이유는 그저 양 때문입니다. RAW 프레임 스무 장이면 1기가바이트쯤이고, 평균을 내려고 사진 1기가바이트를 올리는 일이야말로 이 도구가 피하려고 있는 것입니다.

### 어떤 RAW 포맷을 읽을 수 있고, 어떻게 읽나요?

CR2, CR3, NEF, NRW, ARW, SR2, SRF, DNG, ORF, RAF, RW2, PEF, SRW, 3FR, IIQ, DCR, KDC, MRW, MEF, RWL 등입니다. 카메라가 쓰는 것의 거의 전부입니다. 거기서 읽는 것은 촬영 순간 카메라 자신이 만든 전체 크기 JPEG 미리보기입니다. 카메라 뒷면에 보이는 그 영상이고, 운영체제가 축소판으로 그리는 그 영상입니다. 파일의 디렉터리 구조를 훑어서 찾는데 몇 킬로바이트짜리 읽기를 몇 번 하는 값이 들고, 그다음 한 조각을 가져옵니다. **센서 데이터의 디모자이킹이 아닙니다.** 결과는 카메라의 화이트 밸런스와 픽처 스타일이 적용된 채널당 8비트이고, RAW 변환기가 줄 12비트나 14비트의 선형 센서 데이터가 아닙니다.

### 그러면 센서 데이터를 제대로 디코딩하지 않는 이유는요?

LibRaw나 dcraw를 함께 싣는다는 뜻이 되기 때문입니다. 포맷 한 계열을 위한 수십 메가바이트짜리 두 번째 엔진이고, 그 대부분이 제조사별 압축 방식입니다. 그 맞바꿈은 이 사이트 소스의 `docs/what-can-be-built-here.md`에서 다투어져 있고, 카메라 RAW는 이 도구가 있기도 전부터 제외 목록에 올라 있었습니다. 달라진 것은 그 질문에 대한 답이 아니라, 스택에는 그것이 필요 없다는 발견입니다. 미리보기는 전체 해상도이고, 어차피 카메라가 JPEG으로 주었을 바로 그 영상이며, 그것을 읽는 것이 디모자이킹보다 백 배쯤 빠릅니다. 센서 데이터가 필요하다면 먼저 RAW 변환기에서 현상한 다음 그것이 내놓는 TIFF나 JPEG을 스택하십시오. 이 도구는 그것들도 받습니다.

### 몇 장까지, 얼마나 큰 것까지 다룰 수 있나요?

일곱 방법 가운데 여섯은 흘려보냅니다. 누산기 하나만 들고 각 프레임을 정확히 한 번씩 읽으므로, 백 장이 두 장과 같은 메모리를 쓰고 늘어나는 것은 시간뿐입니다. 중앙값이 예외인데, 어떤 묶음의 가운뎃값은 전부 가지기 전에는 알 수 없기 때문에 모든 프레임을 한꺼번에 들고 있습니다. 2400만 화소 스무 장이면 1.4 GB쯤이고, 그것을 내주는 브라우저는 없습니다. 그럴 때는 이미지를 가로 띠로 잘라 한 띠씩 스택하는데, 띠마다 프레임을 다시 읽는 값이 듭니다. 페이지는 버튼을 누르기 전에 이것을 모두 계산해서 숫자로 보여 주므로, 느린 실행이 놀랄 일이 되지 않습니다.

### 프레임 정렬은 실제로 무엇을 하나요?

각 프레임이 기준 장에 대해 얼마나 움직였는지 찾아 픽셀 이하 단위로 되돌립니다. 방법은 위상 상관입니다. 두 이미지 사이의 이동은 두 스펙트럼 사이의 위상 차로 나타나므로, 각각 푸리에 변환을 한 번씩만 하면 200픽셀 어긋남도 2픽셀 어긋남만큼 싸게 찾습니다. 두 번째 설정은 같은 요령을 로그-극좌표 스펙트럼에 적용해 회전과 배율까지 되살립니다. 모두 전역적입니다. 프레임 전체에 대해 이동 하나, 각도 하나, 배율 하나입니다. 그래서 움직인 카메라는 고치지만 움직인 피사체는 고치지 못하고, 한 걸음 왼쪽에서 찍은 사진도 고치지 못합니다. 눈에 보이는 결과가 하나 있습니다. 왼쪽으로 스무 픽셀 옮긴 프레임은 더 이상 오른쪽 끝에 닿지 않으므로, 결과는 모든 프레임이 덮는 부분까지 잘립니다. 정렬한 스택이 들어간 프레임보다 아주 조금 작게 돌아오는 이유이고, 없던 프레임으로 만들어진 검은 테두리를 피하는 유일한 방법입니다.

### 어느 방법을 써야 하나요?

아무것도 움직이지 않은 묶음의 노이즈에는 **평균**입니다. 무작위 노이즈를 프레임 수의 제곱근만큼 줄입니다. 일부 시간에만 있던 것을 없애려면 **중앙값**입니다. 붐비는 광장을 열두 번쯤 찍어 텅 빈 광장을 얻는 고전적인 용법이 그것입니다. 둘 다 원하면 **시그마 클리핑**입니다. 각 픽셀이 보통 무엇인지 배운 다음 그것과 맞는 값만 평균 내므로, 지나가는 자동차에 대한 중앙값의 면역과 평균의 노이즈 감소를 함께 얻습니다. 별 궤적과 불꽃놀이와 라이트 페인팅에는 **밝게**입니다. 움직인 밝은 것을 없애려면 **어둡게**입니다. 긴 노출 하나를 흉내 내려면 **더하기**입니다. 포커스 링을 돌려 가며 찍은 접사에는 **포커스 스태킹**입니다.

### RAW 파일이 14비트인데 결과는 왜 8비트인가요?

스택되는 것이 카메라 자신의 미리보기이고 그것이 JPEG이기 때문입니다. 다만 스택이 그 값의 일부를 되찾아 준다는 점은 말해 둘 만합니다. 8비트 프레임 열여섯 장의 평균은 그중 어느 한 장보다 실제로 더 고운 계조를 가집니다. 각 프레임의 반올림을 서로 다르게 만든 그 노이즈야말로 평균이 단계 사이에 내려앉게 해 주는 것이기 때문입니다. 여기서 산술은 부동소수점으로 하고 맨 끝에서 한 번만 반올림하므로, 중간에 버려지는 것은 없습니다. 그래도 선형 센서 데이터를 스택하는 것과 같지는 않고, 이 도구는 그런 척하지 않습니다.

### 크기가 다른 프레임이나 다른 카메라의 프레임을 스택할 수 있나요?

됩니다. 다만 대개는 실수이고, 정말 그러려던 것인지 확인해 볼 만합니다. 결과는 가장 큰 프레임의 크기가 되고, 나머지 프레임은 맞게 배율을 바꿔 가운데 놓입니다. 카메라를 섞으면 색 표현도 섞이므로, 둘의 평균은 같은 빛에 대한 서로 다른 두 해석의 평균이 됩니다. 정말 도움이 되는 경우는 두 해상도로 찍은 묶음이나, 같은 장면의 RAW 파일과 JPEG입니다.

### 실행이 띠로 나뉜다고 나옵니다. 무슨 뜻인가요?

그 방법에 필요한 작업 메모리가 이 도구가 한 번에 잡으려는 양보다 많다는 뜻입니다. 그래서 이미지를 가로 띠로 잘라 한 띠씩 스택합니다. 결과는 정확히 같습니다. 다만 띠마다 프레임을 다시 읽으므로 오래 걸리고, 그것이 디코딩 몇 번이 되는지를 페이지가 말해 줍니다. 작업 해상도를 한 단계 낮추면 메모리가 4분의 1이 되고, 띠로 나뉘던 실행이 거의 언제나 한 번에 끝나는 실행으로 돌아옵니다. 어느 설정이 그렇게 하는지 설명에 나옵니다.

### 왜 이 도구만 Worker를 쓰나요?

일이 분 단위로 재어지는 유일한 도구이기 때문입니다. 여기 있는 다른 도구는 모두 1, 2초짜리 일을 하고, 거기서 일을 주 스레드 밖으로 옮기는 것은 형식일 뿐입니다. 큰 프레임 스무 장을 스택하는 것은 수백 메가바이트에 걸친 빽빽한 산술이고, 주 스레드에서 그것은 얼어붙은 페이지를 뜻합니다. 진행 막대는 움직이지 않고, 취소 버튼은 답하지 않으며, 끝내는 브라우저가 탭을 닫겠다고 나섭니다. Worker는 바로 이 브라우저 안의 두 번째 실행 흐름이고, 바로 이 폴더의 파일을, 바로 이 정책 아래에서 돌립니다. 서버도 아니고 네트워크 기능도 아닙니다.

### 무료인가요? 계정이 필요한가요?

무료이고, 계정도 로그인도 체험판도 워터마크도 없습니다. 몇 장을 스택하든, 얼마나 크든 제한이 없습니다. 그 값을 치르는 서버가 없기 때문입니다. 일은 이 기기에서 일어나고 천장은 이 기기의 메모리뿐입니다. 이 사이트는 광고로 운영되고, 광고 쪽에는 사진에 대한 것이 전해지지 않습니다.

## 이 약속을 직접 확인하는 방법

- **사진이 갈 곳이 없습니다.** Content-Security-Policy에는 이 페이지가 접속할 수 있는 주소가 모두 적혀 있고, 그중 이 사이트의 것은 하나도 없습니다. 파일이 모일 만한 엔드포인트가 여기에는 없고, 설령 있다 해도 그것을 보낼 코드가 없습니다. `src/`에도 worker에도 `fetch`도, `XMLHttpRequest`도, `sendBeacon`도 없습니다.
- **RAW 파일은 업로드되는 것이 아니라 읽힙니다. 그것도 아주 조금만.** 카메라 RAW 파일 안에는 촬영 순간 카메라가 만들어 넣은 전체 크기 JPEG이 이미 들어 있습니다. 이 도구는 디렉터리 항목 몇 개를 훑어 그것을 찾은 다음 한 조각만 달라고 하는데, 60 MB 파일에서 보통 100킬로바이트가 안 됩니다. 작업하는 동안 페이지가 그 숫자를 파일 크기 옆에 보여 줍니다. 센서 데이터는 아예 읽지 않습니다.
- **일은 서버가 아니라 이 기기의 Worker에서 일어납니다.** 여기서 worker를 쓰는 도구는 이것뿐입니다. 스택은 몇 초가 아니라 몇 분짜리 산술이고, 얼어붙은 페이지는 진행 상황을 보여 줄 수도 취소될 수도 없기 때문입니다. Worker는 바로 이 브라우저 안의 두 번째 실행 흐름입니다. `src/worker.js`를 보십시오. 거기에 파일 자체를 건네는데, 파일에 대한 참조는 바이트가 아니므로 그것은 공짜입니다. 그리고 페이지와 똑같은 Content-Security-Policy를 따릅니다. 곧 보낼 곳이 없다는 뜻입니다.
- **이 묶음에 대해 어디에도 알려지는 것이 없습니다.** 몇 장을 스택했는지, 어느 카메라가 썼는지, 각 장이 얼마나 움직였는지, 어느 방법을 골랐는지, 얼마나 걸렸는지는 페이지를 닫을 때까지 이 페이지의 메모리에 있을 뿐입니다. 이 저장소에는 그 가운데 무엇도 실어 나르는 별도의 분석 이벤트가 없고, 이 사이트가 다운로드 뒤에 묻는 단 하나의 질문은 엄지 방향과 도구 이름을 보낼 뿐 그 밖에는 아무것도 보내지 않습니다.
- **오프라인에서 작동합니다.** 네트워크를 끊어도 이 도구는 그대로입니다. 애초에 네트워크 단계가 없었기 때문입니다. worker와 그것이 불러오는 모든 모듈은 이 페이지 자신의 service worker가 캐시해 두므로, 설치해 둔 사본은 네트워크를 뽑은 채로도 RAW 파일을 스택합니다.

**직접 확인해 보세요.** 위에 적은 어느 것도 그냥 믿으실 필요는 없습니다. 이 페이지는 저장소 안의 템플릿과 설정을 빌드 스크립트가 찍어 낸 결과이고, 그 스크립트는 누구나 읽고 직접 돌려 볼 수 있습니다. 결과물은 `dist` 브랜치에 그대로 올라가 있고요. 그래서 실제로 제공되는 파일과 소스를 빌드한 결과를 나란히 놓고 비교해 보실 수 있습니다: https://github.com/A-Box-of-Tools/website

먼저 읽어 볼 파일을 꼽자면, Content-Security-Policy는 `config/site.toml`, RAW 파일을 메가바이트가 아니라 킬로바이트만 읽어서 여는 방법은 `src/raw.js`, 각 방법의 산술은 `src/stack.js`, 그리고 페이지에 나오는 메모리와 디코딩 횟수가 어디서 오는지는 `src/plan.js`입니다. 그것들은 그 파일이 내놓는 답이지 어림값이 아닙니다.
