5.19. 톤 보정#

톤 보정은 캡처된 이미지에서 밝기와 색상이 분포되는 방식을 변경합니다. 프레임이 너무 어둡거나, 너무 밝거나, 너무 평탄하거나, 잘못된 색상으로 치우쳤을 때 애플리케이션이 적용하는 수정 작업입니다.

이 보정은 두 가지 계열로 나뉩니다. 밝기를 재분포시키는 밝기-대비 조정과, 각 픽셀이 어떤 색상으로 읽히는지를 변경하는 색상 조정입니다. 둘 다 센서의 ISP에 대응하는 기능이 있으며, ISP는 들어오는 각 프레임을 보정합니다. 여기서 다루는 메서드는 이미 캡처된 Image에 사후적으로 적용되며, 프레임이 ISP가 제공한 것보다 더 많은 보정이 필요한 경우를 위한 것입니다.

5.19.1. 히스토그램 평활화#

가장 단순한 대비 확장 연산은 히스토그램 평활화입니다. 그 아이디어는 출력의 히스토그램이 가능한 한 평탄해지도록 픽셀 값을 다시 매핑하는 것, 즉 모든 값이 대략 똑같은 빈도로 나타나도록 하는 것입니다. 시각적 효과는 저대비 이미지(히스토그램이 좁은 대역에 집중된 이미지)가 픽셀이 전체 0255 범위에 걸쳐 분포하는 고대비 이미지로 바뀌는 것입니다.

histeq()는 평활화를 실행합니다:

img.histeq()

그 동작 방식은 직관적입니다. 원본 히스토그램의 누적 분포 함수(CDF)가 계산되고, 각 입력 픽셀 값이 CDF상의 위치로 매핑되어 출력 범위에 맞게 스케일링됩니다. 픽셀이 이미 고르게 퍼져 있던 곳에서는 매핑이 항등 함수에 가깝고, 픽셀이 한 밝기에 몰려 있던 곳에서는 그 밝기를 더 넓은 출력 값 범위에 걸쳐 늘려 픽셀을 퍼뜨립니다.

저대비 장면에서는 그 결과가 극적입니다. 어두운 실내 사진과 histeq를 적용한 같은 사진의 차이는 흔히 “판독 불가”와 “완벽히 판독 가능”의 차이가 됩니다. 절충점은 이 연산이 센서 노이즈를 포함해 모든 것을 증폭한다는 것입니다. 복원할 실제 저대비 세부가 있는 장면에서는 histeq가 정답이지만, 그것이 전혀 필요 없는 깔끔하고 잘 노출된 장면에서는 histeq가 눈에 띄는 노이즈를 만들어냅니다.

5.19.2. CLAHE: 적응형 평활화#

히스토그램 평활화는 전역적입니다. 즉 전체 이미지에서 계산된 하나의 CDF를 사용해 어디에나 적용합니다. 이는 밝기 범위가 대략 균일한 이미지에서는 잘 작동하지만, 국소적으로 어둡거나 밝은 영역이 있는 장면에서는 실패합니다. CDF가 픽셀이 더 많은 쪽으로 끌려가고, 반대쪽은 과도하게 보정됩니다.

적응형 변형은 대비 제한 적응형 히스토그램 평활화(Contrast Limited Adaptive Histogram Equalisation)이며, 흔히 CLAHE라고 불립니다. 하나의 전역 CDF 대신, CLAHE는 이미지의 작은 타일마다 별도의 CDF를 계산하고, 각 타일을 자체 CDF에 대해 평활화한 다음, 타일 경계를 함께 혼합합니다. 그 결과 밝기 조정이 국소적으로 일어납니다. 그늘진 구석은 밝은 구석이 잘못된 방향으로 끌어당기는 일 없이 자체적인 평활화를 받게 됩니다.

adaptive=True 플래그는 histeq()를 CLAHE 모드로 전환합니다:

img.histeq(adaptive=True, clip_limit=10)

clip_limit 매개변수는 CLAHE의 이름에 있는 “대비 제한”이 가리키는 부분입니다. 국소 평활화는 CDF에 서로 다른 값이 거의 없는 평탄한 영역에서 노이즈를 과도하게 증폭할 수 있습니다. 클립 제한은 단일 빈이 얼마나 공격적으로 재분포될 수 있는지를 제한하여, 중요한 곳에서는 여전히 대비 확장을 허용하면서도 노이즈 증폭을 방지합니다. 10 정도의 값이 합리적인 출발점입니다. 더 큰 값은 더 많은 눈에 띄는 노이즈를 대가로 CLAHE가 더 강하게 작동하게 하고, 더 작은 값은 더 부드럽게 만듭니다.

CLAHE는 전역 histeq보다 비용이 많이 들지만, 밝기가 고르지 않게 분포된 장면(즉 대부분의 실제 장면)에서 더 깨끗한 결과를 만들어냅니다.

5.19.3. 감마, 대비, 밝기#

