티스토리 뷰

부제: 인간의 색상 감각이과식으로 파해치기

👨‍💻 🎨 👀 🧠 🔎 🔬 🧪 🖌️ 🌈

 

바쁜 사람들을 위한 3줄 요약:

색각 모델을 사용하여 인간의 색 인지를 과학적으로 접근할 수 있다.

이를 통해 순정틱하면서 모든 색이 고르게 잘 보이는 터미널 색 구성을 만들었다.
(미리보기, 다운로드)

 

개요

검은 바탕에 글씨로만 이루어진 화면. 개발을 하다보면 오래 보게 되는 터미널입니다. 주르륵 올라가는 화면을 쓰다보면 해커가 된 기분도 나죠. 😄

xterm 기본 색 구성 터미널


현대의 터미널은 RGB 24-bit 색상도 쓸 수 있지만, 기본적으로는 16색 조합을 많이 사용합니다.

흑, 적, 녹, 황, 청, 자, 옥, 백의 '기본' 8색 + '밝은' 8색.

xterm의 기본 색 구성

 

이런 기본 터미널 색상 설정들은 보통 파랑이 너무 어둡죠. 초록은 너무 밝아 눈이 시립니다. 🥶

 

그래서 찾아보면,
https://gogh-co.github.io/Gogh/
https://github.com/AlexAkulov/putty-color-themes
각자의 취향대로, 감각대로 만든 수많은 16색 조합이 공유되고 있습니다.

근데 저 중 제 마음에 쏙 드는 건 없습니다. 대게 아래와 같은 문제들이 있죠.

  • 이름과 색이 딴판 (Red가 자홍색이고, Blue가 보라색이고...)
  • 배경색에 묻혀 잘 안보이는 일부 색상
  • '밝은' 색상들이 따로 없거나, 엉망임

이런 문제들을 해결하고자... 저는 바다에 작은 돌 하나를 던지기로 했습니다.

 

New standard terminal color scheme 🌈

없으면 만들면 되죠.

기본 터미널 색 구성의 심한 밝기, 채도차이를 일정하게 줄여보자.

 

이를 통해 정석에 가까우면서도 잘 보이는, new standard를 지향하는 색 구성을 만들려 합니다.

 

첫 단계: 색상(hue)은 그대로 두고 밝기만 올리기...?

일단 파랑색의 밝기부터 올려보겠습니다.

 

 

B값을 최대로 해도 ◼(0,0,255) 여전히 어둡습니다.

 

여기서 밝기를 올려 R, G를 올리면 ◼(100,100,255)  밝기는 높아지는데, 색에 붉은기가 돌기 시작합니다.

 

시작부터 난관이네요. 🤦

 

색각 모델(Color appearance model)

위에서 보셨듯 인간의 시각은 RGB 값에 선형적으로 반응하지 않습니다. R, G 값을 동일하게 조정해도 보이는 색상은 틀어지죠.

여기서 필요한 것이 색각 모델(CAM: color appearance model) 입니다.
최신 CSS 표준에 관심이 있는 분은 Oklab, Oklch에 대해 들어보셨을 수도 있겠네요. Oklab 또한 색각 모델의 일종입니다.

RGB를 사용하여 색상 평면을 구성하면 아래와 같이 밝기가 들쭉날쭉 하지만,

 

색각 모델을 사용하면 아래처럼 균등한 밝기를 갖는 색상 평면을 구할 수 있습니다.

 

Oklch 색각 모델을 사용해서, 다시 파란색을 봅시다.

좌: 색각 모델 사용 안함 / 우: Oklch 색각 모델 사용

https://bottosson.github.io/misc/colorpicker/#0000ff

 

상단 #0000ff와 비교했을 때, 좌측 팔레트는 붉은기가 돌지만, 색각 모델을 적용한 우측 팔레트는 더 적절한 파란색을 나타냅니다.

 

다시 첫 단계: 색은 그대로 두고 밝기만 올리기

Oklch 색상 추출 도구를 사용해 파랑의 밝기를 올려보면 ◼(72,127,255) 붉은기가 빠졌죠? 이제서야 밝은 파랑으로 보입니다. 


