본문 바로가기
Nuke/Color

Float

by 르면가게 2024. 12. 13.

https://compositormathematic.wordpress.com/2013/07/03/float/

 

Float

I think it’s fitting that my first real post should be something that is fundamental to our workflow, but continues to impress me in how it has revolutionised compositing – floating point num…

compositormathematic.wordpress.com

8bit 색상과 그 한계

8bit 색상은 컴포지팅을 처음 시작한 사람들이 경험했을 법한 초기 색상 모델 중 하나로, 16,777,216개의 색상을 표현할 수 있습니다. 숫자로 보면 많은 것처럼 보이지만, 실제로는 그리 넉넉하지 않습니다. 여기서 중요한 포인트는 정확한 색 표현에 한계가 있다는 점입니다.

8bit RGB 색상 모델

  • RGB 값은 각각 0에서 255까지의 값을 가질 수 있습니다. 즉, 각 색상 채널(빨강, 초록, 파랑)은 256개의 값을 가질 수 있습니다.
    • 예: (0, 0, 0)은 검정색, (255, 255, 255)는 흰색입니다.
    • 이 외에도 다양한 중간 색을 표현할 수 있지만, 여전히 256개의 고정된 값 안에서만 가능합니다.

색상 범위와 클리핑(Clipping)

  • 예를 들어, 이미지를 1.5배 밝게 하고 싶다면, 170의 값에 1.5를 곱해 255를 얻고, 그 이상은 오버플로우 되어버립니다. 255가 최대값이기 때문에 그 이상은 표현할 수 없고 정보가 손실됩니다. 이를 **클리핑(clipping)**이라고 합니다.
    • 이 경우, 밝기를 올렸지만 실제로 더 밝은 색을 표현할 수 없어서 정보가 잘리게 됩니다.

감마 보정 및 색 공간 변환에서의 문제점

  • 또 다른 문제는 반올림 오류입니다. 예를 들어, 13에 1.5를 곱한 값은 19.5가 되어야 하지만, 8bit 색상에서는 정수만 표현할 수 있기 때문에 19나 20으로 반올림됩니다.
    • 이 오류는 0.02% 미만의 작은 차이처럼 보일 수 있지만, 여러 번의 색 보정 작업이나 감마 보정, 색 공간 변환을 수행할 때 그 오차가 누적되어 큰 영향을 미칠 수 있습니다.

8bit에서 16,777,216개의 색상은 어떻게 가능한가?

  • 비트0 또는 1의 값을 가질 수 있는 이진 값입니다. 8비트는 0과 1을 8번 반복할 수 있기 때문에, 8비트는 2^8 = 256 개의 값이 가능합니다.
  • 각 색상 채널은 256개의 값을 가질 수 있고, 세 개의 채널(RGB)에 대해 모든 가능한 조합을 계산하면: 256×256×256=16,777,216 즉, 총 16,777,216개의 색상이 가능합니다.
  • $256 \times 256 \times 256 = 16,777,216$

결론: 8bit의 한계

  • 8bit 색상 모델은 한정된 값으로 색을 표현할 수 있기 때문에 고급 작업에서는 정밀도가 부족할 수 있습니다. 특히 색 보정 작업이나 다중 색 보정정확한 계산이 필요한데, 8bit에서는 반올림 오류클리핑 때문에 품질이 떨어질 수 있습니다.
  • 이를 해결하려면 더 높은 **비트 심도(예: 16bit, 32bit)**의 색상 모델을 사용하는 것이 좋습니다.

IEEE 32-bit Float 색상 모델

32비트 부동소수점 색상 모델은 8비트와 16비트에 비해 훨씬 높은 정밀도를 제공합니다. 여기서 중요한 개념은 부동소수점(floating point) 방식입니다. 32비트 부동소수점 숫자는 **mantissa(가수)**와 exponent(지수) 두 부분으로 나뉘어 계산됩니다. 이를 통해 정수뿐만 아니라 매우 작은 수와 큰 수를 모두 다룰 수 있는 방식이 가능합니다.