히스토그램 평활화는 밝기를 다시 매핑하는 데이터 기반 방식입니다. 데이터 비의존적인 방식은 몇 개의 조정하기 쉬운 노브로 매개변수화된, 선택한 곡선을 적용하는 것입니다. gamma()는 세 가지를 제공합니다:

img.gamma(gamma=1.0, contrast=1.0, brightness=0.0)

각 매개변수는 모든 픽셀에 하나의 특정 변환을 적용합니다:

gamma는 각 픽셀 값을 거듭제곱 함수 output = input ** (1 / gamma)에 통과시킵니다. 표준적인 의미는 다음과 같습니다. 1.0보다 큰 값은 이미지를 밝게 하고 중간 톤을 끌어올립니다(고전적인 “모니터 감마” 보정). 1.0보다 작은 값은 어둡게 합니다. 이 매개변수는 비선형적입니다. 흑점과 백점은 보존하고 그 사이의 분포만 다시 형성하는데, 이는 기존 극단을 망가뜨리지 않으면서 그림자나 하이라이트 영역의 세부를 복원하는 것이 목표일 때 올바른 동작입니다.

contrast는 각 픽셀을 중간 회색 지점을 중심으로 한 단순 곱셈에 통과시킵니다. 1.0보다 큰 값은 대비를 높이고(어두운 곳은 더 어둡게, 밝은 곳은 더 밝게, 중간 회색은 그대로), 1.0보다 작은 값은 대비를 줄입니다.

brightness는 모든 픽셀 값에 상수를 더합니다. 양수 값은 밝게 하고, 음수 값은 어둡게 합니다. 이 이동은 균일하여 아무것도 보존되지 않으므로 그 자체만으로 애플리케이션이 원하는 경우는 드물지만, 결과를 다시 중심에 맞추기 위한 대비 처리와 잘 어울립니다.

세 매개변수는 조합됩니다. 한 번의 gamma() 호출로 감마 곡선, 그다음 대비 곱셈, 그다음 밝기 이동을 모두 한 번의 처리로 적용할 수 있습니다. 순서는 감마가 먼저, 그다음 대비, 그다음 밝기이며, 이는 세 가지가 모두 기본값이 아닐 때 가장 직관적인 결과를 주는 순서와 일치합니다.

5.19.4. 자동 화이트 밸런스#

톤 보정의 색상 계열은 자동 화이트 밸런스로 시작합니다. 센서의 ISP가 이미징 파이프라인의 일부로 실행하는 것과 동일한 메커니즘, 즉 평균적인 회색 패치가 실제 회색으로 읽히도록 빨강, 초록, 파랑 채널의 상대적 게인을 조정하는 메커니즘이 완성된 Image에 대한 캡처 후 연산으로도 제공됩니다:

img.awb()

기본값은 그레이 월드(gray-world) 알고리즘을 사용합니다. 전체 이미지의 평균 색상이 중립 회색이라고 가정하고, 그렇게 되도록 채널별 게인을 조정합니다. 대안인 max=True 형태는 화이트 패치(white-patch) 알고리즘을 사용합니다. 가장 밝은 픽셀이 중립 흰색이라고 가정하고, 그렇게 되도록 게인을 조정합니다. 둘 다 RGB565와 raw Bayer에서 작동합니다. 어느 것도 그레이스케일(균형을 맞출 색상이 없는 경우)이나 YUV(이 알고리즘이 작동하는 색상 표현이 아닌 경우)에서는 작동하지 않습니다.

ISP의 자동 화이트 밸런스 대신 캡처 후 형태를 사용해야 할 때는 다음과 같습니다. ISP의 선택이 특정 장면에 잘 맞지 않았을 때, 애플리케이션이 다른 조건에서 캡처된 참조 프레임을 디스크에서 불러오는 경우, 또는 색상 판단이 충분히 중요해서 애플리케이션이 자체적인 알고리즘 선택으로 다시 실행하고 싶을 때입니다.

5.19.5. 색상 보정 행렬#

이미지에 필요한 색상 보정이 화이트 밸런스가 제공하는 채널별 스케일링이 아니라 더 일반적인 채널 혼합일 때, 사용할 연산은 색상 보정 행렬입니다. ccm() 메서드는 모든 픽셀의 (r, g, b) 벡터에 곱해 새로운 (r, g, b) 벡터를 생성하는 3x3(또는 오프셋이 있는 3x4) 행렬을 적용합니다:

img.ccm([[1.1, -0.05, -0.05],
        [-0.05, 1.1, -0.05],
        [-0.05, -0.05, 1.1]])

이 행렬을 사용하면 애플리케이션이 색상 채널 간의 크로스토크를 보정할 수 있습니다. 예를 들어 빨강 센서의 응답에 일부 초록 빛이 포함된 경우, 행렬은 보상을 위해 초록 채널의 일부를 빨강 출력에서 뺄 수 있습니다. 채널별 오프셋과 결합하면, 3x4 형태는 애플리케이션이 각 채널을 다시 영점화할 수도 있게 합니다.

ISP 파이프라인 자료는 색상 보정 행렬의 이유를 다룹니다. Image에 대한 캡처 후 형태는 사후에 적용되는 동일한 연산일 뿐입니다.