심도가 낮은 렌즈와, 큰 크기의 촬상면을 가진 DSLR 같은 종류가 아니면 찍기 힘든 사진이 있다면 아마 배경이 뭉개진 이미지들이 아닐까 합니다만, 사실 단순이 Gaussian blur 만 줘서는 큰 렌즈의 빛의 굴절로 인해 생기는 일명 Bokeh 라는 형태를 만들어 내기가 쉽지는 않습니다.
그래서 어떻게 Bokeh 를 만들어 낼까? 란 고민을 하다 scratchpixel.com 에 한 페이지를 보게 되었습니다. circualr shifting 이라는 형태를 가지고 빛이 렌즈와 조리개를 통해 촬상면에 맺히는 형태를 흉내 낸 시뮬레이션 정도 이긴 합니다만 꽤 그럴싸한 결과물을 얻을 수 있었습니다.
십수년 전 분당에서 운동 하다 찍은 사진
32x32 짜리 마스크
bokeh effect 를 거친 결과 (이전버젼)
원래 소스는 조금 복잡한 처리를 해야 하나, 제가 이를 조금 수정 하여 다음 github 위치에 소스를 공개하여 G++ 를 가진 대부분 시스템에 빌드 해서 쓸 수 있도록 한 다음 ( OpenMP 필요 ), 마스크 이미지를 원래 이미지 만큼 크게 쓰지 않아도 자동으로 만들어 주도록 하여 구동 되게 수정 하였습니다.
또한 원래 소스가 가지는 버그 ( 결과 이미지가 마스크 이미지 크기에 따라 오른쪽 위로 이동 하는 버그 ) 를 수정한 것을 최신 소스버젼에 적용 해 두었습니다.
결과물을 보면 꽤 빛이 뭉개져서 나타나는 형태가 은근 심도가 낮은 렌즈로 조리개를 개방해서 잘 찍어 놓은 느낌이 나게 됩니다만, 이 알고리즘에도 몇가지 단점들이 있습니다. 아마 원래 소스가 간단히 효과만 내겠다는 취지로 만들어 졌을 수도 있으나, 기본적으로 마스크 이미지 크기만큼 전체 영상이 이동 되는 효과가 생기는 것은 물론, 넓이에 대해 제한이 없이 넘겨지다 보니 좌표계 오류가 내제 되어 있습니다.
이런 문제는 추후 차차 수정 해 나가기로 하고, 관심이 있으신 분은 아래 URL 에서 소스를 내려 받거나, git clone 을 하시어 readme.md 를 참조하여 소스를 빌드 할 수 있습니다.
소스 중 bokeh 관련 알고리즘은 libbokeh.* 에 구현이 되어 있으며, 원래 소스와 조금 다르게 설계되어 있으며, 특히 OpenMP로 CPU 내 여러 thread 를 활용 할 수 있도록 만들어 져 있으나, 아직은 100분 활용하지 못하는 부분이 있습니다.
소스를 빌드 하고 나서 아래처럼 기본으로 넣어 둔 예제를 구동 하면,
이미지가 있는 위치에 원래 소스에 대당하는 파일 이름 뒤에 _bokeh 가 붙은 상태로 png 포맷으로 저장 되게 됩니다. 대부분의 jpg 나 png, bmp 를 읽어 올 수 있도록 되어 있으나, 일부 메타 정보로 회전이 들어 가 있는 이미지는 원래 이미지 상태로만 적용 되어 저장 되므로 의도와는 달리 다른 방향으로 돌아 가 있는 결과가 나올수 있습니다.
프로그램 상 마스크 이미지를 RGB 로 읽어 오기는 합니다만, 실제 저장은 흑백 이미지로 해야 하며, RGB 컬러일 경우 3색을 평균한 값으로 처리 하게 되며, 마스크 이미지는 원래 이미지 보다 크기가 작아야 합니다.
해당 프로그램 소스는 원래 공개된 소스와 마찬가지로 Open Source 이며, 별다른 License 가 없었던 이유로 저는 MIT License 를 걸어 두었기 때문에 원래 소스를 마음껏 사용이 가능하나, 헤당 소스에 대한 warranty 는 전혀 없기 떄문에 소스코드를 쓰는 입장에서는 혹시 원래 소스가 가지고 있을 수 있는 버그나, 문제점에 대해 직접 수정을 할 수 있어야 합니다.
추후 OpenMP 에서 그리 높은 CPU 효율이 없는 원래 소스를 좀 더 효과적으로 만들수 잇도록 해 볼 생각 입니다.