이렇듯, 색각 모델을 사용하면 인간의 시각에 맞게 색을 다룰 수 있게 됩니다.

 

자 그럼 이제부터 색각 모델을 사용하여 터미널 기본 색 구성을 만져주겠습니다.
목표는 색상(hue)을 유지하면서, 과도한 밝기 차이를 줄이는 것입니다.

 

CAM16-UCS

사용할 색각 모델은 CAM16-UCS(Color Appearance Model 2016 - Uniform Color Space)입니다.

 

 

J(밝기), a(적-녹), b(황-청) 3개 값으로 색을 나타냅니다.

(밝기(lightness)는 휘도(L: luminance)와 구분하기 위해 L* 또는 J로 표기합니다.)

 

J, a, b의 직교 좌표계(x, y, z)를 원통 좌표계(r, Φ, z)로 변환하면 우리가 쓰려는 색의 3요소가 나옵니다.

J: 밝기(Lightness)
C: 채도(Chroma)
h: 색상(hue)

 

(아래 도표들은 이해를 돕기 위한 것으로, 실제 색각 모델, 색상과 차이가 있습니다.)

색 조정 🖌️

xterm의 기본 설정을 기준으로 조정을 진행해보겠습니다.
https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit

xterm의 기본 색 구성

 

색 변환에는 파이썬 colour-science 패키지를 사용합니다.

$ pip install colour-science

 

RGB 색상을 XYZ 색공간을 거쳐서 CAM16-UCS (Jab → JCh)로 변환합니다.

import colour  # colour-science

# Convert to CAM16-UCS-JCh
xyz = colour.sRGB_to_XYZ(color_rgb/255)
jab = colour.XYZ_to_CAM16UCS(xyz)
color_jch = colour.models.Jab_to_JCh(jab)

그리고 J, C, h로 분리합니다.

j = color_jch[..., 0]
c = color_jch[..., 1]
h = color_jch[..., 2]

 

밝기(Lightness)

먼저 너무 어두운 파랑, 너무 밝은 초록의 차이를 좁혀보죠.

 

 

 

조정 전 밝기 분포

하지만 밝기 차이를 없애지는 않습니다. 딱 절반으로 타노스 해보겠습니다.

j_mean = np.mean(j[2:8])
j[2:8] = (j[2:8] + j_mean) / 2  # colors

j_mean = np.mean(j[10:16])
j[10:16] = (j[10:16] + j_mean) / 2  # bright colors

 

조정 후 밝기 분포

 

밝기 조정 후 색 구성

 

밝기 차이를 완전히 없애지는 않습니다. 그렇게 하면 색상의 구분감이 떨어지고, 이후에 설명할 clipping 문제가 심해져 결과물이 이상해집니다.

 

색상(Hue)

색상을 평면에 표시해보면 각도 간격이 일정치 않습니다.

특히 노란색이 초록으로 치우쳐 있죠.

조정 전: 일정하지 않은 색상(각도) 간격

이를 60˚씩 균등하게 퍼트려 색상 간의 차이를 극대화해줍니다.

# Set hue(mean delta to original is about 3)
h[2:8] = (30, 150, 90, 270, 330, 210)
h[2:8] += 3

h[10:16] = (30, 150, 90, 270, 330, 210)
h[10:16] += 3

조정 후: 일정해진 색상(각도) 간격

 

 

채도(Chroma)

이렇게 조정한 색은 RGB (-32, 266, 128) 와 같이 SDR 디스플레이에서 표시할 수 없는 색이 포함되어 있습니다. 사진의 밝기를 조정하다 노출 과다/부족으로 clipping이 발생한 상황이라고 생각하시면 됩니다.

조정 전: 색상 범위(gamut)를 벗어남

 

일단 채도 차이를 타노스 합니다.

# Normalize chroma
c_min = np.min(c[2:8])
c[2:8] = (c[2:8] + c_min) / 2

c_min = np.min(c[10:16])
c[10:16] = (c[10:16] + c_min) / 2

 

그리고 동일 비율로 채도를 낮춰 색들을 정상범위(0~255) 안으로 밀어넣어 톤을 정리해줍니다.

