Illustracy

Illustracy — 4. 알고리즘과 수식 (3/4): 영역 · 재질 · 톤 · 파츠 · 역산 · 저장 · 검증

← README · 4절 1 · 2 · 3 · 4 · English


4.6 영역과 재질

\mathrm{shadeRelated}(c_1,c_2)=
\begin{cases}
\text{참} & \Delta E<\varepsilon_s\\
|L_1-L_2|<3\varepsilon_s & C_1<12,\ C_2<12\\
|h_1-h_2|<\varepsilon_h,\ \ 0.3< C_1/C_2<3.3 & C_1\ge 12,\ C_2\ge 12\\
\text{아래 규칙} & \text{한쪽만 무채색}
\end{cases}
\qquad \varepsilon_h=14+40m,\ \ \varepsilon_s=5+12m

풀이 — 왜: 같은 재질의 명암은 밝기와 채도는 바뀌어도 색상은 거의 그대로입니다. 이 성질로 두 색이 같은 재질의 명암 관계인지 판정합니다. 원리: 가까운 색($\Delta E < \varepsilon_s$)은 언제나 같은 재질입니다. 둘 다 무채색($C < 12$)이면 색상이 뜻이 없으므로 밝기 차만 봅니다. 둘 다 유채색이면 LCh의 색상각 차 $< \varepsilon_h$와 채도 비 0.3~3.3을 봅니다(그림자는 채도를 바꿔도 몇 배 넘게 바꾸지 않음). 허용치는 병합 강도 𝑚의 1차식이라 기본값에서 $\varepsilon_h = 34^\circ$, $\varepsilon_s = 11$입니다. 참고: R7 CIE 2004 · R10 Fairchild 2013 · 이 프로그램에서 정한 규칙

한쪽만 무채색이면(𝑛: $C < 12$인 쪽, 𝑐: 다른 쪽) 다음을 봅니다.

4.7 톤, 밑색, 그림자, 하이라이트

4.8 파츠 정리

$\mathrm{minPart} = \max(64, 0.0015N)$. 처음에는 재질 하나가 파츠 하나이고, 파츠의 넓이는 불투명 픽셀 수, 대표색은 파츠 안에서 가장 넓은 재질의 밑색입니다. 파츠 사이 경계 길이는 가로 · 세로로 이웃한 픽셀 쌍 중 두 파츠에 걸친 쌍의 수입니다.

  1. 넓이 $\ge \mathrm{minPart}$인 파츠를 넓은 순서로 놓고, 모든 쌍에서 대표색 $\Delta E < 6$이면 합침.
    • 풀이 — 왜: 재질이 지나치게 잘게 나뉘면 층이 너무 많아지므로, 작은 파츠는 비슷한 이웃에 합치고 거의 같은 색 파츠는 하나로 둡니다. 원리: $\mathrm{minPart} = \max(64, 0.0015N)$은 그림의 0.15%(최소 64px)입니다. 대표색 $\Delta E < 6$은 나란히 놓아도 비슷해 보이는 차이라 같은 파츠로 봅니다. 참고: R7 CIE 2004 · 이 프로그램에서 정한 규칙
  2. 파츠 경계를 긴 순서로 보며, 경계가 8픽셀 이상이고 어두운 쪽 둘레(다른 파츠와 맞닿은 경계 합)의 40% 이상이며 어두운 쪽이 밝은 쪽의 1.5배 이하 넓이일 때, 밝기 비 $r = \mathrm{lum}(\mathrm{dark})/\max(\mathrm{lum}(\mathrm{lit}), 10^{-3})$가 0.45~0.93이고, 어두운 쪽이 어느 채널에서도 밝은 쪽보다 0.03 넘게 밝지 않으며(곱하기로 만들 수 있는 색), 다음을 만족하면 그림자로 합칩니다. 단 $r < 0.6$이면서 어두운 쪽이 그림의 1% 이상으로 넓으면 합치지 않습니다(빛을 받은 갈색 머리카락과 피부. 시험 그림 25장 · 합성 48장에서 그만큼 진한 면을 그림자로 합친 것은 이 경우 말고는 모두 그림의 0.3% 미만인 작은 면이었습니다). 그다음 1을 한 번 더 합니다.
    • 풀이 — 왜: 선으로 나뉘어 따로 잡힌 그림자 면을 그 밑색 파츠에 합쳐, 같은 재질의 밝은 면과 그림자가 한 파츠가 되게 합니다. 원리: 밝기 비 $r$ 0.45~0.93과 “어느 채널도 밝은 쪽보다 0.03 넘게 밝지 않음”은 어두운 쪽을 밝은 쪽에 곱하기로 만들 수 있다는 조건입니다(곱하기는 채널마다 어둡게만 함). 맞닿은 경계가 어두운 쪽 둘레의 40% 이상이면 그 면이 밝은 면에 붙어 있습니다. 채도 조건은 두 경우로 나눕니다: 둘 다 옅으면(채도 25 미만) 채도 차와 밝기 비만, 아니면 색상각 차 30° 미만과 채도 비 0.5~2입니다. 진한(𝑟 < 0.6) 넓은 면을 빼는 것은 빛을 받은 갈색 머리카락과 피부처럼 다른 재질이 곱하기 관계로 보이는 경우를 막기 위해서입니다. 참고: R1 Porter · Duff 1984 · R7 CIE 2004 · 이 프로그램에서 정한 규칙
    • 둘 다 채도 25 미만(흰 머리카락 ↔ 연보라 그림자 같은 경우): $\lvert C_d - C_l\rvert < 18,\ r \ge 0.55$, 밝은 쪽 채도가 4 이상이면 색상각 차 50° 미만
    • 그 밖: 둘 다 채도 12 이상, 색상각 차 30° 미만, $0.5 < C_d/C_l < 2$
  3. $\mathrm{minPart}$ 미만 파츠는(작은 재질부터) 가장 길게 맞닿은 $\Delta E < 30$ 이웃에, 없으면 $\Delta E < 20$인 큰 파츠 중 가장 가까운 색에 합칩니다. 그것도 없으면 넓이가 $\mathrm{minKeep} = \max(64, 0.0001N)$ 미만일 때만 가장 길게 맞닿은 이웃에 합치고, 그보다 큰 파츠는 따로 둡니다(색이 다른 이웃에 합치면 눈동자 · 머리끈 · 넥타이의 밑색이 피부 · 머리카락 색이 되어 밑색 층에서 사라짐).
    • 풀이 — 왜: 작은 파츠를 색이 많이 다른 이웃에 합치면 눈동자 · 머리끈 · 넥타이의 밑색이 사라지므로, 색이 비슷한 이웃에만 합치고 아니면 따로 둡니다. 원리: $\Delta E < 30$인 가장 길게 맞닿은 이웃 → $\Delta E < 20$인 가장 가까운 큰 파츠 → 그래도 없으면 $\mathrm{minKeep} = \max(64, 0.0001N)$ 미만의 아주 작은 부스러기만 이웃에 붙이는 단계적 규칙입니다. 참고: R7 CIE 2004 · 이 프로그램에서 정한 규칙
  4. “작은 파츠”가 아닌 파츠 수가 최대 파츠 수 $\max(4, P)$(𝑃 기본 32)를 넘는 동안, 가장 작은 파츠를 맞닿은 파츠 중 $\Delta E < 30$인 가장 가까운 색에 합치고, 없으면 “작은 파츠”로 표시합니다.
    • 풀이 — 왜: 층 수가 지나치게 많으면 PSD를 다루기 어려워 파츠 수에 상한을 둡니다. 원리: 가장 작은 파츠부터 비슷한 색($\Delta E < 30$) 이웃에 합치기를 수가 $\max(4, P)$ 이하가 될 때까지 되풀이합니다(작은 것부터 없애는 탐욕 병합). 참고: 이 프로그램에서 정한 규칙

