개발일기

[대표색상 뽑기] Kmeans로 색상 정보 추출하기 본문

Project Portfolio

[대표색상 뽑기] Kmeans로 색상 정보 추출하기

츄98 2025. 4. 23. 12:46
목차
1. 개요
2. K-means 알고리즘
3. 거리계산(유클리드, CIEDE2000, 코사인 유사도) 알고리즘
4. 색상 정보 추출 코드
5. 대표 색상 추출 코드

 

1. 개요

K-means는 데이터의 특징을 바탕으로 유사한 데이터끼리 K개의 클러스터로 나누는 군집화 알고리즘이다.

이미지의 색상을 추출하는 경우는 색상의 RGB 또는 HSV 값을 데이터로 사용하여 유사한 색상끼리 묶는 방식이다.

 

K-means로 색상 정보를 추출하고자 한 목적은, 영상에 대한 대표 색상을 뽑기 위함이다.

과연 K-means로 대표 색상을 잘 뽑을 수 있을까.

기준으로 잡은 15가지 색과 K-means에 의해 나온 결과색상 사이의 거리를 계산하여

15가지 색상 중 가장 가까운 색상을 매칭하여 대표생삭으로 정의해보고자 한다.

사용된 알고리즘은, K-means와 거리계산(유클리드, CIEDE2000, 코사인 유사도) 알고리즘이다.

 

2. K-means 알고리즘

K-means 알고리즘은 주어진 데이터를 K개의 클러스터(cluster, 군집)로 분할하여, 데이터의 특징이 비슷한 것들끼리 하나의 그룹으로 묶는 대표적인 군집화(Clustering) 기법이다.

  • 비지도학습(Unsupervised Learning) 알고리즘.
  • 반복적으로 클러스터의 중심을 업데이트하여 데이터 간 유사성을 극대화하는 방식이다.

 

2.1  동작 과정

Step 1: 초기화 (Initialization)

  • 데이터를 K개의 클러스터로 나누기로 했다고 가정한다.
  • 알고리즘 시작 전 초기 중심점(centroid) 을 결정한다.
    • 무작위(random)
    • K-means++ 방식(중심점을 가능한 멀리 떨어지도록 선택)
    • 사전 지식 기반의 중심점 지정 등으로 설정할 수 있다.

Step 2: 할당 단계 (Assignment)

  • 각 데이터 포인트를 가장 가까운 중심점(centroid)에 할당한다.
  • 거리를 주로 유클리드 거리로 계산한다.

Step 3: 중심점 갱신 단계 (Update)

  • 클러스터에 속한 데이터들의 평균(mean)을 구해 새로운 중심점으로 설정한다.
  • 각 클러스터의 중심점은 해당 클러스터 내 모든 데이터의 좌표 평균값으로 업데이트된다.

Step 4: 수렴 확인 (Convergence)

  • 클러스터 중심점이 더 이상 변화하지 않거나, 중심점 이동거리가 일정 오차(tolerance) 이하가 될 때까지 반복한다.
  • 최종적으로 중심점이 안정화되면 알고리즘이 종료된다.

 

2.2  주요 파라미터

파라미터 의미 및 설명 기본값
n_clusters 군집(클러스터)의 개수 8
init 초기 중심점 선택 방법
'k-means++', 'random', 사용자 지정 배열 중 선택
'k-means++'
n_init 알고리즘 반복 횟수 (가장 좋은 결과를 선택).
숫자 또는 'auto' 설정 가능
10
max_iter 중심점 업데이트를 최대 몇 번까지 반복할지 제한 300
tol 중심점 이동거리가 이 값 이하가 되면 알고리즘이 수렴했다고 판단 1e-4
random_state 난수 발생의 시드값 설정 (동일한 결과를 얻기 위함) None
algorithm 내부적으로 사용할 알고리즘 방식:
'lloyd', 'elkan' 중 선택
('elkan'은 데이터가 클 때 효율적)
'lloyd'

 

 

2.3  예시

from sklearn.cluster import KMeans

kmeans = KMeans(
    n_clusters=5,          # 클러스터 개수
    init='k-means++',      # 효율적 초기화 방식
    n_init=10,             # 반복 횟수
    max_iter=300,          # 최대 반복 횟수
    tol=1e-4,              # 수렴 조건
    random_state=42,       # 재현성 보장
    algorithm='lloyd'      # 일반적 알고리즘 방식
)

