본문 목표
저번 포스트에서 Thresholding 에 대해서 알아봤다.
Thresholding을 하는 이유는 내가 명확하게 보고 싶은 것만 보면서
이미지의 크기를 작게하고, 데이터를 단순화해서 연산처리 속도에서 이득을 얻기 위함이었다.
하지만 저번 포스트에서 배우기로는 살짝 아쉬운 부분은 하나의 임계값을 기준으로 잡아서 극과 극으로 데이터를 처리했었던 것이라 아쉬움이 있을 수 있다.
왜냐하면 야외에서 카메라를 사용해 인물을 찍었다 했을 때,
바닥은 비교적 어둡고, 하늘이 찍혔으면 그 부분은 밝을 것이다.
근데 내가 원하는 것은 그 중간에 있는 object 의 데이터일 경우에는 어떻게 해야 좋을지 고민이 될 것이다.
이런 애매한 상황에서 사용할 수 있는 것이 double thresholding 이다.
opencv에서는 inRange() 라는 함수로 사용 가능하다.
키워드 : double thresholding, inRange(), 이중 임계 값 처리
알아볼 함수 원형
- 이중 임계 값 처리 ( inRange )
...
Mat img = imread("Lenna.png", 0); //이미지를 grayscale로 불러옴
Mat img_inRange;
inRange(img, Scalar::all(151), Scalar::all(200), img_inRange);
...
inRange( src , lower_value, upper_value, dst)
○ src : 입력할 이미지 변수
○ lower_value : threshold 값 1, 임계값 1 로 낮은 값을 입력,
○ upper_value : threshold 값 2, 임계값 2 로 높은 값을 입력
○ dst : 필터가 적용되어 저장될 이미지 변수
이 때, lower_value 와 upper_value 에는 Scalar 값으로 넣어 줘야 한다.
그냥 쉽게 Scalar::all( value ) 를 사용하면 된다.
inRange( ) 함수는 src 이미지에서 lower_value 와 upper_value 사이의 값들만 살려서 dst 이미지에 저장한다.
이 때, 세세하게 분석해보니
살아나는 값의 범위는
lower_value ≤ survive_value ≤ upper_value
이다.
그러니깐, threshold( ) 함수를 사용한다면
threshold < survive_value
위와 같이 초과의 개념인데에 반해
inRange( ) 함수는 임계값 이상과 이하개념 적용된다.
예를 들면,
threshold(img, img_threshold_180, 180, 255, THRESH_BINARY);
threshold(img, img_threshold_150, 150, 255, THRESH_BINARY);
위와 같이 임계값을 150과 180으로 잡은 이미지가 있다고 하고,
inRange(img, Scalar::all(151), Scalar::all(180), img_inRange);
위와 같이 151 부터 180 까지 임계값을 추출한 이미지가 있다고 하자.
img_inRange 에 180을 임계값으로 한 이미지인 img_threshold_180 을 더한 결과는
임계값을 150으로 한 이미지와 결과가 동일했다.
따라서 inRange( ) 범위인 151 ≤ value ≤ 180 에 180 < value 가 더해져서
임계값을 150으로 한 threshold( ) 범위인 150 < value 와 같아진다는 것이다.
그냥 정리하면
threshold( ) 함수는 임계값 초과의 개념을 사용한다면
inRange( ) 함수는 임계값 이상 또는 이하의 개념을 사용한다.
코드 테스트 결과
- CODE
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int ac, char** av) {
Mat img = imread("Lenna.png", 0); //이미지를 grayscale로 불러옴
Mat img_threshold, img_threshold_150;
Mat img_inRange;
inRange(img, Scalar::all(151), Scalar::all(180), img_inRange);
threshold(img, img_threshold, 180, 255, THRESH_BINARY);
threshold(img, img_threshold_150, 150, 255, THRESH_BINARY);
imshow("original", img);
imshow("inRange", img_inRange);
imshow("threshold", img_threshold);
imshow("threshold_150", img_threshold_150);
imshow("making threshold 150", img_inRange + img_threshold);
imshow("sub1", (img_inRange + img_threshold)- img_threshold_150);
imshow("sub2", img_threshold_150 - (img_inRange + img_threshold));
waitKey(0);
return 0;
}
- RESULT
너무나도 많이 봐온 원본 이미지...
위는 임계 값을 150을 적용한 thresholding 이미지 이다.
위는 임계 값을 180을 적용한 thresholding 이미지 이다.
위는 임계 값으로 151과 180 범위를 적용한 inRange( ) 결과 이미지이다.
이론상으로 생각해보면
inRange( 151, 180) 결과에 threshold(180) 결과를 합치면
threshold(150) 과 같아야한다.
이를 확인해보자.
왼쪽의 inRange(151, 180) 과 threshold(180) 을 합친 이미지와
오른쪽의 threshold(150) 이미지가 눈으로 봤을 때에는 결과가 동일해 보인다.
이번에는 연산으로 동일한지 확인을 해보자.
두 이미지를 서로 뺄셈 연산을 한 결과이다.
sub1 은 inRange(151,180) + threshold(180) 에서 threshold(150) 을 빼준 결과 이미지이고,
sub2 는 반대로 threshold(150)에서 inRange(151,180) + threshold(150) 값을 빼준 결과 이미지이다.
임계 값 처리를 한 두 이미지가 다른 부분이 있었다면, 감산 결과 이미지에서 흰색 점이 떠야하는데 보이지 않는 것으로 봐서 같다고 할 수 있다.
이번에는 inRange( ) 범위를 150 부터 180 까지 적용했을 때 결과를 확인해보자.
위의 사진처럼 하얀 점들이 생긴 것을 확인할 수 있다.
sub1 에서 밝은 점이 생겼으므로, inRange(150,180) + threshold(180) 값이
threshold(150) 보다 더 넓은 영역에서 흰색 픽셀을 갖고 있다는 결론을 얻을 수 있다.
따라서 inRange()를 이용해서 double thresholding 이 가능했다.
즉, 이중 임계값 처리를 한줄로 쉽게 구할 수 있었다.
그리고 inRange( ) 는 이상, 이하의 임계값 처리가 되었고,
threshold( ) 는 초과의 개념으로 임계값 처리가 됨을 알 수 있었다.
도움이 되었거나, 문제가 있는 경우 댓글로 알려주세요~!
감사의 댓글은 작성자에게 큰 힘이 됩니다 ^^
'코딩 > OpenCV' 카테고리의 다른 글
[C++ opencv] opening, closing 기법 사용하여 경계 확실히 하기 (0) | 2020.07.03 |
---|---|
[C++ opencv] erode, dilate 사용하여 물체 명확하게 하기 (5) | 2020.07.01 |
[C++ opencv] Thresholding 임계값 처리로 binary 이미지 만들기 (1) | 2020.06.30 |
[C++ opencv] 가우시안 필터 vs 평균 필터, 노이즈제거 승자는? (6) | 2020.06.30 |
[C++ opencv] 가우시안 필터로 노이즈 제거하기 gaussian filter, gaussian blur() (4) | 2020.06.30 |
댓글