마지막으로 파츠를 넓은 순서로 보며 8비트로 반올림한 밑색이 앞 파츠와 $\Delta E < 2.5$이면 층을 만들 때 하나로 봅니다(사람이 구분하기 어려운 차이).

풀이 — 왜: 사람이 구분하기 어려운 색 차이로 층을 둘로 나누면 쓸모없는 층만 늘어납니다. 원리: $\Delta E < 2.5$는 CIELAB에서 겨우 구별되는 차이(약 2.3)와 비슷한 크기입니다. 8비트로 반올림한 뒤 견주어 저장될 값 기준으로 판단합니다. 참고: R8 Mahy et al. 1994

캐릭터 나누기

캐릭터 나누기와 파츠 이름은 이름 · 폴더용 얼굴(4.5 얼굴 찾기의 9, 조정한 점수)을 씁니다.

  1. 캐릭터 얼굴: 점수 11.5 이상인 얼굴(과 점수가 가장 높은 얼굴)에서, 모든 쌍이 다음을 만족하는 묶음 중 표 $\sum(\text{점수} - 10)^2$가 가장 큰 묶음.
    • 풀이 — 왜: 여러 캐릭터가 있는 그림에서 어느 얼굴들이 서로 다른 캐릭터인지 정해야 캐릭터마다 폴더를 나눌 수 있습니다. 한 캐릭터의 가짜 얼굴(무릎 · 손)이 다른 캐릭터로 잡히지 않게 해야 합니다. 원리: 표 $\max(0, \text{점수} - 10)^2$은 문턱 근처 얼굴엔 작고 확실한 얼굴엔 큰(점수 11 → 1표, 14 → 16표) 제곱 가중입니다. 모든 쌍이 크기 · 높이가 비슷하고 서로의 머리 · 몸 자리 밖이어야 하는 묶음 중 표 합이 가장 큰 것을 고르는데, 후보 8개의 부분집합 $2^8 = 256$개를 모두 보는 완전 탐색이라 늘 최적의 묶음을 찾습니다. 참고: 이 프로그램에서 정한 규칙
    • 크기(두 눈 사이) 비가 0.5~2(찾은 크기는 사람이 표시한 두 눈 사이의 0.67~1.18배로 흔들림)
    • 서로의 얼굴 틀에서 세로로 $4d$ 안(높이가 비슷함)
    • 서로의 머리 타원 · 몸 기둥(4.5의 자리 확률과 같은 모양) 밖 후보는 점수 순서로 8개까지이고, $2^8$개 이하의 부분집합을 모두 봅니다(둘 이상인 묶음이 표 합에서 가장 높은 얼굴 하나를 넘어야 채택). 얼굴이 하나만 남으면 나누지 않습니다. $\max(0, \text{점수} - 10)^2$은 문턱 근처의 얼굴보다 확실한 얼굴에 훨씬 큰 표를 줍니다(점수 11은 1표, 14는 16표).
  2. 씨앗: 얼굴마다 가운데에서 가로 · 세로 $10d$ 안에서, 한 캐릭터의 머리 타원이나 몸 기둥에만 드는 칠한 픽셀. 둘 이상의 자리에 드는 픽셀은 씨앗에서 뺍니다.
    • 풀이 — 왜: 캐릭터마다 확실히 그 캐릭터인 픽셀에서 퍼지기를 시작해야 경계가 맞습니다. 원리: 한 캐릭터의 머리 타원 · 몸 기둥에만 드는 픽셀이 씨앗이고, 두 캐릭터의 자리가 겹치는 픽셀은 어느 쪽인지 모르므로 씨앗에서 뺍니다. 참고: 이 프로그램에서 정한 규칙
  3. 퍼지기: 씨앗(거리 0)에서 칠 · 선 픽셀을 따라 4-이웃으로 퍼지며, 픽셀 𝑞로 들어가는 한 걸음 비용 $1 + \mathrm{round}(30\,{\alpha_q}^2)$(𝛼 = 선 알파)의 최단 거리로 캐릭터를 정합니다. 비용이 정수라 다익스트라 대신 버킷 큐(버킷 32개를 돌려 씀. 한 걸음 비용이 31 이하라 충분)를 씁니다. 진한 선($\alpha = 1$)은 한 칸에 31걸음 값이라 넘기 어렵습니다. 닿지 못한 픽셀(떨어진 조각, 배경)은 4-이웃 너비 우선으로 가장 가까운 캐릭터로 채웁니다.
    • 풀이 — 왜: 두 캐릭터가 맞닿은 곳에서는 사이의 진한 윤곽선이 경계입니다. 선을 건너기 어렵게 만든 최단 거리로 캐릭터를 나누면 경계가 선을 따라갑니다. 원리: 픽셀에 들어가는 비용 $1 + \mathrm{round}(30\alpha^2)$는 선 알파가 클수록 제곱으로 커져, 진한 선은 31걸음 값이라 돌아가는 편이 쌉니다. 각 픽셀은 가장 가까운(최단 경로 비용) 씨앗의 캐릭터가 됩니다. 비용이 1~31의 정수라 다익스트라 대신, 거리 값별 버킷 32개를 돌려 쓰는 버킷 큐(Dial의 방법)로 $O(V + E)$에 구합니다. 참고: R28 Dijkstra 1959 · R29 Dial 1969
  4. 캐릭터 쪽 픽셀의 5% 미만을 차지한 캐릭터는 빼고 1~3을 다시 합니다.
  5. 한 캐릭터에 64픽셀 미만인 파츠 조각은 그 파츠가 가장 많은 캐릭터로 옮깁니다(옆 캐릭터 파츠의 끝자락이 부스러기 층이 되지 않게).
  6. 캐릭터마다 그 픽셀만 담은 [선화] · [효과] · [채색]을 만듭니다. 캐릭터끼리 픽셀이 겹치지 않으므로 합성 결과는 한 폴더일 때와 같습니다.

