SLOHERO
07

PHOTOSHOT / DEVELOPMENT JOURNAL

그림자는 차갑게,
중간톤은 따뜻하게

배경의 푸른 기운을 남기면서 얼굴에는 따뜻한 색을 더하고 싶었습니다. 색상균형에서는 어두운 영역, 중간톤, 밝은 영역의 설정을 따로 저장하고 RGB 채널에 적용합니다.

조정 레이어 07 · 색상균형
2026.10.01 · SLOHERO · 공개 코드 v0.16.0 기준
보정 전색상균형 보정 전 AI 생성 인물 예시
보정 후색상균형 보정 후 AI 생성 인물 예시
사진과 패널은 기존 릴스 제작 자료입니다. AI 생성 인물 사진을 사용했으며, 계산 도표와 수치는 공개 코드 v0.16.0을 별도로 실행해 확인했습니다.

슬라이더는 세 개지만 저장되는 색상값은 아홉 개입니다. 07편에서는 이 설정이 실제 픽셀 계산으로 이어지는 과정과 ‘명도 유지’ 옵션의 동작을 살펴봅니다.

  1. 01세 영역의 설정을 한 레이어에 저장하기
  2. 02RGB별 검정점·흰색점·감마 구하기
  3. 03같은 회색도 밝기에 따라 다른 색이 됩니다
  4. 04명도 유지 옵션에 따른 계산 차이
  5. 05기능 설명과 실제 구현을 구분해서 기록하기
01

세 영역의 설정을 한 레이어에 저장하기

릴스에서는 중간톤의 빨강을 +14, 파랑을 −12로 바꿨습니다. 어두운 영역은 빨강 −6·파랑 +10, 밝은 영역은 빨강 +8·파랑 −6입니다. 초록은 세 영역 모두 0으로 두었습니다.

화면에서 명암 영역을 바꾸면 해당 영역의 설정을 불러옵니다. 코드에는 shadowsR, midtonesR, highlightsR처럼 영역과 채널을 붙인 이름으로 저장했습니다. 각 값의 범위는 −100~100입니다.

영역 선택은 편집할 설정 묶음을 고르는 기능입니다. 얼굴이나 배경을 직접 선택하는 것은 아니므로, 특정 피사체에만 적용하려면 마스크를 함께 사용합니다.

릴스 최종 설정 · 명도 유지 켬. 오른쪽 패널은 중간톤 편집 화면입니다.
영역빨강초록파랑
어두운 영역-6010
중간톤140-12
밝은 영역80-6
중간톤 빨강14 파랑-12 명도 유지 켬 색상균형 패널
실제 조작 화면. 설정을 바꾸는 영역과 사진에서 효과가 나타나는 영역은 구분해서 봐야 합니다.
02

RGB별 검정점·흰색점·감마 구하기

현재 새 레이어는 revision 2 계산을 사용합니다. 명도 유지가 켜져 있으면, 각 채널의 어두운 영역 설정을 검정점으로, 밝은 영역 설정을 흰색점으로 바꿉니다. 중간톤 설정은 감마에 들어갑니다.

이때 슬라이더값을 그대로 픽셀에 더하지 않습니다. 어두운 영역의 최댓값, 밝은 영역의 최솟값, 중간톤의 최댓값과 최솟값 사이 중심을 먼저 구합니다. 다른 채널과 얼마나 차이가 나는지가 계산에 반영됩니다.

black = shMax - v['shadows' + key];
white = 255 - v['highlights' + key] + hiMin;
gamma = 2 ** (
  (v['midtones' + key] - midCenter) / 100
);

예제의 중간톤 중심은 (14 + −12) ÷ 2 = 1입니다. 따라서 빨강 감마는 2의 0.13제곱, 파랑 감마는 2의 −0.13제곱이 됩니다. 표의 감마는 소수 넷째 자리까지 표시했습니다.

왼쪽의 릴스 설정을 실제 revision 2 식에 대입했습니다. 검정점과 흰색점은 0~255 입력 기준입니다.
채널검정점흰색점감마
R162411.0943
G102490.9931
B02550.9138
03