# clip chroma into sRGB gamut
for desaturate in np.arange(1, 0.1, -0.001):
    # Convert back to RGB
    color_jch_adj = np.stack([j, c*desaturate, h], axis=-1)
    jab = colour.models.JCh_to_Jab(color_jch_adj)
    xyz = colour.CAM16UCS_to_XYZ(jab)
    color_rgb = colour.XYZ_to_sRGB(xyz)

    if np.all(0 <= color_rgb) and np.all(color_rgb <= 1):
        color_jch = color_jch_adj
        break

조정 후: 색상 범위 안

 

결과물

결과물입니다.

 

표준에 가까우면서 모든 색들이 고르게 잘 보이죠?

색들의 밝기 차이가 줄어들어 빨강, 파란색이 더 잘 보이고, 시얀, 녹색의 튀는 부분이 사라졌습니다.

 

추가 조정

가독성과 색 구분 향상을 위한, 다소 주관이 반영된 추가 조정입니다.

배경색

 

(0,0,0) 검정 배경은 가독성에 좋지 않은 것으로 알려져 있습니다.

 

 

배경을 검정에 가까운 회색(20,20,20)으로 수정합니다.

 

 

색상 구분 향상

'보통'과 '밝은' 색들의 hue에 약간의 이격을 줘서 서로 더 잘 구분되도록 조정합니다.

조정 전: 일반/밝은 색상 간의 차이가 적음 .

# Set hue(mean delta to original is about 3)
h[2:8] = (30, 150, 90, 270, 330, 210)
h[2:8] -= 10  # 원래는 +3이었음

h[10:16] = (30, 150, 90, 270, 330, 210)
h[10:16] += 3

조정 후: 일반/밝은 색상 간의 차이가 생김

 

추가 조정 결과물 ✨

최종 결과물입니다.

브라우저에서 미리보기

 

조정 전/후 비교

조정 과정

 

 

조정 전후 미리보기

코드

색 생성과 시각화에 사용한 Python 코드는 아래에 있습니다.

https://colab.research.google.com/drive/1BZ26_QMkFRFsBzrRvCLGu10bw2inz947?usp=sharing

 

설정 다운로드 🛠️⬇️

PuTTY, Mintty, Windows Terminal 용 배색 설정파일을 아래에서 받을 수 있습니다.
https://github.com/dofuuz/dimidium

 

색각 모델 만져보기

파이썬을 몰라도 괜찮습니다. 아래 사이트에서 OKLCH로 직접 조색을 할 수 있습니다.

https://oklch.com/

https://bottosson.github.io/misc/colorpicker

 

의견 받습니다.

최적의 가독성을 위한 배경색 의견 받습니다.
(0,0,0) 검정 배경이 좋지 않다는 건 정설이지만, 정확히 어느정도의 회색이 최적인지는 못 찾겠네요.

→ 비교적 낮은 전경색 밝기를 고려하여 (20, 20, 20) 회색으로 확정했습니다.

 

색 구성 이름 아이디어 부탁드립니다.

현 후보로는...

  • 피사계 심도(Depth of Field)를 뜻하는... 사실 그냥 만든 놈 닉네임에서 따온 DOF
  • CAM + terminal = Caminal
  • 절반을 뜻하는 라틴어 Dimidium (← 잠정 후보)
  • 밝기의 빈부차를 줄인다는 의미의 Bamboo spear(죽창)

→ Dimidium으로 결정되었습니다.

 

기타 글과 색 구성에 대한 전반적인 의견을 받습니다.




의견 반영 후 생성 코드와 색 설정 정리하여 별도의 Github 리포지토리에 업로드하도록 하겠습니다.

별도의 저장소로 분리했습니다. 의견은 계속 받습니다!


감사합니다.

 

 

2024-01-11: CAM16-UCS 단락 추가, 본문 내에 Python 코드 추가, 조정 전후 미리보기 GIF로 대체

2024-01-16: 글 내용 정돈. 링크 추가.

2024-01-23: GeekNews에 글 등록

2024-01-26: 흰색(전경) 밝기를 약간 낮추었습니다. (본문 내용에는 미반영)

2024-01-28: 기존 dotfiles에서 별도의 저장소로 분리

2024-02-08: Dimidium 릴리즈

2024-03-02: 제작 후기 업로드

 

최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함