1. 8bit vs. 32bit

  • 8비트는 각 색상 채널에 대해 256개의 값을 갖습니다 (0부터 255까지).
  • 반면에 32비트 부동소수점에서는 2^32 값을 사용할 수 있지만, 단순히 0부터 4,294,967,295까지의 정수를 사용하는 것은 아닙니다. 대신 부동소수점 형식을 사용하기 때문에 훨씬 더 정밀하고 다양한 범위의 값을 표현할 수 있습니다.

2. 부동소수점의 구성

  • 부동소수점 수는 크게 두 부분으로 나누어집니다: mantissaexponent.
    • Mantissa: 숫자의 실제 값, 예를 들어 1.25.
    • Exponent: 이 값을 얼마나 크게 또는 작게 만들 것인지 나타내는 지수, 예를 들어 3을 곱해주면 1.25 × 2^3 = 10이 됩니다.

간단한 예시:

  • 10.0을 표현하려면:
    • Mantissa = 1.25, Exponent = 3 (따라서 1.25 × 2^3 = 10.0).
    • 이렇게 숫자는 가수지수의 조합으로 이루어집니다.

3. 부동소수점의 장점

  • 정확도: 부동소수점은 0과 1 사이의 작은 값에 대해 높은 정확도를 제공합니다. 예를 들어, 0과 1 사이의 숫자는 매우 세밀하게 표현될 수 있습니다.
    • 예를 들어, 0.999보다 작은 값들도 정확하게 표현할 수 있으며, 매우 큰 값도 다룰 수 있습니다.
  • 큰 숫자와 작은 숫자를 다룰 때 부동소수점은 큰 범위에서 정확한 값을 표현할 수 있게 해줍니다. 이는 정밀한 색상 계산이나 과학적 계산에서 매우 중요합니다.

4. IEEE 32-bit 부동소수점의 동작

  • 부동소수점 수지수에 따라 숫자 범위를 조정할 수 있어, 거의 무한한 범위의 숫자를 다룰 수 있습니다.
    • 예를 들어, 큰 숫자는 2^100 같은 매우 큰 수로 표현될 수 있으며, 작은 숫자는 2^-100과 같이 매우 작은 수로도 표현할 수 있습니다.
  • 정밀도0과 1 사이에서 특히 뛰어나며, 반올림 오류가 매우 적습니다. 그럼에도 불구하고 자세히 계산하면 여전히 약간의 오차가 존재할 수 있지만, 이 오차는 대개 실용적인 작업에서는 무시할 수 있을 정도로 미미합니다.

5. 결론

  • 32비트 부동소수점은 8비트 및 16비트보다 훨씬 높은 정밀도를 제공합니다.
  • 큰 범위정밀도를 갖는 이 방식은, 특히 고급 VFX 작업에서 매우 유용합니다. 예를 들어, 색상 보정, 색상 공간 변환, 입력 및 출력 간의 정확한 계산에서 중요한 역할을 합니다.
  • Nuke와 같은 프로그램에서 부동소수점을 사용하는 이유는, 고해상도 이미지에서 정확하고 세밀한 작업을 수행하기 위해서입니다.

Nuke에서 부드러운 그라디언트를 만들고, 그 아래에 Add[Math] 노드를 추가하여 값 1,000,000을 적용한 후, 다시 -1,000,000 값을 넣어 원래 값으로 되돌리는 작업을 하면 부드러운 그라디언트가 단계적인 모양으로 변할 수 있습니다. 이는 부동 소수점 정밀도와 관련된 현상입니다. 아래에서 자세히 설명드리겠습니다.

여기 이러한 오류를 확인할 수 있는 재미있는 실험이 있습니다:

그라디언트 생성:

  • Ramp 또는 비슷한 노드를 사용해 부드러운 그라디언트를 생성합니다. 그라디언트는 원래 0과 1 사이에서 부드럽게 변화해야 합니다.

