영상분할(image/video segmentation)이란?
어떤 디지털 이미지가 주어져있을때, 그 영상을 여러개의 영역으로 분할하는 것이다.
영상분할은 보통 object classification(물체 분류)에 활용되는데, 우리 눈에는 배경과 어떤 물체 영역이 구별되어 보이지만 실제로 밝기값의 차이가 크거나 미미할 수 있다. 이런 이미지를 0과 255같이 2가지의 값으로 분리시켜 물체의 분류가 용이해지도록 하는 것이다.
입력: gray-scale 이미지
출력: binary image(0과 255 또는 0과 1 같이 2개의 값으로만 이루어진값)
1. Thresholding
영상분할에는 다양한 방법들이 있는데, 그 중 대표적인 방법으로 Thresholding이 있다.
가정
- 분할, 추출하고 싶은 물체와 배경의 밝기값이 다르다.
- 배경영역과 물체영역 내의 밝기값이 단조롭다.(차이가 별로 없다.)
threshoding에선 적절한 threshold를 찾는 것이 가장 중요하다!
고려해야할 문제
- Noise (노이즈)
- Illumination and reflectance (조명이 비균일하게 작용함)
위와 같은 문제를 해결하기 위해, thresholding을 하기전에 smoothing을 적용한다.
실제로 smoothing을 적용한 후 thresholding을 하면 좀 더 좋은 결과를 얻을 수 있다.
2. Global thresholding
: 동일한 threshold을 모든 픽셀에 적용하는 방법
2.1 Basic method
- 임의로 하나의 T를 정하고
- 이 T를 가지고 segmentation 수행해서 2개의 그룹으로 나눈다.
- 각 그룹에 대해서 픽셀들 값들의 평균 m1, m2를 구한다.
- 이 평균 m1, m2로 새로운 threshold를 구해준다. T=0.5x(m1+m2)
- 이 2개의 T가 매우 유사하다면 종료. 그렇지 않으면(차이가 크다면) 새로 구한 T를 가지고 1-4번을 반복한다.)
2.2 Otsu's method
- 만약, 굉장히 좋은 threshold를 가지고 하나의 영상을 두개의 그룹으로 분할했다면, 하나의 그룹에 속한 픽셀들의 값은 유사할테고, 또 다른 그룹의 픽셀값들도 유사하다. 그렇다면, 두 그룹값의 밝기값의 차이는 클것이다.
- 다양한 T를 적용해보고, 그 T를 통해서 얻어진 두개의 영역의 픽셀의 밝기값의 차이를 계산해서 픽셀값의 차이가 크다면 이 T는 좋은 T이다. -> 이 T를 결과로 쓰겠다.
- 잘 구해졌는지 판단하기 위해서 히스토그램을 이용할것임.
- 영상에 대해서 normalized histogram을 계산할것(normalized histogram : 히스토그램 그리고 픽셀수로 각각의 bin을 나눈것)
- 주어져있는 후보 t인 k로 between class-variance를 계산한다. (두 영역의 밝기값 차이가 크다면 between class-variance도 크고, 작다면 작을것임)
- 즉, 우리가 선택해야하는 t k는 variance가 가장 큰 값일때이다.
3. Local (adaptive) thresholding
: 각 픽셀마다 threshold를 다르게 적용하는 방법.
- 각각의 픽셀에 대한 T를 정할 때, 주변의 픽셀값들의 분포를 토대로 구하는 것.
- ADAPTIVE_THRESH_MEAN_C : 𝑇 𝑥, 𝑦 = 𝑚𝑒𝑎𝑛 𝑜𝑓 𝑡ℎ𝑒 𝑏𝑙𝑜𝑐𝑘𝑠𝑖𝑧𝑒 × 𝑏𝑙𝑜𝑐𝑘𝑠𝑖𝑧𝑒 𝑛𝑒𝑖𝑔ℎ𝑏𝑜𝑟ℎ𝑜𝑜𝑑 𝑜𝑓 𝑥, 𝑦 − 𝐶 (주변 픽셀들의 평균- 상수C를 T로 씀)
- ADAPTIVE_THRESH_GAUSSIAN_C : 𝑇 𝑥, 𝑦 = 𝑎 𝑤𝑒𝑖𝑔ℎ𝑡𝑒𝑑 𝑠𝑢𝑚(𝑐𝑟𝑜𝑠𝑠 − 𝑐𝑜𝑟𝑟𝑒𝑙𝑎𝑡𝑖𝑜𝑛 𝑤𝑖𝑡ℎ 𝑎 𝐺𝑎𝑢𝑠𝑠𝑖𝑎𝑛 𝑤𝑖𝑛𝑑𝑜𝑛𝑤) 𝑜𝑓 𝑡ℎ𝑒 𝑏𝑙𝑜𝑐𝑘𝑠𝑖𝑧𝑒 × 𝑏𝑙𝑜𝑐𝑘𝑠𝑖𝑧𝑒 𝑛𝑒𝑖𝑔ℎ𝑏𝑜𝑟ℎ𝑜𝑜𝑑 𝑜𝑓 𝑥, 𝑦 − 𝐶 (가우시안 함수를 활용해서 가중치 평균을 구한 후, 거기서 특정한 상수 C값을 뺀것을 T로 씀)
- Image partitioning : 임의로 영상을 분할해서, 각 분할된 영역별로 동일한 T를 가지도록 thresholding할 수 있다.
example code
// Basic method
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
int main() {
Mat image, thresh;
int thresh_T, low_cnt, high_cnt, low_sum, high_sum, i, j, th;
thresh_T = 200; // 초기 T값
th = 10; // 초기 T값과 다시 구해진 T값의 차이가 일정크기 이하면 멈추는데 사용하는값
low_cnt = high_cnt = low_sum = high_sum = 0;
image = imread("zx.png", 0);
cout << "threshold value:" << thresh_T << endl;
while (1) {
for (j = 0; j < image.rows; j++) {
for (i = 0; i < image.cols; i++) {
if (image.at<uchar>(j, i) < thresh_T) {
low_sum += image.at<uchar>(j, i);
low_cnt++;
}
else {
high_sum += image.at<uchar>(j, i);
high_cnt++;
}
}
}
if (abs(thresh_T - (low_sum / low_cnt + high_sum / high_cnt) / 2.0f) < th) { // 새로운 T값 < th일때
break; // 멈춤
}
else {
thresh_T = (low_sum / low_cnt + high_sum / high_cnt) / 2.0f;
cout << "threshold value:" << thresh_T << endl;
low_cnt = high_cnt = low_sum = high_sum = 0;
}
}
threshold(image, thresh, thresh_T, 255, THRESH_BINARY);
imshow("Input image", image);
imshow("thresholding", thresh);
waitKey(0);
}
// Otsu's algorithm
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
int main() {
Mat image, result;
image = imread("zx.png", 0);
threshold(image, result, 0, 255, THRESH_BINARY | THRESH_OTSU);
imshow("Input image", image);
imshow("result", result);
waitKey(0);
}
// Local(Adaptive) Thresholding
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
int main() {
Mat image, binary, adaptive_binary;
image = imread("zx.png", 0);
threshold(image, binary, 150, 255, THRESH_BINARY);
adaptiveThreshold(image, adaptive_binary, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 85, 15);
imshow("Input image", image);
imshow("binary", binary);
imshow("adaptive binary", adaptive_binary);
waitKey(0);
}
이 게시물은 한동대학교 황성수 교수님의 컴퓨터비전 강의를 공부하며 정리한 내용입니다.
'Computer Vision' 카테고리의 다른 글
[OpenCV] 동영상 분할(Video Segmentation) (0) | 2020.01.19 |
---|---|
[OpenCV] 컬러영상처리(Color Processing) (0) | 2020.01.19 |
[OpenCV] 공간 도메인 필터링(Spatial Filtering) (0) | 2020.01.19 |
[OpenCV] 히스토그램 평활화(Histogram Equalization) (0) | 2020.01.19 |
[OpenCV] 밝기값 변환(Intensity Transformation) (0) | 2020.01.18 |