이미지 대표색, 평균값이 아니라 클러스터링을 쓰는 이유
이미지에서 "대표 색상"을 뽑는다고 하면 가장 먼저 떠오르는 방법은 모든 픽셀의 RGB 값을 더해서 평균 내는 것입니다. 구현도 가장 간단합니다. 하지만 이 방식은 실제로 이미지에 존재하지 않는 색을 대표색으로 뽑아버리는 근본적인 결함이 있습니다. 모두의 툴의 이미지 색상 추출기는 이 문제를 피하기 위해 단순 평균이 아니라 K-means와 유사한 클러스터링(군집화) 알고리즘을 실제로 코드에서 사용하고 있으며, 이 가이드는 그 이유와 구현 방식을 검증한 내용입니다.
1. 단순 평균의 함정: 없는 색이 만들어진다
이미지의 절반이 순수한 빨강(255,0,0), 나머지 절반이 순수한 파랑(0,0,255)이라고 가정하면, 모든 픽셀 RGB를 산술 평균한 값은 (127,127,127) 근처, 즉 회색에 가까운 보라색이 됩니다. 그런데 이 이미지에는 애초에 보라색 픽셀이 단 하나도 없습니다. 대비되는 두 색이 절반씩 섞인 이미지일수록 평균값은 실제 이미지 어디에도 존재하지 않는 색을 대표색으로 만들어내며, 색상 수를 하나만 뽑는 방식(단순 평균)은 이 문제를 구조적으로 피할 수 없습니다.
2. 클러스터링은 왜 이 문제를 피하는가
클러스터링은 픽셀 전체를 하나로 뭉치지 않고, 비슷한 색끼리 여러 그룹(군집)으로 나눈 뒤 각 군집의 중심값을 대표색으로 삼습니다. 앞의 빨강+파랑 예시라면 빨강 픽셀들이 하나의 군집, 파랑 픽셀들이 또 다른 군집으로 분리되어, 팔레트에는 실제 이미지에 존재하는 빨강과 파랑이 각각 그대로 나타납니다. 존재하지 않는 색이 섞여 나올 여지 자체가 없는 구조입니다.
3. 실제 구현 검증: K-means 유사 알고리즘, 10회 반복
코드를 직접 확인한 결과, 이미지 색상 추출기는 이미지를 80×80px로 축소해 Canvas의 getImageData로 픽셀 배열을 읽은 뒤, 요청한 색상 수만큼 초기 중심점을 픽셀 배열에서 균등 간격으로 샘플링합니다. 이후 "모든 픽셀을 가장 가까운 중심점에 배정 → 각 군집의 평균 RGB로 중심점 재계산"을 10회 반복하는 K-means 유사 클러스터링을 실행합니다. 이는 단순 평균이나 히스토그램 방식이 아니라, 실제로 색상 군집을 찾아가는 반복 최적화 알고리즘입니다. 알파 채널 값이 128 이하(50% 미만 불투명도)인 픽셀은 애초에 군집화 대상에서 제외되어, PNG 투명 배경이 팔레트에 섞여 나오는 것도 방지합니다.
4. 요청한 색상 수보다 적게 나오는 이유도 이 구조 때문
단색 로고나 플랫 일러스트처럼 이미지의 실제 고유 색상 수가 요청한 색상 수보다 적으면, 서로 다른 초기 중심점 여러 개가 반복 과정에서 결국 같은 색으로 수렴합니다. 이 경우 동일한 색으로 수렴한 중심점은 픽셀 수를 합산해 하나로 합치고, 반복 끝에 픽셀을 단 하나도 배정받지 못한 중심점은 결과에서 제외합니다. 그래서 색상 수를 10으로 설정해도 실제 팔레트에는 3~4개 칩만 나오는 경우가 정상적으로 발생하며, 이는 버그가 아니라 클러스터링 구조상 필연적인 결과입니다.
| 방식 | 대표색 결과 | 실제 이미지와 일치? |
|---|---|---|
| 단순 평균 (전체 픽셀 산술평균) | 회색빛 보라 (127,127,127) | 불일치 — 이미지에 없는 색 |
| K-means 클러스터링 (2개 군집) | 빨강(255,0,0) 50%, 파랑(0,0,255) 50% | 일치 — 실제 존재하는 색 그대로 |
5. 대표색(dominant color)과 평균색은 다른 개념이다
대표색은 클러스터링으로 찾은, 이미지에서 실제로 자주 나타나는 색상 군집의 중심값입니다. 평균색은 모든 픽셀 RGB의 단순 산술 평균입니다. 팔레트 추출·브랜드 컬러 확인·UI 배경색 자동 매칭처럼 "이미지에 실제로 어떤 색이 쓰였는가"가 중요한 용도라면 평균이 아니라 클러스터링 기반 대표색을 써야 합니다. HEX 코드를 RGB나 HSL로 바꿔 활용하고 싶다면 색상 변환기를, 특정 색만 정확히 짚어내고 싶다면 HEX to RGB 변환기를 함께 사용하면 됩니다.
자주 묻는 질문
Q. 이 도구는 정말로 단순 평균이 아니라 클러스터링을 쓰나요?
네. 코드 확인 결과 이미지를 80×80px로 축소한 뒤 초기 중심점을 균등 샘플링하고, 픽셀을 가장 가까운 중심점에 배정한 뒤 평균색으로 중심점을 갱신하는 과정을 10회 반복하는 K-means 유사 알고리즘을 사용합니다.
Q. 요청한 색상 수보다 적게 나오면 잘못된 건가요?
아닙니다. 이미지의 고유 색상이 요청 수보다 적으면 여러 초기 중심점이 같은 색으로 수렴해 하나로 합쳐지고, 픽셀을 전혀 배정받지 못한 중심점은 결과에서 제외되므로 정상적인 동작입니다.
Q. 투명 배경 PNG도 정확하게 처리되나요?
네. 알파 채널 값이 128 이하인(50% 미만 불투명도) 픽셀은 애초에 클러스터링 대상에서 제외되므로, 투명 배경 색이 팔레트에 섞여 나오지 않습니다.
Q. 이미지 파일이 서버로 전송되나요?
아니요. 80×80px로 축소한 뒤 Canvas의 getImageData로 픽셀 배열을 브라우저 안에서 직접 읽어 클러스터링하므로 원본 이미지가 브라우저 밖으로 전송되지 않습니다.