이름 붙이기

캐릭터 얼굴(위 1의 묶음)마다 원래 해상도의 얼굴 틀 $(u, v)$(단위 𝑑, 가운데에서 가로 · 세로 $3.6d$ 안)에서 영역별로 파츠 픽셀을 셉니다. 영역이 겹치면 눈 칸 → 피부 → 앞머리 → 그 위 → 몸통 순서로 한 곳에만 셉니다(눈 자리는 따로). “칠해져 있음”은 영역 픽셀 중 파츠(배경이 아닌 칠)의 비율입니다. 무릎 · 손 · 옷 무늬 · 배경 장식의 가짜 얼굴은 그 칸이 옷 · 리본 · 소품 위에 놓여 틀린 이름을 붙이므로 쓰지 않습니다.

영역 범위
눈 칸 $0.25 \le \lvert u\rvert \le 0.75,\ \lvert v\rvert \le 0.22$
눈 자리(머리카락 후보 판정) $0.2 \le \lvert u\rvert \le 0.8,\ \lvert v\rvert \le 0.35$
피부(콧등 · 볼) $\lvert u\rvert \le 0.15,\ 0.1 \le v \le 0.5$ 또는 $0.3 \le \lvert u\rvert \le 0.7,\ 0.35 \le v \le 0.7$
앞머리 $\lvert u\rvert \le 0.8,\ -0.9 \le v \le -0.45$
그 위(이마 위 · 정수리) $\lvert u\rvert \le 0.8,\ -1.6 \le v < -0.9$
몸통 가운데 $\lvert u\rvert \le 0.8,\ 2 \le v \le 3.5$