kmeans.fit(data)

# 클러스터 중심값
print(kmeans.cluster_centers_)

 

3. 거리계산 알고리즘

3.1  유클리드 거리

유클리드 거리는 두 점 간의 직선 최단거리를 나타내는 가장 기본적이고 널리 쓰이는 거리 측정 방법으로,

두 점 x=(x1,x2,...,xn), y=(y1,y2,...,yn) 간의 유클리드 거리는 아래와 같이 정의한다.

장점 단점
이해하기 쉽고 계산 속도가 빠름 차원의 저주(고차원에서는 유의미한 거리구분이 어려움)
가장 널리 쓰이며 기본적인 방법 밝기 차이에 너무 민감 (색상 비교 시 문제가 될 수 있음)
# 유클리드 거리 계산
distances = np.linalg.norm(initial_centroids - dominant_color, axis=1)

# initial_centroids : 기준이 되는 색상(결과값)
# dominant_color : K-means로 추출한 색상

 

 

3.2  CIEDE2000 거리

CIEDE2000은 사람의 눈이 색상 차이를 얼마나 민감하게 느끼는지 실제 인지 차이를 반영하는 가장 정확한 색상 비교 알고리즘.

  • RGB가 아니라 Lab 색공간에서만 사용 가능하다.
  • 인간의 시각적 색상 차이를 정확히 모델링하도록 설계되었다.

장점 단점
인간 눈에 가장 정확하게 대응 계산이 상대적으로 복잡하고 느림
밝기, 채도, 색상 모두를 고려 RGB에서 바로 적용 불가능, Lab 변환 필수
색상 판별 및 매칭 정확도 높음 단순한 거리 비교에만 사용 (색상 전용)
  • RGB to Lab 변환이 필수적이다.
  • Lab 색상공간은 사람의 눈이 색상을 인지하는 방식을 수학적으로 모델링한 색상공간이다.
  • L (Lightness): 밝기 (0 = 검정, 100 = 흰색)
  • a (green–red): 초록(-a)부터 빨강(+a)까지의 색상 범위
  • b (blue–yellow): 파랑(-b)부터 노랑(+b)까지의 색상 범위
  • RGB나 HSV 공간과 달리, 밝기(L)와 색상(a,b)이 독립적이다.
  • RGB 색상에서 직접 Lab으로 변환하는 방식은 없다. 중간에 XYZ라는 중간 색상공간을 거쳐야 한다.
# initial_centroids_rgb : 기준이 되는 색상(결과값)
# dominant_color_rgb : K-means로 추출한 색상

def closest_color_ciede2000(dominant_rgb, initial_centroids_rgb):
    # RGB를 [0, 1] 범위로 정규화
    dominant_rgb_norm = np.array(dominant_rgb, dtype=np.float32) / 255
    centroids_rgb_norm = np.array(initial_centroids_rgb, dtype=np.float32) / 255

    # RGB → LAB 변환
    dominant_lab = color.rgb2lab([[dominant_rgb_norm]])[0][0]
    centroids_lab = color.rgb2lab(centroids_rgb_norm.reshape(-1, 1, 3)).reshape(-1, 3)

    dominant_lab = dominant_lab.reshape(1, 3)

    # Delta E 계산 (CIEDE2000)
    delta_e = color.deltaE_ciede2000(centroids_lab, dominant_lab)

    # 가장 가까운 색상 찾기
    nearest_color_idx = np.argmin(delta_e)
    nearest_color = initial_centroids_rgb[nearest_color_idx]

    return nearest_color.astype(int)

 

3.3  코사인 유사도

코사인 유사도는 두 벡터가 가리키는 방향의 유사성을 측정한다. 거리가 아닌 각도(벡터의 방향)를 기준으로 판단한다.

  • 색상의 밝기나 명암보다는 색상 방향(비율)이 유사한지를 판단할 때 유용하다.

  • 값의 범위는 [-1, 1]이며,
  • 1이면 완전히 같은 방향(유사함)
  • 0이면 직교(완전히 무관)
  • -1이면 정반대 방향이다.
