Sharpening Filter
영상의 윤곽선 부분을 강조하게 해주는 필터 입니다. 일반적으로 뭉개진(blur) 영상을 선명하게 하기 위해서 사용 합니다.
영상의 경계부분의 대비효과를 증가시킴으로 마치 영상이 선명해지는 것 같은 효과를 얻게 되는 것입니다.
Filter에서 Kernel 의 사이즈가 클수록 상세한 Edge를 검출할 수가 없으며, 작으면 잡음에 민감해진다.
Roberts : 마스크의 크기가 가장 작고 잡음에 민감하다. (2x2)
Prewitt : 널리 사용되는 것으로 대각 방향의 Edge보다 수평수직의 Edge를 찾는데 사용한다.
Sobel : 수평수직보다 대각선 방향에 놓여진 엣지를 찾는데 사용한다.
출처 : http://forum.falinux.com/zbxe/index.php?document_srl=549723∣=lecture_tip
Sharpening의 방법에는 여러가지 필터가 있는데요, 오늘 살펴볼 필터는 Sobel 필터 입니다.
(다루지 않는 Robert,Prewitt는 위의 출처 페이지를 보시면 됩니다.)
void cv::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 : 입력 영상(Mat)
dst : 출력 영상(Mat)
ddepth : 출력영상의 Depth
dx : x축 미분 차수
dy : y축 미분 차수
ksize : Sobel 윈도우의 커널 크기(Filter 크기)
scale :
delta :
3x3 Sobel Kernel & 3x3 Scharr Kernel
Matrix 를 사용한 예제 입니다.
코드
uchar dataA[] { 1,1,1,1,1,1,
1,1,1,1,1,1,
1,1,9,9,1,1,
1,1,9,9,1,1,
1,1,1,1,1,1,
1,1,1,1,1,1};
Mat A(6,6,CV_8U,dataA);
int dx = 1, dy = 0;
int ksize = 3;
Sobel(A,dst3,ddepth,dx,dy,ksize);
Sobel(A,dst4,ddepth,dx,dy,-1);
실행결과
설명
Soble fliter에서 gx 필터를 적용한 결과 입니다.
이미지를 사용한 예제 입니다.
코드(주요사용함수, 전체코드는 아래에 첨부)
int ksize = 3;
int ddepth = CV_32F;
int thresh = 100;
Sobel(srcImage,dstGx,ddepth,1,0,ksize);
Sobel(srcImage,dstGy,ddepth,0,1,ksize);
normalize(abs(dstGx),dstImageGx,0,255,NORM_MINMAX,dtype);
normalize(abs(dstGy),dstImageGy,0,255,NORM_MINMAX,dtype);
magnitude(dstGx,dstGy,dstMag);
normalize(dstMag,dstImageGxy,0,255,NORM_MINMAX,dtype);
threshold(dstMag,dstImageGxy,thresh,255,THRESH_BINARY);
실행결과
1) x축에 대한 Sobel filter 적용 결과
Sobel(srcImage,dstGx,ddepth,1,0,ksize);
normalize(abs(dstGx),dstImageGx,0,255,NORM_MINMAX,dtype);
x축에 대한 filter를 적용하면 위의 그림과 같이 가로로되어 있는 edge를 검출하는데 부족하다는 것을 볼 수 있습니다.
대각선에 대해서도 검출은 하지만, 아래의 y축의 결과와 비교해보면, 검출하는 부분이 확실히 다른 부분이 있다는 점을 확인 할 수 있었습니다.
2) y축에 대한 Sobel filter 적용 결과
Sobel(srcImage,dstGy,ddepth,0,1,ksize);
normalize(abs(dstGy),dstImageGy,0,255,NORM_MINMAX,dtype);
위와 마찬가지 입니다. x축에 대한 filter 결과와 거의 반대의 결과가 나온 다는 것을 확인 할 수 있습니다.
3) x축과 y축에서 Sobel filter를 적용한 결과
Sobel(srcImage,dstGx,ddepth,1,0,ksize);
Sobel(srcImage,dstGy,ddepth,0,1,ksize);
normalize(abs(dstGx),dstImageGx,0,255,NORM_MINMAX,dtype);
normalize(abs(dstGy),dstImageGy,0,255,NORM_MINMAX,dtype);
magnitude(dstGx,dstGy,dstMag);
normalize(dstMag,dstImageGxy,0,255,NORM_MINMAX,dtype);
threshold(dstMag,dstImageGxy,thresh,255,THRESH_BINARY);
위의 Gx와 Gy의 Sobel filter를 magnitude로 이용해 하나의 Mat으로 변환 합니다.
void cv::magnitude(
InputArray x,
InputArray y,
OutputArray magnitude
)
아래의 공식을 사용하여 계산 됩니다.
아래는 전체 코드 입니다.
Matrix 로 테스트한 코드
JNIEXPORT jstring JNICALL
Java_com_tistory_technote_opencvandroid_MainActivity_convertNativeLibtoSharpeningSobel(JNIEnv *env, jobject, jlong addrInput, jlong addrResult) {
Mat &img_input = *(Mat *) addrInput;
Mat &img_result = *(Mat *) addrResult;
cvtColor(img_input, img_result, CV_RGBA2GRAY);
jstring result;
std::stringstream buffer;
Mat srcImage = img_result;
uchar dataA[] { 1,1,1,1,1,1,
1,1,1,1,1,1,
1,1,9,9,1,1,
1,1,9,9,1,1,
1,1,1,1,1,1,
1,1,1,1,1,1};
Mat A(6,6,CV_8U,dataA);
buffer << "A = " <<endl;
buffer << A << endl;
int dx = 1, dy = 0;
int ksize = 3;
Mat kx,ky;
getDerivKernels(kx,ky,dx,dy,ksize);
buffer << "kx = " << kx << endl;
buffer << "ky = " << ky << endl;
Mat kxy = ky * kx.t();
buffer << "kxy = " << kxy << endl;
int ddepth = CV_16S ;
Mat dst1;
sepFilter2D(A,dst1,ddepth,kx,ky);
buffer << "dst1 = sepFilter2D(A,dst1,ddepth,kx,ky);" << endl;
buffer << dst1 << endl;
Mat dst2;
filter2D(A,dst2,ddepth,kxy);
buffer << "dst2 = filter2D(A,dst2,ddepth,kxy);" << endl;
buffer << dst2 << endl;
Mat dst3;
Sobel(A,dst3,ddepth,dx,dy,ksize);
buffer << "dst3 = Sobel(A,dst3,ddepth,dx,dy,ksize);" << endl;
buffer << dst3 << endl;
Mat dst4;
Sobel(A,dst4,ddepth,dx,dy,-1);
buffer << "dst4 = Sobel(A,dst4,ddepth,dx,dy,-1);" << endl;
buffer << dst4 << endl;
Mat dst5;
Scharr(A,dst5,ddepth,dx,dy);
buffer << "dst5 = Scharr(A,dst5,ddepth,dx,dy);" << endl;
const char *cstr = buffer.str().c_str();
result = env->NewStringUTF(cstr);
return result;
}
영상을 사용한 예제 코드 입니다.
JNIEXPORT jstring JNICALL
Java_com_tistory_technote_opencvandroid_MainActivity_convertNativeLibtoSharpeningSobel2(JNIEnv *env, jobject, jlong addrInput, jlong addrResult) {
Mat &img_input = *(Mat *) addrInput;
Mat &img_result = *(Mat *) addrResult;
cvtColor(img_input, img_result, CV_RGBA2GRAY);
jstring result;
std::stringstream buffer;
Mat srcImage = img_result;
int ksize = 3;
int ddepth = CV_32F;
int thresh = 100;
Mat dstGx, dstGy;
Sobel(srcImage,dstGx,ddepth,1,0,ksize);
Sobel(srcImage,dstGy,ddepth,0,1,ksize);
int dtype = CV_8U;
Mat dstImageGx;
normalize(abs(dstGx),dstImageGx,0,255,NORM_MINMAX,dtype);
Mat dstImageGy;
normalize(abs(dstGy),dstImageGy,0,255,NORM_MINMAX,dtype);
Mat dstMag;
magnitude(dstGx,dstGy,dstMag);
Mat dstImageGxy;
normalize(dstMag,dstImageGxy,0,255,NORM_MINMAX,dtype);
threshold(dstMag,dstImageGxy,thresh,255,THRESH_BINARY);
buffer << "dstImageGxy" << endl;
img_result = dstImageGxy.clone();
const char *cstr = buffer.str().c_str();
result = env->NewStringUTF(cstr);
return result;
}
관련문의
- 이메일: [email protected]
- Blog : technote.tistory.com
- Github : https://gitlab.com/Technote/opencv320-android-study