풀이 — 왜: 얼굴의 정해진 자리에 무엇이 칠해져 있는지 보면 피부 · 머리카락 · 눈 파츠를 알아낼 수 있습니다. 원리: 얼굴 틀 좌표(눈 사이 거리 𝑑 단위)의 칸이라 얼굴 크기 · 기울기와 상관없이 같은 자리를 봅니다. 칸이 겹치면 정해진 순서로 한 곳에만 세어 한 픽셀이 두 번 표를 주지 않게 합니다. 참고: 이 프로그램에서 정한 규칙

  1. 피부 표: 피부 영역이 절반 이상 파츠로 칠해져 있을 때, 그 35% 이상을 차지한 가장 넓은 파츠.
  2. 머리카락 후보: 피부 파츠가 아니고, 넓이가 $0.3d^2$ 이상이며(흰자 위 그림자 같은 조각은 빠짐), 픽셀의 절반 이상이 눈 자리에 있지 않은 파츠(눈동자는 빠짐).
    • 풀이 — 왜: 흰자 위 그림자 같은 작은 조각과 눈동자가 머리카락으로 불리지 않게 거릅니다. 원리: 넓이 문턱 $0.3d^2$은 눈 사이 거리의 제곱에 비례해 얼굴 크기에 맞춰집니다. 참고: 이 프로그램에서 정한 규칙
  3. 머리카락 표: 앞머리 영역이 절반 이상 칠해져 있을 때, 후보 픽셀 중 40% 이상인 가장 넓은 파츠와 30% 이상인 그다음 파츠(머리색 + 광택). 후보 픽셀이 앞머리 영역의 25% 미만이면(이마가 드러남) 위 영역에서도 같은 방법으로 고릅니다(위 영역의 10% 이상이 후보일 때). 앞머리가 여러 색 파츠로 잘게 나뉘어 고르지 못한 경우에는 위 영역을 보지 않습니다(위 영역에는 모자가 많음).
  4. 피부와 머리카락이 한 파츠: 두 영역이 절반 넘게 칠해져 있고 피부 파츠가 앞머리 영역의 80% 이상, 위 영역의 90% 이상을 덮으면(창백한 얼굴 + 옅은 머리) 그 파츠에 머리카락 표도 줍니다.
  5. 옷 표시: 몸통 가운데의 25% 이상을 덮는 파츠.
  6. 눈: 점수 12 이상인 캐릭터 얼굴의 눈 칸 안 픽셀(그 얼굴의 피부 · 머리카락 표 파츠 제외)을 모든 얼굴에서 더해 30픽셀 이상이고 파츠 넓이의 절반 이상인 파츠.
  7. 표를 받은 파츠에 이름을 붙이되,
    • 픽셀의 3분의 2 넘게 캐릭터 얼굴 가운데에서 $6d$ 밖($(x - c_x)^2 + (y - c_y)^2 > 36d^2$, 세 픽셀마다 하나씩 세어 3배)에 있으면 붙이지 않습니다(바닥 · 소품과 한 색인 파츠). 긴 머리카락, 전신 그림의 다리 피부는 절반 넘게 $6d$ 밖에 있을 수 있습니다.
      • 풀이 — 왜: 바닥 · 소품이 얼굴 근처 파츠와 같은 색이라 한 파츠로 합쳐졌으면, 그 파츠에 피부 · 머리카락 이름을 붙이면 틀립니다. 원리: $(x - c_x)^2 + (y - c_y)^2 > 36d^2$는 반지름 $6d$ 원 밖이라는 뜻을 제곱근 없이 쓴 것입니다. 세 픽셀마다 하나씩 세어 3배 하는 것은 표본 추출로 시간을 줄인 것입니다. 참고: 이 프로그램에서 정한 규칙
    • 피부 표와 머리카락 표를 함께 받으면 붙이지 않습니다.
    • “피부”는 따뜻한 색일 때만, “머리카락”은 옷 표시가 없을 때만 붙입니다. 이름은 피부 → 머리카락 → 눈 순서로 봅니다. 밑색 $(r, g, b)$(0~1)에서 $\mathrm{mx} = \max,\ \mathrm{mn} = \min$일 때 따뜻한 색($\mathrm{skinLike}$)은

      $\displaystyle mx=r\ \wedge\ mx\ge0.55\ \wedge\ \big(mx-mn\ge0.07\,mx\ \vee\ \text{옅은 피부}\big)\ \wedge\ \big(g\ge b-0.02\ \vee\ b-g<0.35\,(r-\min(g,b))\big)$

      입니다(빨강 채널이 가장 밝음, 채도 7% 이상, 마지막 항은 분홍까지 받고 보라 · 파랑은 뺌). 옅은 피부($\mathrm{mx} \ge 0.85$, $\mathrm{mx} - \mathrm{mn} \ge 0.025\mathrm{mx}$)는 파츠 넓이가 $12 d_\max^2$(가장 큰 캐릭터 얼굴의 𝑑) 이하이고 $0.13N$ 이하일 때만 “피부”라고 부릅니다. 옅은 피부는 흰 옷 · 흰 머리카락과 한 파츠로 합쳐지기 쉬운데, 그러면 넓이가 얼굴 · 손 · 팔다리보다 훨씬 커지기 때문입니다.

      • 풀이 — 왜: 얼굴 자리에 있더라도 피부색이 아닌 파츠(파란 머리카락, 보라 옷)를 “피부”로 부르지 않으려면 피부다운 색인지 봐야 합니다. 원리: 빨강 채널이 가장 밝고(피부는 R > G > B 쪽) 충분히 밝으며(≥ 0.55), $\mathrm{mx} - \mathrm{mn} \ge 0.07\mathrm{mx}$는 HSV 채도 7% 이상입니다. 마지막 항은 파랑이 초록보다 많이 크지 않을 때만 받아 분홍은 들이고 보라 · 파랑은 뺍니다. 옅은 피부는 흰 옷 · 흰 머리카락과 합쳐지기 쉬워, 넓이가 얼굴 크기에 견줘 지나치지 않을($12d_\max^2$ 이하) 때만 피부로 부릅니다. 참고: R31 Smith 1978 · 이 프로그램에서 정한 규칙
  8. 뜻 이름이 붙은 파츠는 작아도 “작은 파츠” 폴더에 넣지 않습니다.
  9. 떨어진 머리카락 조각 떼기: “머리카락” 이름을 받은 파츠 𝑘마다
    • 닻: 닻 얼굴(캐릭터 얼굴과, 점수 11 이상인 모든 얼굴: 캐릭터 묶음에 들지 못한 다른 인물 · 같은 인물의 두 번째 모습)마다 머리 타원 $(u/2.2)^2 + ((v + 0.3)/2)^2 \le 1$ 안의 𝑘 픽셀에서 𝑘를 따라 4-이웃으로 닿는 픽셀을 남깁니다.
    • 가까운 조각: 남지 않은 𝑘 픽셀의 4-연결 조각 𝑐(넓이 $A_c$) 중, 캐릭터 얼굴의 몸 가운데 기둥 $\lvert u\rvert < 1 \land v > 1.5$에 드는 픽셀 수 $B_c$가 $B_c \le 0.5 A_c$이고 남은 픽셀까지의 체임퍼 거리(4.2)가 $2.5 d_\max$($d_\max$ = 가장 큰 캐릭터 얼굴의 𝑑) 이하인 픽셀이 하나라도 있는 조각을 남깁니다. 남긴 조각에서 거리를 다시 재어 새로 남길 조각이 없을 때까지, 세 번까지 되풀이합니다.
      • 풀이 — 왜: “머리카락” 파츠에 머리와 떨어진 같은 색 물건(소품, 옷 장식)이 섞이면 이름이 틀리므로 떼어 냅니다. 원리: 얼굴의 머리 타원에서 그 파츠를 따라 이어지는 픽셀(닻)을 남기고, 이어지지 않은 조각은 남은 머리카락까지의 체임퍼 거리가 $2.5d_\max$ 안이면 머리카락으로 남깁니다(묶은 머리 · 흩날린 머리카락). 몸 가운데 기둥에 절반 넘게 든 조각은 옷일 가능성이 커서 남기지 않습니다. 떼어 낸 픽셀은 같은 밑색의 새 파츠로 옮겨 층 픽셀은 바뀌지 않습니다. 참고: R21 Borgefors 1986 · 이 프로그램에서 정한 규칙
    • 남지 않은 픽셀은 밑색이 같은 새 파츠(뜻 이름 없음)로 옮깁니다. 그래서 층 픽셀과 합성 결과는 바뀌지 않습니다.
    • 새 파츠 때문에 “작은 파츠”가 아닌 파츠 수가 최대 파츠 수를 넘으면, 넘는 수만큼 새 파츠를 작은 것부터 “작은 파츠”로 표시합니다.
  10. 나머지 파츠는 밑색의 색 이름입니다. 8비트 밑색을 HSV($V = \mathrm{mx},\ S = (\mathrm{mx} - \mathrm{mn})/\mathrm{mx}$, 𝐻는 0~360°)로 바꿔 차례로 봅니다.

    조건 이름
    $V < 0.18$ 검정
    $S < 0.1$ $V > 0.9$이면 흰색, 아니면 회색
    $5^\circ \le H \le 45^\circ,\ 0.08 \le S \le 0.55,\ V \ge 0.7$(살색) $S < 0.25$이면 베이지, 아니면 살구
    $H < 15^\circ$ 또는 $H \ge 345^\circ$ $V < 0.45$ 갈색, $S < 0.5 \land V > 0.8$ 분홍, 그 밖 빨강
    $H < 40^\circ$ $V < 0.6$ 갈색, 아니면 주황
    $H < 65^\circ$ $V < 0.5$ 갈색, 아니면 노랑
    $H < 160^\circ$ · $< 200^\circ$ · $< 255^\circ$ · $< 290^\circ$ · 그 밖 초록 · 청록 · 파랑 · 보라 · 분홍

    $H = 60^\circ \times((g - b)/(\mathrm{mx} - \mathrm{mn}) \bmod 6)$($\mathrm{mx} = r$), $60^\circ \times((b - r)/(\mathrm{mx} - \mathrm{mn}) + 2)$($\mathrm{mx} = g$), $60^\circ \times((r - g)/(\mathrm{mx} - \mathrm{mn}) + 4)$($\mathrm{mx} = b$)입니다. 살색은 “베이지 · 살구”로 부르고 “피부”라고 부르지 않습니다. 살색인 머리카락(금발 · 옅은 갈색) · 꽃 · 나무 · 과자 · 방 안이 많아, 얼굴 없이 색만으로 “피부”라고 하면 대부분 틀리기 때문입니다(11). 같은 이름이 여럿이면 넓은 파츠부터 “이름”, “이름 2”, “이름 3” …입니다.

    풀이 — 왜: 뜻 이름이 없는 파츠도 색 이름을 붙이면 층 목록에서 찾기 쉽습니다. 원리: HSV는 RGB 정육면체를 색상환으로 펼친 좌표입니다. 𝑉는 가장 큰 채널, 𝑆는 $(\mathrm{mx} - \mathrm{mn})/\mathrm{mx}$, 𝐻는 가장 큰 채널이 어느 것이냐에 따라 60° 구간을 정하고 나머지 두 채널의 차로 구간 안 위치를 정합니다(빨강 0°, 초록 120°, 파랑 240°). 표는 어둡기 → 무채색 → 살색 → 색상 구간 순서로 봅니다. 참고: R31 Smith 1978 · 이 프로그램에서 정한 규칙