장점 단점
벡터의 크기(밝기)에 덜 민감해 톤만 비교 가능 밝기 차이를 무시해서 실제 색상차이를 놓칠 수 있음
높은 차원 데이터에서 효과적 색상 비교 목적으로는 잘 안 쓰임(보조적으로 사용)
# initial_centroids_rgb : 기준이 되는 색상(결과값)
# dominant_rgb : K-means로 추출한 색상

def closest_color_cosine(dominant_rgb, initial_centroids_rgb):
    dominant_rgb = np.array(dominant_rgb).reshape(1, -1)
    centroids_rgb = np.array(initial_centroids_rgb)

    # 코사인 유사도 계산 (값이 클수록 가까운 색상)
    cosine_sim = cosine_similarity(dominant_rgb, centroids_rgb)

    # 가장 가까운 색상 찾기 (유사도 최대)
    nearest_color_idx = cosine_sim.argmax()
    nearest_color = initial_centroids_rgb[nearest_color_idx]

    return nearest_color.astype(int)

 

 

4. 색상 정보 추출 코드

초기 중심점을 랜덤하게 잡는 것이 아니라 특정 문제 (여기서는 색상표)를 활용하여 초기 중심을 지정하고자 했다.

기준으로 잡은 15가지 색상으로 초기중심점을 잡는 "사전 지식 기반 초기화" 방식으로

n_init = 1, init = initial_centroids (15가지 기준 색상 rgb 배열), n_clusters = len(initial_centroids)을 입력값으로 정했다.

또한 재현성을 보장하기 위해 random_state=42를 입력값에 넣었다.

 

def extract_dominant_color(image):
    image = cv2.resize(image, (64, 64), interpolation=cv2.INTER_AREA)
    img_rgb = cv2.cvtColor(crop_center_square(image, 0.9), cv2.COLOR_BGR2RGB)
    img_flat = img_rgb.reshape((-1, 3))
    
    kmeans = KMeans(n_clusters=len(initial_centroids), init=initial_centroids, n_init=1, random_state=42)
    kmeans.fit(img_flat)

	# 가장 빈도수가 높은 색상 클러스터의 중심값 추출
    dominant_cluster_idx = np.bincount(kmeans.labels_).argmax()
    dominant_color = kmeans.cluster_centers_[dominant_cluster_idx]

    return dominant_color.astype(int)

 

 

5. 대표 색상 추출 코드

위에서 나온 dominant_color와 기준으로 잡은 15가지 색상 사이의 거리를 계산하여 가장 가까운 색상을 다시 대표색으로 반환하는 코드를 작성했다. 유클리드 거리, CIEDE2000거리, 코사인 유사도 3가지의 거리계산 알고리즘을 사용해본 결과, CIEDE2000알고리즘에서 가장 유사한 색상을 반환해주었다.

 

nearest_color = closest_color_ciede2000(dominant_color, initial_centroids)

return nearest_color.astype(int)

 

 

 

이렇게 잘 뽑는 경우도 있지만,

 

도로색을 뽑는 경우도 있다. 이미지의 80%를 잘라서 넣었음에도 여전히 도로나 창문같은 요소들이 색상값에 방해를 주는 것 같다.

 

- 색상 히스토그램을 그려 그 중 가장 많은 비율을 가진 색상값을 뽑아 기준색과 매칭시켜보기

- 차량 segment, 창문제외 등 색상값에 방해를 주는 요소를 제거하여 색을 추출하기

 

2가지 방식을 더 시도해보려고 한다.

 

2025.04.28 - [Today I Learned] - [대표색상 뽑기 - 연구일지2] 색상 히스토그램 & Kmeans 알고리즘으로 색상 정보 추출하기

 

[대표색상 뽑기 - 연구일지2] 색상 히스토그램 & Kmeans 알고리즘으로 색상 정보 추출하기

개발일기 [대표색상 뽑기 - 연구일지2] 색상 히스토그램 & Kmeans 알고리즘으로 색상 정보 추출하기 본문 카테고리 없음 [대표색상 뽑기 - 연구일지2] 색상 히스토그램 & Kmeans 알고리즘으로 색상 정

developer908.tistory.com