해당 포스트는 "OpenCV로 배우는 영상 처리 및 응용", "C++ API OpenCV 프로그래밍" 책의 내용을 요약한 것이다.
※ 모폴로지 연산
- Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1))
: 모폴로지 연산을 위한 크기 ksize, 모양 shape 요소값 1의 마스크를 반환한다. shape는 다음과 같은 값들이 있다. 만약 shape가 MORPH_RECT이라면 사각형 마스크를 갖는다. MORPH_ELLIPSE라면 ksize의 사각형에 내접한 타원 모양을 갖는 마스크를 갖는다. MORPH_CROSS라면 anchor.x와 anchor.y를 중심으로 십자형 모양을 가진다.
- void erode(InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations=1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue())
: src를 kernel 마스크를 통해 침식 연산을 iterations 번 수행해 dst에 저장한다.
- void dilate(InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations=1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue())
: src를 kernel 마스크를 통해 팽창 연산을 iterations 번 수행해 dst에 저장한다.
- void morphologyEx(InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor = Point(-1,-1), int iterations=1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue())
: src를 kernel 마스크를 통해 op에 해당하는 연산을 iterations번 수행해 dst에 저장한다. op의 값들은 다음과 같다.
1. op = MORPH_OPEN : dst = dilate(erode(src, kernel), kernel)
2. op = MORPH_CLOSE : dst = erode(dilate(src, kernel), kernel)
3. op = MORPH_GRADIENT : dst = dilate(src, kernel) - erode(src, kernel)
4. op = MORPH_TOPHAT : dst = src - open(src, kernel)
5. op = MORPH_BLACKHAT : dst = close(src, kernel) - src
'OpenCV 프로그래밍' 카테고리의 다른 글
| phaseCorrelate (0) | 2017.06.27 |
|---|---|
| dft, idft, mulSpectrums, 저주파/고주파 통과 필터 (0) | 2017.06.26 |
| getDerivKernels, Sobel, Scharr, Laplacian, LoG (0) | 2017.06.26 |
| filter2D, boxFilter, bilateralFilter, blur, GaussianBlur (0) | 2017.06.25 |
| 경계값 채우기(copyMakeBorder, borderIntrepolate) (0) | 2017.06.25 |
getDerivKernels, Sobel, Scharr, Laplacian, LoG
해당 포스트는 "OpenCV로 배우는 영상 처리 및 응용", "C++ API OpenCV 프로그래밍" 책의 내용을 요약한 것이다.
※ 1차 미분 필터링
- void getDerivKernels(OutputArray kx, OutputArray ky, int dx, int dy, int ksize, bool normalize=false, int ktype= CV_32F)
: 영상에서 미분을 계산하기 위한 ksize*1 크기의 선형 마스크를 kx와 ky에 저장한다. dx와 dy는 행과 열의 미분계수인데 보통 1이 들어간다. ksize는 커널의 크기로 ksize=CV_SCHARR(-1)이면 Scharr 3*3 커널이 생성되고 ksize=1,3,5,7 이면 Sobel 커널이 생성된다. setFilter2D 함수에서 생성된 커널을 사용하여 필터링할 수 있고 2D 필터는 ky*kx.t() 로 얻을 수 있다.
- void Sobel(InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize=3, double scale=1, double delta =0, int borderType=BORDER_DEFAULT)
: src에 Sobel 마스크를 적용하여 dst에 저장한다. dx와 dy는 행과 열에 대한 미분 차수이고 ksize는 소벨 윈도우 마스크의 크기를 말한다. 만약 dx=1, dy=0 이면 x 방향 마스크가 되고 dx=0, dy=1이면 y방향 마스크가 된다. ksize가 -1 이면 Scharr 3*3 마스크가 적용된다.
- void Scharr(InputArray src, OutputArray dst, int ddepth, int dx, int dy, double scale=1, double delta=0, int borderType=BORDER_DEFAULT)
: src에 Scharr 마스크를 적용하여 dst에 저장한다.
※ 2차 미분 필터링
- void Laplacian(InputArray src, OutputArrya dst, int ddepth, int ksize=1, doule scale=1, double delta=0, int borderType=BORDER_DEFAULT)
: src에 대해서 라플라시안 마스크를 적용한 후 dst에 저장한다.
- LoG(Laplacian of Gaussian) 필터링
: 라플라시안 마스크는 잡음에 상당히 민감하다. 그래서 잡음을 줄이기 위해서 가우시안 마스크로 스무딩을 하여 잡음 제거 후 라플라시안을 적용할 수 있다. 이렇게 가우시안 마스크와 라플라시안을 같이 계산한 게 LoG 필터링이다. 에지는 LoG 필터링된 결과에서 0-교차하는 위치이다. 0-교차는 자신과 옆 픽셀의 곱이 마이너스 인 것을 말한다. 다음은 LoG(x,y)를 계산하는 수식이다.
#include "opencv2\opencv.hpp" using namespace cv; using namespace std; void ZeroCrossing(Mat &src, Mat &dst, int threshold); int main() { Mat srcImage = imread("lena.jpg", IMREAD_GRAYSCALE); if (srcImage.empty()) return -1; const int ksize = 9; float logArr[ksize*ksize]; int s, t, k = 0; float g; float sigma= 0.3f*(ksize/2-1.0f) + 0.8f; for (s = -ksize / 2; s <= ksize / 2; s++) //LoG 필터 마스크 생성 for (t = -ksize / 2; t <= ksize / 2; t++) { g = exp(-((float)s*s + (float)t*t) / (2 * sigma*sigma)); g *= (1 - ((float)s*s + (float)t*t) / (2 * sigma*sigma)); g /= (3.141592f*sigma*sigma*sigma*sigma); logArr[k++] = -g; } Mat logKernel(ksize, ksize, CV_32F, logArr); Mat logImage; filter2D(srcImage, logImage, CV_32F, logKernel); Mat dstImage; ZeroCrossing(logImage, dstImage, 1); //0-교차점 탐색 후 에지 검출 imshow("dstImage", dstImage); waitKey(); return 0; } void ZeroCrossing(Mat &src, Mat &dst, int th) { int x, y; double a, b; Mat zeroCrossH(src.size(), CV_32F, Scalar::all(0)); Mat_<float> _src(src); for (y = 1; y<src.rows - 1; y++) //가로 방향으로 0교차점 탐색 for (x = 1; x<src.cols - 1; x++) { a = _src(y, x); b = _src(y, x + 1); if (a == 0) a = _src(y, x - 1); if (a*b < 0) zeroCrossH.at<float>(y, x) = fabs(a) + fabs(b); else zeroCrossH.at<float>(y, x) = 0; } Mat zeroCrossV(src.size(), CV_32F, Scalar::all(0)); for (y = 1; y<src.rows - 1; y++) //세로 방향으로 0교차점 탐색 for (x = 1; x<src.cols - 1; x++) { a = _src(y, x); b = _src(y + 1, x); if (a == 0) a = _src(y - 1, x); if (a*b < 0) zeroCrossV.at<float>(y, x) = fabs(a) + fabs(b); else zeroCrossV.at<float>(y, x) = 0; } Mat zeroCross(src.size(), CV_32F, Scalar::all(0)); add(zeroCrossH, zeroCrossV, zeroCross); threshold(zeroCross, dst, th, 255, THRESH_BINARY); }
'OpenCV 프로그래밍' 카테고리의 다른 글
| dft, idft, mulSpectrums, 저주파/고주파 통과 필터 (0) | 2017.06.26 |
|---|---|
| getStructuringElement, erode, dilate, morphologyEx (0) | 2017.06.26 |
| filter2D, boxFilter, bilateralFilter, blur, GaussianBlur (0) | 2017.06.25 |
| 경계값 채우기(copyMakeBorder, borderIntrepolate) (0) | 2017.06.25 |
| OpenCV 히스토그램 생성, 평활화, 역투영 (0) | 2017.06.24 |