4.9 픽셀별 역산

파츠 𝑘, 톤 단계 𝑣의 픽셀에서 칠한 색은

x_c=F_c\cdot(sh^1_c)^{[v\ge1]}\cdot(sh^2_c)^{[v=2]}\qquad(\text{하이라이트 톤이면 }x_c=\text{톤 색})

풀이 — 왜: 역산의 출발점은 “층들이 만들어 내는 칠한 색”입니다. 톤 단계에 따라 밑색에 그림자가 몇 번 곱해졌는지가 정해집니다. 원리: $[v \ge 1]$은 참이면 1인 아이버슨 괄호라, 지수로 쓰면 조건이 거짓일 때 그 곱셈이 1(곱하지 않음)이 됩니다. 밝은 면(𝑣 = 0)은 𝐹, 1차 그림자는 $F\cdot sh^1$, 2차는 $F\cdot sh^1\cdot sh^2$입니다. 참고: R1 Porter · Duff 1984 · 이 프로그램에서 정한 규칙

복원색 $u = U_c$와 비교해 남은 어두워짐 𝐷와 밝아짐 𝑆를 구합니다. 1/255 이하의 밝아짐은 양자화 잡음으로 봅니다.

u\le x+\tfrac{1.2}{255}:\quad D_c=1-\mathrm{clamp}\!\left(\frac ux\right);\qquad
u> x+\tfrac{1.2}{255}:\quad S_c=\mathrm{clamp}\!\left(1-\frac{1-u}{1-x}\right)