첫 번째 Add[Math] 노드 (큰 값 적용):

  • Add[Math] 노드를 사용해 값 1,000,000을 더합니다. 이 연산은 이미지를 매우 큰 값으로 확대하는 것입니다.
  • 출력된 색상을 샘플링하면, Nuke는 큰 숫자에 대해 과학적 표기법을 사용하여 1.0e+06과 같이 표시할 수 있습니다. 이는 값이 매우 크지만 부동 소수점으로 처리할 수 있는 범위 내에 있다는 것을 의미합니다.

두 번째 Add[Math] 노드 (음수 큰 값 적용):

  • 이제 두 번째 Add[Math] 노드를 사용하여 값 1,000,000을 적용합니다. 이 연산은 첫 번째 연산에서 확대된 값을 원래 값으로 되돌리려는 시도입니다.
  • 하지만 이 과정에서 부동 소수점 정밀도의 한계로 인해, 원래의 부드러운 그라디언트가 정확히 복원되지 않고 계단형으로 변하는 현상이 발생합니다. 이때 0과 1 사이의 값이 더 이상 부드럽게 변화하지 않고 17개의 단계로 나뉘게 됩니다.

왜 이런 현상이 발생할까요?

  • 부동 소수점의 정밀도 문제입니다. 부동 소수점 숫자는 정수처럼 정확한 값으로 저장되기보다는 일정한 비트 수로 근사값을 저장하게 됩니다. 이로 인해 큰 숫자나 작은 숫자 사이를 계산할 때 정밀도가 손실되어 원래의 이미지 데이터가 왜곡될 수 있습니다.
  • 또한 클램프(Clamp) 노드를 과도하게 사용하거나, 이미지의 색상 범위를 넘어서게 되는 경우, 중요한 색상 정보가 잘려나가는 클리핑(Clipping) 문제가 발생할 수 있습니다.

결론:

  • 부동 소수점에서 매우 큰 값과 작은 값을 다룰 때, 특히 색상 정보나 그라디언트와 같은 연속적인 데이터를 처리할 때 정밀도 손실이 발생할 수 있습니다. 이를 해결하려면 과도한 수치 변환을 피하고, 적절한 색상 범위를 유지하는 것이 중요합니다.
  • 또한, 클램프 노드 사용 시 색상 정보가 손실되지 않도록 신중하게 조작해야 합니다.

부동 소수점 숫자에는 세 가지 '특수한' 숫자가 있습니다: inf, -inf, NaN입니다.

  1. infinf: 각각 양의 무한대와 음의 무한대를 나타냅니다. 이 값을 생성하는 가장 쉬운 방법은 0으로 나누기입니다. 예를 들어, 어떤 수를 0으로 나누면 inf나 inf가 발생합니다. 수학적으로는 정의되지 않은 연산이기 때문에 이러한 값들이 생기게 됩니다.
  2. NaN (Not a Number): 말 그대로 **"숫자가 아님"**을 의미합니다. 이는 잘못된 연산이 발생했음을 나타내는 값으로, 보통 예기치 않은 상황에서 발생합니다. 예를 들어, 0을 0으로 나누거나, 음수의 제곱근을 구하려고 할 때 NaN이 발생할 수 있습니다.

이 세 가지 값은 일상적인 작업에서 발생하지 않기를 바라겠지만, 때때로 불쑥 등장할 수 있습니다. 부동 소수점 연산을 할 때 NaN이나 inf가 생기면, 연산에 문제가 있다는 신호이므로 항상 조심해야 합니다.

이 값을 다루는 방법:

  • NaNinf를 계산에 포함시키면 예기치 않은 결과가 나올 수 있기 때문에, 이러한 값들이 발생했을 때 처리할 수 있는 방법을 마련해두는 것이 좋습니다.
  • 예를 들어, isnan()이나 isinf()와 같은 함수를 이용해 값이 NaN인지, 무한대인지 확인하고, 그런 값을 필터링하거나 적절히 대체할 수 있는 로직을 추가하는 것이 중요합니다.