연결 성분 레이블링(CCL)이란? AI에서 이어진 픽셀을 묶어 영역마다 번호를 붙이는 방법
TL;DR
연결 성분 레이블링(CCL)은 정한 이웃 규칙으로 이어진 대상 픽셀을 묶고, 각 덩어리에 서로 다른 정수 번호를 붙이는 방법입니다. 흑백 마스크에서 떨어진 영역을 구별하고 면적·위치를 따로 계산할 때 씁니다. 상하좌우만 볼지 대각선까지 볼지에 따라 덩어리 수가 달라집니다. 번호는 물체 이름이나 영상 간 추적 ID가 아니며 붙은 여러 물체를 자동으로 분리하지도 않습니다. 입력의 전경 정의와 라이브러리별 반환 규칙을 함께 확인합니다.
핵심 3줄 요약
- 핵심 1
같은 연결 덩어리에 같은 번호를 붙입니다. 한 번의 이웃 비교만이 아니라 대상 픽셀을 따라 도달하는 전체 영역을 묶습니다. - 핵심 2
연결 규칙이 결과를 바꿉니다. 2차원에서 4방향은 상하좌우, 8방향은 대각선까지 이웃으로 봅니다. - 핵심 3
영역 수와 실제 물체 수는 구분합니다. 붙은 물체는 합쳐지고 끊긴 물체는 나뉠 수 있습니다. 배경 번호와 영역 통계를 따로 읽습니다.
이 글에서 다룰 내용
- 연결 성분 레이블링의 한 문장 정의
- 작은 마스크로 이해하는 4방향·8방향 연결
- 전경 선택·이웃 탐색·번호 부여의 순서
- OpenCV·SciPy·scikit-image의 입력과 반환 차이
- 오츠 이진화·이미지 분할·데이터 라벨링과의 차이
- 영역별 통계와 실전 체크리스트
- 붙음·끊김·좌표·번호 재사용에서 주의할 점
연결 성분 레이블링을 한 문장으로 정의하면 무엇인가요?
연결 성분 레이블링은 영상에서 정한 값 조건과 이웃 관계를 만족하는 픽셀들의 최대 연결 집합을 찾고, 집합마다 고유한 정수 레이블을 부여하는 영상 처리 방법입니다.
영문명은 Connected Component Labeling이며 CCL, 연결 요소 레이블링, 연결 성분 라벨링이라고도 부릅니다. 이 글은 2차원 영상의 연결 영역을 다룹니다. 최대 연결 집합이란 같은 규칙으로 더 이어 붙일 픽셀이 없는 덩어리이며, 영상에서 면적이 가장 큰 덩어리 하나만 고른다는 뜻은 아닙니다.
배경과 대상을 구분한 이진 마스크를 생각하면 쉽습니다. 배경은 0으로 두고 대상 픽셀을 따라 이어지는 곳마다 번호를 붙입니다. scikit-image 공식 label 문서처럼 같은 정수값인 이웃만 묶는 API도 있으므로 모든 함수가 입력의 비영 값을 똑같이 처리한다고 가정하지 않습니다.
한 줄 정리: CCL은 이미 정한 대상 픽셀의 연결 덩어리를 구별합니다. 픽셀이 무엇을 뜻하는지 학습하는 단계와는 역할을 나눠 봅니다.
쉬운 예시로 이해해 볼까요?
감자나라ai님이 작은 이진 마스크에서 떨어진 얼룩 후보를 세려 한다고 가정해 보겠습니다. 위에서 아래로 네 행은
[1, 1, 0, 0, 0]
,
[0, 1, 0, 1, 0]
,
[0, 0, 1, 0, 0]
,
[0, 0, 0, 0, 1]
입니다. 1은 대상이고 0은 배경입니다.
4방향 연결에서는 왼쪽 위의 세 픽셀이 한 덩어리입니다. 나머지 세 픽셀은 상하좌우로 이어지지 않아 각각 따로 남습니다. 따라서 전경 덩어리는 4개이고 면적은 탐색 순서대로 3·1·1·1픽셀입니다. 여기서 전체 전경 픽셀 수와 덩어리 수는 다릅니다.
8방향 연결에서는 가운데 대각선 픽셀이 왼쪽 위 덩어리와 오른쪽 위의 단독 픽셀을 잇습니다. 이 다섯 픽셀이 같은 번호를 받고 오른쪽 아래 한 픽셀은 따로 남습니다. 전경 덩어리는 2개, 면적은 5·1픽셀입니다. 연결 규칙을 바꿔도 전체 전경은 여전히 6픽셀입니다.
이 예시의 번호 지도·덩어리 수·면적은 Python 표준 라이브러리로 직접 만든 이웃 탐색으로 확인했습니다. OpenCV·SciPy·scikit-image의 함수를 실행한 결과나 실제 얼룩 검출 성능은 아닙니다. 같은 영역 분할이라도 API와 알고리즘이 다르면 붙는 번호의 순서가 달라질 수 있습니다.
쉬운 예시: 모서리로만 닿은 두 칸을 같은 덩어리로 볼지 정하는 문제입니다. 픽셀을 늘리거나 지우지 않고도 연결 규칙만으로 영역 수가 바뀝니다.
왜 AI에서 연결 성분 레이블링이 중요한가요?
픽셀 마스크를 영역별 검토 대상으로 바꿉니다
모델이 대상 여부를 표시했거나 밝기 기준으로 마스크를 만든 뒤에는 어느 픽셀들이 한 덩어리인지 알아야 할 때가 있습니다. 영역마다 번호를 붙인 뒤 특정 부분을 확대하고 크기와 위치를 기록합니다. 모델의 신뢰도와 영역의 번호는 별도 항목으로 관리합니다.
영역을 세는 기준을 명확히 합니다
전경 픽셀 수는 대상이 차지한 크기이고 연결 성분 수는 정한 이웃 규칙에서 떨어진 덩어리 수입니다. 작은 잡음이 늘거나 두 영역 사이에 가는 다리가 생기면 두 숫자는 다르게 변합니다. 개수를 업무 지표로 쓸 때는 무엇을 하나로 셌는지 먼저 정의합니다.
학습 없는 후처리의 실패 원인을 살핍니다
CCL 자체는 정답 자료로 가중치를 학습하지 않습니다. 같은 입력과 같은 연결 조건에서 영역을 계산합니다. 전처리나 분할 모델을 바꿨을 때 새로 붙거나 끊긴 곳을 원본과 대조하면 오류 원인을 좁힐 수 있습니다. 번호가 생겼다는 사실은 물체를 정확히 찾았다는 평가를 대신하지 못합니다.
핵심 인사이트: 자동으로 구하는 것은 연결 덩어리입니다. 실제 상품·문자·결함의 개수로 읽으려면 덩어리와 대상이 대응하는지 별도로 검증합니다.
연결 성분 레이블링은 어떤 순서로 작동하나요?
1. 배경과 연결할 픽셀의 조건을 정합니다
이진 마스크라면 배경과 전경의 두 값을 구분합니다. 어두운 글자를 대상으로 삼는다면 화면의 흰 배경이 전경으로 뒤집히지 않았는지 봅니다. 여러 클래스의 정수 지도에서는 같은 값끼리 연결할지, 특정 클래스만 뽑아 이진 마스크로 만들지 결정합니다.
2. 이웃과 연결 경로를 확인합니다
4방향은 위·아래·왼쪽·오른쪽, 8방향은 여기에 네 대각선을 더합니다. 바로 옆 픽셀뿐 아니라 그 이웃에서 다시 이어지는 픽셀도 같은 덩어리에 포함됩니다. 길고 굽은 경로라도 조건을 만족하면 이어지며, 가까워 보여도 사이가 배경으로 끊겨 있으면 같은 성분이 아닙니다.
3. 연결 덩어리마다 정수 번호를 붙입니다
이웃 탐색으로 한 영역을 모두 방문하거나 임시 번호들의 동등 관계를 합치는 방식 등을 사용합니다. 탐색·병렬화 방식은 구현마다 다릅니다. OpenCV 문서는 여러 CCL 알고리즘을 구분하며 일부만 행 우선 번호 순서를 보장한다고 설명합니다. 번호 크기를 면적 순위나 발견 확률로 해석하지 않습니다.
4. 번호 지도에서 필요한 통계를 계산합니다
출력은 보통 입력과 위치가 대응하는 정수 레이블 지도입니다. 같은 번호의 픽셀을 모으면 면적이나 경계 상자 등을 계산할 수 있습니다. 통계까지 함께 주는 함수와 레이블 지도만 만드는 함수는 다릅니다. 원본과 결과를 겹쳐 잘못 합쳐진 영역과 분리된 영역을 확인합니다.
실전 팁: 원본·입력 마스크·연결 규칙·정수 번호 지도를 함께 보관하세요. 보기 좋은 색칠 이미지만 남기면 실제 레이블과 배경값을 복원하기 어렵습니다.
주요 설정과 결과는 어떻게 읽나요?
OpenCV의 반환 개수에는 배경이 포함됩니다
OpenCV 공식 연결 성분 문서의
connectedComponents
는 8비트 단일 채널 입력에서 4방향 또는 8방향 연결을 계산합니다. 기본 연결은 8방향이며 배경 레이블은 0입니다. 반환 개수 N은 배경을 포함한 전체 레이블 수이므로 전경 성분 수는
N - 1
로 읽습니다.
connectedComponentsWithStats
는 레이블 지도와 함께 통계·중심 좌표도 돌려줍니다. 통계에는 배경 행도 들어가므로 이를 전경 목록에 섞지 않습니다. 면적은 해당 성분의 픽셀 수이며 경계 상자 넓이와는 다릅니다. 출력 레이블은 정수 자료형의 범위를 고려해 저장합니다.
SciPy와 scikit-image는 기본 연결과 값 처리가 다릅니다
SciPy의 ndimage.label 문서는 0을 배경, 모든 비영 값을 대상으로 봅니다. 기본 2차원 구조는 상하좌우 연결입니다. 맞닿은 1과 2도 비영 조건에서는 한 덩어리로 이어질 수 있습니다. 이 글의 직접 만든 작은 배열 검사에서도 비영 규칙과 같은 값 규칙의 차이를 확인했습니다.
scikit-image의
measure.label
은 같은 정수값인 이웃을 연결합니다. 기본 배경은 0이며 2차원에서
connectivity=1
은 4방향,
connectivity=2
는 8방향입니다. 생략하면 해당 차원의 완전 연결을 씁니다. 정수 클래스 지도를 넘기는 것과 먼저 불리언 마스크로 바꾸는 것은 결과가 다를 수 있습니다.
SciPy에서 기본 반환의
num_features
는 전경 특징 수입니다. scikit-image도
return_num=True
일 때 전경 레이블 수를 추가로 받습니다. OpenCV의 배경 포함 반환 개수와 같은 방식으로 빼기 연산을 적용하지 않습니다. 함수별 반환 개수의 정의를 먼저 적습니다.
면적·중심·경계 상자의 단위를 맞춥니다
scikit-image의
regionprops
는 0 레이블을 무시하고 영역의 속성을 구합니다. 기본 중심 좌표는 행·열 순서이며 경계 상자는 최소 행·열과 최대 행·열로 표현하고 최대쪽 끝은 포함하지 않습니다. OpenCV 중심은 x·y 순서이고 상자는 왼쪽·위쪽·폭·높이 통계로 읽습니다. 좌표 순서를 그대로 교환하지 않습니다.
픽셀 간격을 따로 주지 않은 픽셀 면적과 보정한 실제 면적도 구분합니다. 레이블 지도에 구멍이 있으면 그 배경은 성분의 전경 픽셀 수에 포함되지 않습니다. 실제 제품의 제곱밀리미터로 바꾸려면 촬영 배율과 축별 간격 등 별도 보정 조건이 필요합니다.
연결 성분 레이블링과 헷갈리는 용어는 무엇이 다른가요?
오츠 이진화·캐니 에지 검출과의 차이
오츠 이진화는 밝기를 나눌 임계값을 고르고 마스크 생성에 씁니다. CCL은 준비된 대상 픽셀에서 떨어진 영역을 구분합니다. 캐니 에지 검출의 출력은 경계선 후보입니다. 그 선에 CCL을 적용해 얻은 면적은 채워진 물체 내부 면적과 같지 않습니다.
이미지 분할·인스턴스 분할과의 차이
이미지 분할은 픽셀을 영역이나 대상에 할당하는 넓은 과제입니다. CCL은 정해진 값과 연결 규칙으로 덩어리를 나누는 특정 처리입니다. 같은 클래스의 두 물체가 붙어 있으면 하나로 묶일 수 있고 가림으로 한 물체가 끊기면 여러 성분이 됩니다. 개별 물체를 알아보는 인스턴스 분할 전체를 대신하지 않습니다.
데이터 라벨링·객체 추적과의 차이
데이터 라벨링은 사람이 학습·평가에 쓸 정답의 의미와 경계를 정하는 작업을 포함합니다. CCL의 레이블은 연결 영역의 식별 번호입니다. 다음 사진에서도 같은 물체에 같은 번호를 준다는 약속은 없습니다. 프레임 간 동일 대상을 연결하는 객체 추적은 별도 단계입니다.
비교 정리: 이진화는 대상 마스크를 만들고 CCL은 그 안의 연결 영역을 번호로 구별합니다. 의미 라벨, 개별 물체의 정답과 시간에 걸친 추적 ID는 따로 관리합니다.
실전에서는 어디에 쓰이나요?
분할 결과를 영역별 검토와 측정으로 넘깁니다
분리된 얼룩이나 부품 후보의 크기·위치를 정리하는 후처리로 검토합니다. scikit-image의 Label image regions 예제는 임계값 처리, 작은 구멍 보완, 테두리 영역 제거 뒤 레이블링하고 면적으로 영역을 고릅니다. 예제의 순서와 면적 기준이 모든 영상에 맞는다는 뜻은 아닙니다.
작은 잡음과 붙은 영역을 따로 살핍니다
크기가 작은 영역을 제외하는 규칙을 붙일 수 있지만 작은 진짜 대상도 사라집니다. 면적 기준을 적용하기 전후의 후보 목록을 보관하고 누락된 부분을 확인합니다. 테두리 영역 제거도 화면 가장자리에 걸친 실제 대상을 버릴 수 있으므로 후처리마다 제외 이유를 기록합니다.
연결 성분 레이블링을 적용할 때 어떤 순서로 확인하나요?
1. 전경·배경과 연결 규칙을 고정합니다
한 영역으로 셀 대상이 무엇인지 적고 입력 크기·잘라낸 위치·마스크 생성 규칙을 정합니다. 대각선 접촉을 같은 대상으로 볼지도 명시합니다. 여러 클래스가 있다면 클래스별로 처리할지 같은 값 규칙을 쓸지 확인하고 실제 배포에서도 같은 조건을 사용합니다.
2. 작은 입력과 경계 사례를 대조합니다
대각선으로만 닿은 두 칸, 가는 다리로 붙은 영역, 중간이 끊긴 영역을 넣어 봅니다. 전부 배경인 경우와 전부 전경인 경우도 검사합니다. 배경 포함 여부와 통계 행을 확인하고 레이블 지도를 흑백 표시용으로 압축하면서 서로 다른 번호가 사라지지 않는지 봅니다.
3. 합침·쪼개짐과 실제 업무 오류를 평가합니다
원본과 정답에서 여러 물체가 합쳐진 오류, 한 물체가 쪼개진 오류, 작은 대상 누락을 나눠 기록합니다. 총개수만 맞아도 합침과 쪼개짐이 우연히 상쇄됐을 수 있습니다. 설정을 고른 자료와 최종 평가 자료를 분리하고 처리 시간·메모리·라이브러리 버전도 남깁니다.
사용할 때 무엇을 주의해야 하나요?
첫째, 붙은 물체를 알아서 나누지 않습니다. 한 픽셀의 다리도 연결 경로를 만들 수 있습니다. 분리 처리를 추가한다면 원본에서 정말 다른 대상인지 확인합니다. 반대로 끊어진 부분을 잇는 보정은 서로 다른 대상을 합칠 수 있습니다.
둘째, 번호 크기에 의미를 붙이지 않습니다. 큰 번호가 더 큰 영역이나 높은 신뢰도를 뜻하지 않습니다. 알고리즘·병렬화·입력 범위가 달라지면 번호 순서도 달라질 수 있습니다. 원본 파일과 영역의 대응 정보를 따로 저장합니다.
셋째, 클래스 지도를 무심코 이진화하지 않습니다. 서로 다른 의미의 1과 2를 모두 참으로 바꾸면 맞닿은 두 클래스가 합쳐질 수 있습니다. 원하는 클래스 마스크를 선택한 뒤 처리하고 배경 0과 전경 번호의 계약을 유지합니다.
넷째, 정수 지도를 표시용 색깔과 구별합니다. 색은 사람이 보기 위한 표현입니다. 원본 레이블은 충분한 범위의 정수 배열로 보존합니다. 해상도를 바꾸면 가는 틈과 접촉 여부도 변하므로 축소한 결과를 원본과 같은 연결 구조라고 가정하지 않습니다.
주의: 연결 성분 수는 입력 마스크와 이웃 규칙에 따른 결과입니다. 실제 물체 수·결함 판정·면적의 정확성을 보증하지 않으며 업무 기준과 원본 대조가 필요합니다.
자주 묻는 질문
Q1. CCL은 딥러닝 모델인가요?
CCL 자체는 정한 값 조건과 이웃 관계로 영역을 계산하는 방법입니다. 신경망의 예측 마스크 뒤에 붙일 수 있지만 이 단계에서 물체의 의미를 새로 학습하지는 않습니다.
Q2. 4방향과 8방향 중 무엇이 더 정확한가요?
대상의 연결 기준과 영상 해상도에 따라 다릅니다. 대각선 접촉을 같은 영역으로 봐야 하는지 정한 뒤 실제 합침·쪼개짐 오류를 비교합니다. 8방향이 항상 더 정확한 설정은 아닙니다.
Q3. 반환 개수는 모두 물체 수인가요?
아닙니다. 먼저 API가 배경을 포함하는지 확인합니다. 그다음 전경 성분과 실제 대상이 대응하는지 봅니다. 붙은 물체나 끊긴 물체 때문에 두 개수는 다를 수 있습니다.
Q4. 같은 번호면 다음 영상에서도 같은 대상인가요?
아닙니다. 번호는 그 실행에서 연결 영역을 구별합니다. 시간에 걸쳐 같은 물체를 연결하려면 추적이나 대응 절차가 필요합니다. 번호 자체를 영구 식별자로 쓰지 않습니다.
Q5. SciPy와 scikit-image의 label은 같은 결과를 내나요?
기본 연결과 값 처리가 다릅니다. 2차원 기본값에서 SciPy는 상하좌우와 비영 조건, scikit-image는 완전 연결과 같은 정수값 조건을 씁니다. 입력 마스크와 연결 규칙을 맞춘 뒤 비교합니다.
Q6. 작은 영역은 모두 잡음으로 지워도 되나요?
작은 문자 획이나 실제 결함도 작은 성분일 수 있습니다. 크기만으로 일괄 삭제하지 말고 누락 사례를 따로 확인합니다. 제외 기준은 검증 자료에서 정하고 최종 평가에서 다시 확인합니다.
출처
마무리
연결 성분 레이블링은 이어진 대상 픽셀을 묶고 영역마다 번호를 붙이는 방법입니다. 이웃 규칙, 같은 값과 비영 값의 차이, 배경을 포함한 반환 개수를 구분하면 흑백 마스크에서 영역 통계로 넘어가는 흐름을 이해하기 쉽습니다.
감자나라ai님이 처음 적용한다면 작은 마스크에서 4방향과 8방향 결과부터 비교해 보세요. 원본과 번호 지도를 겹쳐 붙은 영역·끊긴 대상·작은 후보를 확인합니다. 픽셀 수, 성분 수와 실제 물체 수를 구분하는 것이 실전 점검의 출발점입니다.