곱하기 $x(1 - D) = u$, 스크린 $1 - (1 - x)(1 - S) = u$이므로 두 경우 모두 정확히 원본으로 돌아옵니다. $x \le 0.002$(거의 검정)이면 $D_c = 0$, $x \ge 0.9999$(흰색)이면 $S_c = 0$으로 두어 0으로 나누지 않습니다. $d_\max = \max_c D_c,\ S_\max = \max_c S_c$입니다. 하이라이트 톤 색은 8비트로 반올림한 값($q_8$)을 씁니다. 밑색 · 그림자 층의 알파는 원본 알파 𝐴, 반짝임 픽셀은 하이라이트가 아니라 밑색 쪽으로 칠한 뒤 밝아짐으로 뺍니다.

풀이 — 왜: 층이 만든 색과 원본의 남은 차이를 곱하기 · 스크린 층에 담아, 층을 다 합치면 원본이 정확히 돌아오게 합니다. 원리: 곱하기 $x(1 - D) = u$를 𝐷로 풀면 $D = 1 - u/x$, 스크린 $1 - (1 - x)(1 - S) = u$를 𝑆로 풀면 $S = 1 - (1 - u)/(1 - x)$입니다. 원본이 더 어두우면 곱하기, 더 밝으면 스크린이라 어느 쪽이든 하나만 쓰입니다. 1.2/255는 8비트 반올림 잡음보다 큰 밝아짐만 보는 여유이고, 𝑥가 0이나 1에 가까울 때는 0으로 나누지 않도록 그 값을 0으로 둡니다. 참고: R1 Porter · Duff 1984 · R3 ISO 32000-1 2008

4.10 그라데이션과 명암

$d_\max = \max_c D_c$에 대해, 캐릭터 밖은 1로 둔 뒤

\mathrm{env}=G_{R/2}\big(\mathrm{erode}_R(d_{max})\big),\quad R=\max(8,\,\mathrm{round}(24s)),\qquad
f=\frac{\min(d_{max},\mathrm{env})}{d_{max}}\quad(d_{max}>0)
D^{grad}_c=f\,D_c,\qquad D^{shade}_c=\mathrm{clamp}\!\left(1-\frac{1-D_c}{1-D^{grad}_c}\right)
\quad\Longrightarrow\quad (1-D^{grad}_c)(1-D^{shade}_c)=1-D_c

풀이 — 왜: 남은 어두워짐에는 넓게 천천히 바뀌는 부분(공기 원근 · 큰 명암)과 좁은 붓 터치가 섞여 있습니다. 넓은 부분을 그라데이션 층으로, 나머지를 명암 층으로 나누면 작가가 다루기 쉽습니다. 원리: 반지름 𝑅 침식은 둘레 𝑅 안의 최솟값이라 좁게 튀는 어두워짐을 지우고 넓게 깔린 바닥값(아래 포락선)만 남기고, 가우시안 흐림으로 매끄럽게 합니다. 𝑓를 모든 채널에 곱해 그라데이션은 어두워짐과 같은 색 방향입니다. 나머지는 곱하기를 거꾸로 풀어 $(1 - D^{grad})(1 - D^{shade}) = 1 - D$가 되게 하므로 두 층을 곱하면 원래 어두워짐과 같습니다. 참고: R15 Soille 2003 · R1 Porter · Duff 1984

($D^{grad}_c \ge 0.9999$이면 $D^{shade}_c = 0$.) 모든 채널에 같은 𝑓를 곱하므로 그라데이션은 어두워짐과 같은 색 방향의 일부입니다.

침식은 아래 포락선(넓게 깔린 최소 어두워짐)을, 흐림은 그것을 부드럽게 만듭니다. $\min(d_\max, \mathrm{env}) > 12/255$인 픽셀이 $\max(24, \text{캐릭터 픽셀의 }0.3\%)$보다 적으면 그라데이션 층을 만들지 않고($f = 0$) 명암 한 장으로 둡니다.

풀이 — 왜: 그라데이션이 거의 없는 그림에 빈 층을 만들지 않습니다. 원리: 12/255 넘는 그라데이션 픽셀이 24개 또는 캐릭터의 0.3%보다 적으면 층을 만들지 않습니다. $D^{grad} \ge 0.9999$에서는 나누기가 불안정해 명암을 0으로 둡니다. 참고: 이 프로그램에서 정한 규칙

