OpenCV | 레이블링

박나연·2021년 5월 21일
0

OpenCV

목록 보기
33/40
post-custom-banner

레이블링

이진화를 통해 주요 객체와 배경 영역을 구분할 수 있다. 배경과 객체를 구분하였다면 다시 각각의 객체를 구분하고 분석하는 작업이 필요하다. 이때 사용할 수 있는 기법이 레이블링이다. 영상내에 존재하는 객체 픽셀 집합에 고유 번호를 매기는 작업으로 '연결된 구성 요소 레이블링'이라고도 한다.

검은색 픽셀은 배경, 흰색 픽셀은 객체로 간주하며 하나의 객체는 한개이상의 인접한 픽셀로 이루어지며 하나의 객체를 구성하는 모든 픽셀 에는 같은 레이블 번호가 지정된다.

특정 픽셀과 이웃한 픽셀의 연결관계는 크기 두가지 방식으로 정의할 수 있다. 첫번째는 특정 픽셀의 상하좌우로 붙어있는 픽셀 끼리 연결되어 있다고 정의하는 4-방향 연결성이다.
다른하나는 상하좌우 뿐 아니라 대각선 방향으로 인접한 픽셀도 연결되어 있다고 간주하는 8-방향 연결성이다.

이진영상에 레이블링을 수행하면 각각의 객체 영역에 고유의 번호가 매겨진 2차원 정수 행렬이 만들어지고, 이를 레이블 맵이라고 부른다.

connectedComponents()

int connectedComponents(InputArray image, OutputArray labels,
int connectivity = 8, int ltype = CV_32S);

image : 입력영상
labels : 출력 레이블 맵 행렬
connectivity : 연결성/ 8또는 4
ltype : 출력 행렬 타입
반환값 : 레이블 개수

입력영상 image에 대해 레이블링을 수행하여 구한 레이블 맵 labels를 반환한다.

void labeling_basic() {

	uchar data[] = {
		0,0,1,1,0,0,0,0,
		1,1,1,1,0,0,1,0,
		1,1,1,1,0,0,0,0,
		0,0,0,0,0,1,1,0,
		0,0,0,1,1,1,1,0,
		0,0,0,1,0,0,1,0,
		0,0,1,1,1,1,1,0,
		0,0,0,0,0,0,0,0,
	};
	Mat src = Mat(8, 8, CV_8UC1, data) * 255;

	Mat labels;
	int cnt = connectedComponents(src, labels);

	cout << "src:\n" << src << endl;
	cout << "label:\n" << labels << endl;
	cout << "number of labels: " << cnt << endl; // 배경영역 포함 4개

}

입력영상을 data로 생성하고, 모든 원소에 255를 곱해 입력영상으로 저장한다. 이를 connectedComponents 함수에 넣어 실행한 후 레이블 맵을 labels 행렬에 저장한다.


레이블링 응용

connectedComponentsWithStats()

int connectedComponentsWithStats(InputArray image, OutputArray labels,
OutputArray stats, OutputArray centroids,
int connectivity = 8, int ltype = CV_32S);

image : 입력영상
labels : 출력 레이블 맵 행렬
stats : 각각의 레이블 영역에 대한 통계 정보를 담은 행렬
centroids : 각각의 레이블 영역의 무게 중심 좌표 정보를 담은 행렬
connectivity : 연결성
ltype : 출력 행렬 타입
반환값 : fpdlqmf rotn

레이블 맵과 각 객체 영역의 통계정보를 한꺼번에 반환한다.

stats 행렬의 각 열은 차례대로 특정 영역을 감싸는 바운딩 박스의 x좌표, y좌표, 가로크기, 세로 크기, 그리고 해당영역의 픽셀 개수를 담고 있다.

centroids 행렬의 행 개수는 레이블 개수와 같고 각각 무게중심의 x좌표와 y좌표를 각 열에 저장한다.

void labeling_stats() {
	Mat src = imread("keyboard.bmp", IMREAD_GRAYSCALE);
	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	Mat bin;
	threshold(src, bin, 0, 255, THRESH_BINARY | THRESH_OTSU);

	Mat labels, stats, centroids;
	int cnt = connectedComponentsWithStats(bin, labels, stats, centroids);

	Mat dst;
	cvtColor(src, dst, COLOR_GRAY2BGR);

	for (int i = 1; i < cnt; i++) {
		int* p = stats.ptr<int>(i);

		if (p[4] < 20) continue; // 잡음 처리

		rectangle(dst, Rect(p[0], p[1], p[2], p[3]), Scalar(0, 255, 255), 2);
	}
	imshow("src", src);
	imshow("dst", dst);

	waitKey();
	destroyAllWindows();
}

profile
Data Science / Computer Vision
post-custom-banner

0개의 댓글