적목 효과 제거 프로그램을 만들어보자

Posted by NUL PROG. : 2007. 5. 29. 23:12
적목현상이란?

어두운 곳에서 사람의 동공이 확대되었을 때 플래시를 터트리며 사진을 찍게 되면, 플래시 빛이 이 확대된 동공을 통과하여 망막 뒤의 모세혈관에 반사되고 이 반사된 붉은빛이 다시 카메라의 렌즈로 들어와서 빨간 눈으로 사진이 찍히게 되는데 이를 적목현상이라 한다.

이를 피하려면 ......
  1. 동공이 커지지 않게 조명을 밝게 하거나 (혹은 밝은 곳에서만 사진을 촬영 -_-;)
  2. 플래시의 빛이 반사되는 것이기에 피사체를 중심으로 플래시와 렌즈의 각도를 크게 하거나 (즉 렌즈와 플래시의 거리를 떨어뜨리거나 별도의 조명을 사용)
하는 방법이 있다.

일반적으로 디지털 카메라는 그 크기가 매우 작아서 특히 이런 현상이 자주 발생한다.

아무튼 이를 보정하는 프로그램을 작성해보도록 하겠다. 일단 완성품을 보도록 하자

사용자 삽입 이미지

이번에도 집사람의 사진을 무단 도용하였다 (미안 -_-;)



사용자 삽입 이미지

마우스를 드래그하면 사각 영역이 그려지고,



사용자 삽입 이미지

드래그가 끝나면 선택 영역의 적목현상으로 나타난 빨간 눈을 대충 바꿔 준다.



사람이 영역을 선택해 주기 때문에 시퀀스가 단순하다. 만약 이를 완전 자동화한다면, 사람의 얼굴을 찾고 눈을 찾는 알고리즘이 들어가야 하는데, 이게 쉽지 않고 구현한다 하더라도 어느 정도의 오류 발생을 감수해야 한다.

아래와 같이 쉽게 쉽게 하도록 하자 -_-ㅋ
  1. RGB 칼라맵의 R 강도를 구하고 그 값이 일정 수치 이상인 경우를 찾는다.
    일정 수치라는 건 다양한 테스트로 아무거나 정하거나, 평균값을 구하거나, 평균값에 가중치를 약간 주거나 맘에 드는 걸로 하자.
    예제에서는 그냥 적당한 숫자를 넣었다.
    R 값의 강도 (Redness) 구하기 function SubGetRedness: Double;
    begin
      if r = 0 then Result := 0
      else Result := (r - g + r - b) / r / 2;
    end;
  2. R의 강도가 일정 수치를 넘으면 그 R 값을 G, B 값의 가장 작은 값으로 대체 해준다.
    이때 너무 빨간 빛이 확 줄어버릴 수 있기 때문에 적당한 가중치를 적용하여 기존 R 값을 넣어준다.
    예제에서는 8:2로 넣었다.
    R 값을 8:2 로 보정하는 식 r := Trunc(Min(g,b) * 0.8 + r * 0.2);

너무 간단하게 끝나 버렸다......;

눈이 아닌 부분의 픽셀을 보정하지 않게 막으려면,
R 값이 일정 수치 이상일 때 기하학적인 정보로 눈동자의 중심을 찾고 눈동자의 중심에서 멀리 떨어진 픽셀을 제외 시키는 방법도 좋겠다.
기하학적인 정보로 눈동자를 찾기 어렵다면, 픽셀 좌표의 분포를 검사해서 대략 적인 중심을 구할 수도 있다.

좀 더 부드러운 느낌이 들도록 보정 하려면,
적목효과 보정 주변 픽셀에 블랜딩을 주거나 혹은 블러 효과를 넣는 것도 좋을 것이다.