4.11 밝아짐 나누기

스크린은 순서대로 겹쳐도 $1 - \prod(1 - a_i)$이므로, 가중치 𝑤로 일부를 떼어 내면

a=S\,w,\qquad S'=\mathrm{clamp}\!\left(1-\frac{1-S}{1-a}\right)\quad(a\ge0.9999\text{이면 }S'=0)\qquad\Longrightarrow\qquad 1-(1-a)(1-S')=S

을 채널마다 반복해 차례로 나눕니다($S^{(0)} = S,\ a_i = S^{(i-1)}w_i,\ S^{(i)} = S'$).

풀이 — 왜: 밝아짐 하나를 반짝임 · 림라이트 · 반사광 · 빛 여러 스크린 층으로 나눠도, 다 합치면 원래 밝아짐이 정확히 나와야 합니다. 원리: 스크린은 $1 - \prod(1 - a_i)$로 순서와 상관없이 합쳐집니다. 가중치 𝑤만큼 $a = Sw$를 떼고 나머지 $S'$를 스크린 역산으로 구하면 $1 - (1 - a)(1 - S') = S$가 항등식으로 성립합니다. 이것을 층마다 되풀이하면 모든 층의 스크린 합이 원래 𝑆입니다. 참고: R3 ISO 32000-1 2008 · R1 Porter · Duff 1984

순서 층 가중치 𝑤
1 반짝임(작은 조각) 반짝임 픽셀이거나, $S > 3/255$인 연결 조각 중 넓이 $\le 3\pi r_s^2$, 최대 $S > 0.25$, 평균 $\min_c U > 0.65$, 최대 탑햇 $> 0.12$
2 림라이트 $\mathrm{smoothstep}(R_r, 0.4R_r, e) \cdot \mathrm{clamp}((S_\max - \bar O)/S_\max)$
3 반짝임(가는 광택) $\mathrm{smoothstep}(0.08, 0.2, T) \cdot \mathrm{smoothstep}(0.55, 0.8, \min_c U_c)$
4 반사광 그림자 픽셀이면 1
5 빛 나머지 전부

풀이 — 왜: 밝아짐의 종류마다 생김새가 다르므로(반짝임은 작고 밝음, 림라이트는 실루엣 가장자리, 가는 광택은 탑햇으로 드러나는 가는 구조, 반사광은 그림자 안) 그 특징으로 가중치를 정합니다. 원리: $\mathrm{smoothstep}(R_r, 0.4R_r, e)$는 두 끝을 거꾸로 둔 smoothstep이라 가장자리에서 $0.4R_r$ 안은 1, $R_r$ 밖은 0으로 부드럽게 줄어듭니다. $(S_\max - \bar O)/S_\max$는 밝아짐 중 안쪽 평균을 넘는 몫이라 가장자리에만 있는 빛일수록 1에 가깝습니다. 가는 광택은 탑햇 𝑇와 옅은 색($\min_c U$)의 두 smoothstep을 곱해 둘 다 맞을 때만 큽니다. 참고: R47 Ebert et al. 2003 · R15 Soille 2003 · 이 프로그램에서 정한 규칙

림라이트 · 반사광은 채널 최댓값이 12/255 넘는 픽셀이 $\max(24, \mathrm{round}(0.003 \times \text{캐릭터 픽셀 수}))$보다 적으면 만들지 않고($w = 0$) 빛에 남깁니다.

풀이 — 왜: 림라이트 · 반사광이 거의 없는 그림에 빈 층을 만들지 않습니다. 원리: 12/255 넘는 픽셀 수가 24 또는 캐릭터 픽셀의 0.3%보다 적으면 그 몫을 빛 층에 남깁니다. 참고: 이 프로그램에서 정한 규칙

4.12 최소 알파 저장

곱하기 · 스크린 층의 픽셀 값 𝑣(채널별 0~1)를 “색 𝐾 + 알파 𝑎”로 저장할 때, 가장 작은 알파를 씁니다.

a=\frac{\max(1,\ \mathrm{round}(255\max_c v_c))}{255},\qquad K_c=\mathrm{clamp}\!\left(\frac{v_c}a\right),\qquad
K^{(8)}_c=\mathrm{round}(255K_c),\quad a^{(8)}=\mathrm{round}(255\,a\,A)

$255 \max_c v_c < 0.5$인 픽셀은 비워 둡니다. 채널 중 가장 큰 값이 알파가 되고 그 채널의 𝐾는 1이라, 이보다 작은 알파로는 같은 값을 만들 수 없습니다. 스크린은 $1 - (1 - x)(1 - aK)$, 곱하기는 $x(1 - a + aK)$로 합성되므로, 곱하기 층(그라데이션 · 명암)은 $v = D$로 구한 𝐾를 $K \gets 1 - K$(8비트로 $255 - K^{(8)}$)로 저장합니다. 알파가 작을수록 층이 투명해 보여서, 작가가 옅게 칠한 층처럼 보이고 다시 손대기 쉽습니다. 8/255 넘는 알파가 24픽셀 미만인 층은 비어 있는 것으로 보고 만들지 않습니다.

풀이 — 왜: 같은 효과를 내는 색 · 알파 쌍은 여럿인데, 알파가 가장 작은 쌍으로 저장하면 층이 가장 투명해 작가가 옅게 칠한 층처럼 보이고 고치기 쉽습니다. 원리: 알파 𝑎로 색 𝐾를 스크린하면 효과는 $aK$이므로 $aK_c = v_c$를 만족해야 하고, $K_c \le 1$이라 $a \ge \max_c v_c$입니다. 그래서 가장 큰 채널 값이 가장 작은 알파이고 그 채널의 𝐾가 1입니다. 곱하기 층은 $x(1 - a + aK')$로 합성되므로 $K' = 1 - K$로 저장하면 $a(1 - K') = aK = D$가 되어 같은 식을 씁니다. 8비트 알파에 원본 알파 𝐴를 곱해 투명한 곳에는 효과가 남지 않습니다. 참고: R1 Porter · Duff 1984 · R2 Smith 1995 · R3 ISO 32000-1 2008

그 밖의 층은 다음과 같이 저장합니다(모두 8비트, 알파가 0이 아닌 픽셀을 감싸는 가장 작은 사각형으로 잘라 둠).

층 색 알파
밑색 파츠 밑색 $\mathrm{round}(255A)$
1차 · 2차 그림자 $\mathrm{round}(255 \mathrm{sh}^1)$ · $\mathrm{round}(255 \mathrm{sh}^2)$ 1차는 단계 1 · 2, 2차는 단계 2 픽셀에 $\mathrm{round}(255A)$
하이라이트 $\mathrm{round}(255 \cdot \text{톤 평균})$ 하이라이트 픽셀에 $\mathrm{round}(255A)$
선화 $K^0$(선화 + 색 트레이스), 픽셀별 𝐾(원본 선 색), 0(검정) $\mathrm{round}(255 \cdot a \cdot A)$
색 트레이스(선화에 클리핑) 픽셀별 𝐾 255
배경 𝑈(배경 효과 · 글로우 자리는 $\mathrm{base}$) 255
외곽 글로우 𝑈 255
실루엣(숨김) 회색 160 $\mathrm{round}(255A)$

풀이 — 왜: 나머지 층은 PSD 일반 층(표준 합성)으로 저장되므로 8비트 색과 알파를 정해야 합니다. 원리: 색은 0~1 값에 255를 곱해 반올림하고, 알파는 원본 알파 𝐴를 같은 방식으로 씁니다. 그림자 층은 톤 단계(1차는 1 · 2, 2차는 2)인 픽셀에만 알파를 줘 곱하기가 필요한 곳에만 걸립니다. 층마다 알파가 0이 아닌 최소 사각형으로 잘라 파일 크기를 줄입니다. 참고: R4 Adobe PSD · 이 프로그램에서 정한 규칙

4.13 재현 검증

저장될 8비트 값 그대로 다시 합성합니다.

v=\big(F\cdot sh^1\cdot sh^2\ \text{또는 하이라이트}\big)\times\prod_{\text{grad, shade}}(1-a+aK)
\ \to\ 1-(1-v)\prod_{\text{refl, rim, spark, fx}}(1-aK)
\ \to\ v(1-a_\ell)+a_\ell K_\ell

배경 픽셀은 $v = \text{배경} \to 1 - (1 - v)(1 - aK)$(배경 효과) $\to v(1 - a_g) + a_g K_g$(외곽 글로우)입니다. 여기서 𝑎, 𝐾는 모두 저장된 8비트 값을 255로 나눈 값입니다.

풀이 — 왜: 저장한 층을 포토샵과 같은 순서 · 합성식으로 다시 합쳐야, 결과가 원본과 같은지 프로그램 안에서 확인할 수 있습니다. 원리: 밑색 · 그림자 · 하이라이트로 만든 색에 곱하기 층(그라데이션 · 명암) $(1 - a + aK)$를 곱하고, 스크린 층(반사광 · 림라이트 · 반짝임 · 빛)을 $1 - (1 - v)\prod(1 - aK)$로 얹은 뒤, 선화를 표준 합성 $v(1 - a_\ell) + a_\ell K_\ell$으로 덮습니다. 모든 값은 저장된 8비트 값을 255로 나눈 것이라 파일을 연 결과와 같습니다. 참고: R1 Porter · Duff 1984 · R3 ISO 32000-1 2008 · R4 Adobe PSD

\mathrm{MSE}=\frac1{3n}\sum_{p:\,A_p>0.98}\ \sum_c\big(255\,(v_c(p)-O_c(p))\big)^2,\qquad
\mathrm{PSNR}=10\log_{10}\frac{255^2}{\mathrm{MSE}}

𝑛은 불투명 픽셀(알파 $> 0.98$) 수입니다. $\mathrm{MSE} \le 10^{-9}$이면 PSNR을 99로 두고 화면에 “∞”로 표시합니다.

풀이 — 왜: 재현이 얼마나 정확한지를 하나의 수로 보여 주기 위해서입니다. 원리: MSE는 불투명 픽셀 · 채널마다 8비트 단위 차이의 제곱 평균이고, PSNR $= 10\log_{10}(255^2/\mathrm{MSE})$는 최대 신호(255)의 제곱에 대한 오차의 비를 dB로 나타낸 것입니다. 오차가 작을수록 커지고, 오차가 0이면 무한대라 99로 두고 “∞”로 보입니다. 반투명 픽셀은 바탕에 따라 보이는 색이 달라 빼고 잽니다. 참고: R55 Huynh-Thu · Ghanbari 2008 · R14 Gonzalez · Woods 2018


← README · 다음: 4.14 러프 생성