bilateral filter

컴퓨터비전/영상처리 2014. 10. 10. 16:41

1. Bilateral Filter C++ 코드 이해하기

사실 Bilateral Filter 가 수식으로 보면 이해가 안가서 차라리 c++을 보고, 수식을 이해했다.

이 무슨 반대 현상... 이제 수식이.. 나에게 무슨 말을 하는지 전혀 안들려...

 

어쨌던.. c++ 코드 검토 결과 아래와 같이 생각 된다.

 

생성자에서  kernelD 는 kernel size 만큼의 n x n 가우시안 필터이다.

여기서 kernel size는 kernel radius*2 +1 로 항상 홀수 이며

kernel radius(반지름)은  sigma Max 의 값으로 정해지며 이 값은 sigma D, sigma R 중 큰 값*2 이다.


즉 d=10, r=6을 주면  sigma max 는 10 이 되며 kernel radius는 20 kernelD[41][41] 가우시안 필터가 된다. 값을 확인하고 싶으면 가장 center인 kernel[20][20] 의 값을 보면 1로 되어 있다.

 

gaussSimilarity[i] 는 256 까지로써 exp((double)-((i) / twoSigmaRSquared)); 로 표현하고 있다.

나중에 범위 편차를 구할때 사용함. 현재 여기서는 순서대로 읽다보면 당연히 이해 안됨.

여기까지가 생성자 끝.

 

실제 runfilter 부분을 보면 단순히 apply()를 width, height 만큼 돌린 전형적인 image processing 함수의 틀을 가지고 있으며,  실제적으로 apply() 에서 가장 핵심적인 부분은 아래 한줄 이다.

 

weight = getSpatialWeight(m,n,i,j) * similarity(intensityKernelPos,intensityCenter);


 

여기서 getSpatialWeight(m,n,i,j) 함수는 ( kernelD[(int)(i-m + kernelRadius)][(int)(j-n + kernelRadius)] ) 으로 처리되며, 실제로 m과n 이라는 상대위치가  i,j 라는 센터 위치와 얼마나 가우시안 분포적으로 가중치를 가지고 있는가로 해석 된다.

 

similarity(intensityKernelPos,intensityCenter) 함수는 아래와 같이 변하며 이것은 해당 주석과 동일하다

this equals: Math.exp(-(( Math.abs(p-s)) /  2 * this->sigmaR * this->sigmaR));


이것은 m,n 의 값 intensityKernelPos (13) 와 i,j 의 값 intensityCenter  (12) 의 절대 차가 얼만큼 가우시안 유사도를 가지는가 이다. (즉 인접 화소의 픽셀 값이 유사하면 가우시안 가중치를 높게 받고, 인접 화소의 픽셀값이 유사하지 않으면 가우시안 가중치가 적다.  실제 gaussSimilarity[256] 에는 gaussSimilarity[0] 값이 1이고, gaussSimilarity[128] 값이 0.16 이며, gaussSimilarity[255] 값은 0.02 정도이다. 가우시안 분포를 아는 사람이면 gaussSimilarity[33] 을 봐야 하며, 이 값은 0.6323 값으로 대략 우리가 말하는 33 이 1 시그마 정도 될것이며, 그 때의 값이 63% 가 된다는 것이다.

뭐 다른 그림을 보니 엄밀히는 68.3% 에 해당되는 값은 gaussSimilarity[28] 이다.

 

암튼 여기 까지 해서 다시 수식을 풀면 weight = getSpatialWeight(m,n,i,j) * similarity(intensityKernelPos,intensityCenter); 는 아래처럼 변신하며

 

weight = ( kernelD[(int)(i-m + kernelRadius)][(int)(j-n + kernelRadius)] ) * ( this->gaussSimilarity[abs(p-s)]; ) 이다.

 

이 i,j 를 이미지의 width, height 만큼 for 문을 돌린다.  이중 앞, 뒤 모두 이미 배열이 완성된 상태에서 for 문을 i,j 에 대해서 각각 kernel radius *2 +1 만큼 (41x41 번 돌리며) 이 i,j 를 이미지의 width, height 만큼 for 문을 돌린다.

 

즉 4중 for 문으로 완성된다.  (소프트웨어 공학적인, 계산의 복잡도는 빼자, 보통 image post processing은 이정도 될듯. )

 

한마디로 길게 풀어 쓰면 바이레터럴 필터는 입력 화소 x 의 값 I(x) 에 대해 그 이웃 화소들 y 의 값 I(y) 들의 공간(space), 범위(range) 에 대한 가우시안 가중치를 적용한 결과 이다.

이 결과 값은 주변 값들이 유사한 경우에는 노이즈 제거 효과를 주변값이 급격히 바뀌는 에지에는 유사성이 떨어지므로 가우시안 가중치가 작어져서 에지를 보존하는 수학적 특성을 가지고 있다.

 

여기서 공간(space) 의 편차는 센터 a 와  상대 위치 b 에 대한 가우시안 가중치를 , 범위 편차는  그때의 센터 a 의 화소값 m 과 그 때의 상대 위치 b 의 화소값 n 에 대해, m, n 이 얼마나 가우시안 가중치를 가지고 있는 것으로 계산될 수 있다.

 

아래는 해당 full src 이다.

당연히 내가 짠것 아니다. 위에 링크 걸었으니 참고해라.

단 execute 시키는 것은 open cv가 있어야 하며 최신 open cv 2.4.x 버전으로 변경되면서, 일부 신경써줘야 할것들이 있긴 한데 그건 이 장과는 별개의 얘기...

 

bilateral filter c++ 코드를 보면 구글에 검색을 하니 http://code.google.com/p/bilateralfilter/ 에 잘 나온것 같다. 역시 코드도 구글 코드가 대세인듯



'컴퓨터비전/영상처리' 카테고리의 다른 글

지역 특징(Local Feature)을 찾는법  (0) 2014.10.13
기하 연산  (0) 2014.10.10
영상처리의 기본연산  (0) 2014.10.10
화소 연결성  (0) 2014.10.09
이진영상  (0) 2014.10.09