[OpenCV] 필터링 기본

이번 글에서는 필터링에 대해 기본적인 방법을 알아보겠습니다.

필터(filter)라는 말은 일상에서 보통, ‘원하지 않은 것들을 걸러내고, 원하는 것은 통과시키는 것’을 말합니다.
영상에서의 필터링이란, 영상에서 원하지 않은 정보는 걸러내고, 원하는 정보는 통과시키는 작업을 말합니다.
영상의 잡음을 제거하는 것을 필터링이라고 할 수 있으며, 샤프하게 만드는 것 또한 필터링이라고도 할 수 있습니다.
영상의 필터링은 마스크라는 행렬을 이용하며, 그 모양은 3 x 3 또는 5×5, 십자가 모양일 수도 있습니다.
가운데 회색 부분은 고정점이라고 하며, 고정점을 기준으로 필터링 연산을 하게 됩니다.

3 x 3, 5 x 5 마스크

원하는 필터링 결과를 얻기 위해 적합한 마스크를 이용하여 연산을 진행하면 되고, 아래에는 3X3 마스크를 이용하여 필터링 연산이 수행되는지 간단히 알아보겠습니다.

필터링 연산은 마스크 행렬이 입력 영상 위를 이동하며 모든 픽셀에 대하여 마스크 연산을 수행합니다. 이미지로 봤을 경우 아래와 같습니다.

모든 픽셀에 대한 연산

마스크 연산은 마스크 행렬과, 입력 영상의 같은 위치에 있는 값을 곱한 후 모두 더하는 방식입니다.
수식으로 보면 아래와 같습니다.

//(마스크 행렬: m, 입력 영상: f, 출력 영상: d, 픽셀 위치 좌표: x, y)
d(x, y) = m(0, 0) * f(x - 1, y - 1) + m(1, 0) * f(x, y - 1) + m(2, 0) * f(x + 1, y - 1)
	+ m(0, 1) * f(x - 1, y) + m(1, 1) * f(x, y) + m(2, 0) * f(x + 1, y)
	+ m(0, 2) * f(x - 1, y + 1) + m(1, 2) * f(x, y + 1) + m(2, 2) * f(x + 1, y + 1)

x, y 좌표가 0, 0 인경우 -1에 대한 연산도 하게 되는데, OpenCV에서는 영상의 가장자리를 추가하여 가상의 픽셀을 만들어 연산합니다.

가상 픽셀

가상 픽셀을 채우는 방식은 OpenCV에서 아래와같이 BorderTypes enum 값에 따라 달라집니다.

enum BorderTypes {
    BORDER_CONSTANT    = 0, //!< `iiiiii|abcdefgh|iiiiiii`  with some specified `i`
    BORDER_REPLICATE   = 1, //!< `aaaaaa|abcdefgh|hhhhhhh`
    BORDER_REFLECT     = 2, //!< `fedcba|abcdefgh|hgfedcb`
    BORDER_WRAP        = 3, //!< `cdefgh|abcdefgh|abcdefg`
    BORDER_REFLECT_101 = 4, //!< `gfedcb|abcdefgh|gfedcba`
    BORDER_TRANSPARENT = 5, //!< `uvwxyz|abcdefgh|ijklmno`
    ....

이런 연산을 OpenCV에서는 filter2D라는 함수를 제공해줍니다.

@param src 이미지.
@param dst 결과 이미지. src와 같은 사이즈, 같은 채널이어야함.
@param ddepth 결과 영상의 깊이.
@param kernel 커널. 1채널 실수형 행렬.
@param anchor 고정점. Point(-1, -1)의 경우 커널의 중심을 고정점으로 판단.
@param delta 연산 후 추가 Add 값
@param borderType 가상 픽셀 방식
 */
CV_EXPORTS_W void filter2D( InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor = Point(-1,-1), double delta = 0, int borderType = BORDER_DEFAULT );

이번 글에서는 간단히 필터링 기본 개념을 알아봤습니다. 다음 글에서 실제 필터링을 적용해보겠습니다.