해당 포스트는 "OpenCV로 배우는 영상 처리 및 응용", "C++ API OpenCV 프로그래밍" 책의 내용을 요약한 것이다.



※ 2D 필터링 함수

- void filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor=Point(-1,-1), double delta=0, int borderType=BOARDER_DEFAULT)

: src에 윈도우 kernel을 적용하여 회선 연산을 해 dst에 저장한다. ddepth는 dst의 깊이를 말하며 -1이라면 src와 같은 깊이를 가진다. anchor는 커널의 중심점을 말하며 디폴트 값이 Point(-1,-1)을 하면 내부적인 처리에 의해 자동적으로 커널의 중심을 가리킨다. delta는 필터링 결과에 더해지는 값이고, borderType은 경계값 처리방식이다. 디폴트 값은 BOARDER_DEFAULT로 BORDER_REFLECT101과 같다. 해당 함수를 통해서 kernel 값에 따라 잡음 제거, 블러딩(스무딩), 샤프닝이 가능하다.


- void sepFilter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernelX, InputArray kernelY, Point anchor=cPoint(-1,-1), double deltac=c0, int borderTypec=cBORDER_DEFAULT)

: sepFilter2D는 filter2D와 kernel을 제외하고 똑같다. 이 함수에서 커널의 의미를 예로써 설명하자면 filter2D 함수에서 모든 요소가 1/9인 3*3 마스크를 커널로 했다고 하자. 이는 sepFilter2D에서 요소가 1/3인 3*1행렬을 kernelX로 1*3 행렬을 kernelY로 한 것과 같다. 참고로 요소가 1/3인 행렬 3*1과 1*3을 곱하면 요소가 1/9인 3*3 행렬이 된다.



※ 스무딩 연산

- void boxFilter(InputArray src, OutputArray dst, int ddepth, Size ksize, Point anchor=Point(-1,-1), bool normalize=true, int borderType=BORDER_DEFAULT)

: filter2D 함수와 비슷하다. 다만 kernel이 아닌 ksize를 매개변수로 받는다. boxFilter는 스무딩 연산을 위한 함수이기 때문에 마스크 모든 요소가 1이다. 다만, normalize가 true라면 마스크 값들이 커널 크기로 나누어져 평균 필터와 같게 된다. 


- void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT)

: 양방향 필터를 수행하는 함수이다. 양방향 필터는 가우스안 함수 필터와 비슷하나 가우시안 함수 필터는 주변 값과 상관없는 에지에 대해서도 스무딩 연산을 해 에지를 없애버리기도 한다. 양방향 필터는 연산의 속도는 가우시안 함수 필터보다 더 걸리지만 에지를 보존하면서 스무딩 연산을 한다. d 값은 각 화소의 이웃을 결정할 지름 즉, 필터 크기이다. 만약 d<0이라면 sigmaSpace에 의해서 필터 크기가 결정되는 데 2*3*sigmaSpace+1로 계산한다. sigmaColor는 컬러 공간에서 필터 표준편차를 말한다. sigmaColor가 큰 값을 가지면 이웃 화소 내의 화소 중에서 색상 공간에서 멀리 떨어진 색상을 혼합하여 유사한 색상으로 뭉쳐서 큰 영역으로 만든다. 


- void medianBlur(InputArray src, OutputArray dst,int ksize)

: src 영상에 대해 ksize*ksize 크기의 마스크를 사용하여 중간값 필터를 한 결과를 dst에 저장한다. 중간값 필터에 관한 자세한 내용은 영상처리 카테고리 포스트에 있다.


- void blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType = BORDER_DEFAULT)

: blur 함수는 위에 나와있는 boxFilter(src, dst, -1, ksize, anchor, true, borderType) 이랑 똑같다.


- Mat getGaussianKernel(int ksize, double sigma, int ktype=CV_64F)

: ksize*1 크기의 카우시안 마스크를 행렬로 반환한다. sigma는 가우시안 표준편차이며, sigma가 0보다 같거나 작을 경우 sigma= 0.3* ((ksize-1) * 0.5 -1) + 0.8로 계산한다. ktype은 마슼의 자료형으로 CV_32F 또는 CV_64F이다. 


- void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType = BORDER_DEFAULT)

: ksize 크기의 2차원 가우시안 마스크와 회선을 수행한다. sigmaX는 X-축 방향으로의 가우시안 커널 표준편차, sigmaY는 Y-축 방향으로의 커널 표준편차이다. sigmaX가 0이 아니고 sigmaY가 0일 경우 sigmaY는 sigmaX 값을 가진다. 둘 다 0일 경우 ksize.width와 ksize.height에 따라 자동적으로 설정된다. 2차원 가우시안 마스크 회선은 다음과 같이 구현할 수도 있다. getGaussianKernel 함수로 x축과 y축 방향 가우시안 커널을 얻고 sepFilter2D 함수로 가우시안 필터링 할 수 있다. 또한 두 가우시안 커널을 곱한 후 filter2D함수로 가우시안 필터링을 할 수 있다. 이에 대해선 다음 코드를 통해서 자세히 확인해보자.

#include "opencv2\opencv.hpp"
using namespace cv;
using namespace std;
int main()
{
	uchar dataA[] = { 1, 2, 4, 5, 2, 1,
		3, 6, 6, 9, 0, 3,
		1, 8, 3, 7, 2, 5,
		2, 9, 8, 9, 9, 1,
		3, 9, 8, 8, 7, 2,
		4, 9, 9, 9, 9, 3 };
	Mat A(6, 6, CV_8U, dataA);

	int ksize = 3;
	double sigma = 0.0;
	Mat kx = getGaussianKernel(ksize, sigma);
	Mat ky = getGaussianKernel(ksize, sigma);

	Mat kxy = ky*kx.t();

	Mat dst1;
	sepFilter2D(A, dst1, -1, kx, ky);
	cout << "dst1 = " << dst1 << endl;

	Mat dst2;
	filter2D(A, dst2, -1, kxy);
	cout << "dst2 = " << dst2 << endl;

	Mat dst3;
	GaussianBlur(A, dst3, Size(ksize, ksize), 0.0, 0.0);
	cout << "dst3 = " << dst3 << endl;

	waitKey();
	return 0;
}

위 코드에서 dst1, dst2, dst3의 결과는 똑같이 나온다. 


+ Recent posts