같은 회색도 밝기에 따라 다른 색이 됩니다

구한 검정점과 흰색점으로 채널의 범위를 다시 잡고, 감마를 적용합니다. 아래 x는 0~1로 바꾼 채널값입니다. 분모는 최소 1로 제한해 0으로 나누는 경우를 막았습니다.

const normalized = clamp(
  (x * 255 - black) / Math.max(1, white - black)
);
const result = normalized ** (1 / gamma);

오른쪽은 서로 다른 밝기의 회색 세 개를 같은 설정으로 처리한 결과입니다. 회색이기 때문에 입력의 R·G·B는 같지만, 출력에서는 각 채널의 곡선에 따라 차이가 생깁니다.

‘명도 유지’라는 이름만 보고 밝기 수치가 항상 정확히 같다고 해석하면 안 됩니다. 이 분기는 채널 간 상대값으로 검정점·흰색점·감마를 조정하며, 매 픽셀의 휘도를 일정하게 고정하는 별도 보정은 하지 않습니다.

회색64 128 192에 색상균형 설정을 적용한 RGB 색상표
8비트 RGB 계산 결과. 켬과 끔은 다른 계산 경로입니다. 사진의 특정 지점에서 추출한 값이 아닌 설명용 표본입니다.
04

명도 유지 옵션에 따른 계산 차이

명도 유지 옵션을 끄면, 미리 측정해 둔 색 변화 데이터를 적용합니다. 코드의 순서는 밝은 영역 → 중간톤 → 어두운 영역입니다. 앞 단계의 출력이 다음 단계의 입력으로 들어갑니다.

for (let zone = 2; zone >= 0; zone--) {
  out[c] = sampleResponse(
    balanceResponse[zone],
    v[['shadows', 'midtones', 'highlights'][zone]
      + key],
    -100, out[c]
  );
}

응답 자료 파일의 주석에는 Photoshop 27.3.1의 합성 밝기 단계 이미지를 측정한 RGB8 응답이라고 기록되어 있습니다. Adobe가 공개한 내부 알고리즘이 아니라 이 프로젝트에 저장된 측정 자료입니다.

  1. 채널값 읽기현재 픽셀의 R·G·B를 각각 처리합니다.
  2. 영역별 표 적용밝은 영역의 결과를 중간톤으로, 중간톤 결과를 어두운 영역으로 넘깁니다.
  3. 표 사이 계산입력 밝기와 설정값에 맞는 응답을 보간합니다.
  4. 범위 제한최종 채널값을 0~1로 제한하고 픽셀에 기록합니다.
05

기능 설명과 실제 구현을 구분해서 기록하기

Adobe 문서에서는 명암 영역별 색 조절과 명도 유지 옵션의 목적을 확인했습니다. 포토샷의 계산식은 저장소의 구현을 기준으로 설명했습니다. 같은 이름의 옵션이라도 내부 계산과 모든 색 공간에서의 결과까지 같다는 뜻은 아닙니다.

예전 프로젝트를 열 때는 기존 계산을 사용하도록 revision 분기를 남겼습니다. 조정 레이어의 계산을 개선하더라도 저장해 둔 사진이 갑자기 다른 색으로 보이지 않도록 하기 위한 구조입니다.

이번 글의 표본은 새 레이어를 만드는 함수로 생성해 계산했습니다. 원래 구현과 측정 자료의 위치를 아래에 연결해 두었으니, 식과 표본을 함께 확인할 수 있습니다.

조정 레이어의 설정과 픽셀 계산은 adjustments.ts에서 확인할 수 있습니다.
구분코드에서 확인할 부분
설정세 영역 × RGB = 9개 값
명도 유지 켬채널별 검정점·흰색점·감마
명도 유지 끔영역별 측정 응답표
이전 파일revision에 따른 기존 계산 유지

구현 코드와 참고 자료

공개 코드는 구현을 설명하기 위한 참조입니다. 사용·배포 조건은 저장소의 라이선스 표기를 확인하세요. 사진·패널은 자체 제작 자료, 장식 이미지는 AI 생성 이미지입니다.