| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 백준
- REDIS
- 파이썬
- channels
- 프로젝트
- 채팅
- 개발일지
- WebSocket
- WIL
- WHERE절
- 1주차
- 미니프로젝트
- re-id
- poetry
- vscode
- resnet50
- 마스킹
- Commpot
- 가상환경
- 장고
- 알고리즘
- js
- Git
- 프로그래머스
- Class
- github
- 정보처리기사실기
- 2주차
- sql
- 정보처리기사
- Today
- Total
개발일기
[대표색상 뽑기] 색상 히스토그램 & Kmeans 알고리즘으로 색상 정보 추출하기 본문
- Kmeans 알고리즘만으로 대표 색상 뽑기
2025.04.23 - [Project Portfolio] - [대표색상 뽑기] Kmeans로 색상 정보 추출하기
[대표색상 뽑기 - 연구일지1] Kmeans로 색상 정보 추출하기
목차1. 개요2. K-means 알고리즘3. 거리계산(유클리드, CIEDE2000, 코사인 유사도) 알고리즘4. 색상 정보 추출 코드5. 대표 색상 추출 코드 1. 개요K-means는 데이터의 특징을 바탕으로 유사한 데이터끼리 K
developer908.tistory.com
Kmeans알고리즘에 이어 이번에는 히스토그램을 활용하여 대표색상을 뽑아보려고한다.
그 다음으로 히스토그램과 Kmeans 알고리즘을 합쳐서 색상을 뽑아보면 어떨까?
목차
1. 색상 히스토그램으로 대표색 추출
2. 문제점 파악 - 색상 히스토그램, K-means
3. 개선) K-Means + 히스토그램 가중합 기반 대표색 추출
1. 색상 히스토그램
구성요소

Pixel Value (x축)
- 각 픽셀의 색상 강도 값
- 보통 0~255 범위의 정수 값으로 표현되며, 채널마다 다음과 같은 의미를 갖는다.
- Grayscale: 밝기 (0 = 검정, 255 = 흰색)
- RGB 이미지: R (빨강 채널), G (초록 채널), B (파랑 채널)
- x축은 일반적으로 256개의 bin(구간)으로 나뉘어 있으며,
- 각 bin은 특정 pixel value를 나타낸다.
Frequency (y축)
- 해당 pixel value를 가지는 픽셀의 개수(빈도수) 를 의미
어떻게 대표 색상을 뽑는가? => Peak 찾기
- 히스토그램에서 가장 높은 빈도를 갖는 pixel value를 찾기
- RGB 각각의 채널에 대해 peak를 찾아 (R_peak, G_peak, B_peak)를 조합
코드
# 이미지 색상 히스토그램 그리기
colors = ('r', 'g', 'b')
for i, color in enumerate(colors):
hist = cv2.calcHist([image], [i], None, [256], [0, 256])
plt.plot(hist, color=color)
plt.xlim([0, 256])
plt.title("Color Histogram")
plt.xlabel("Pixel Value")
plt.ylabel("Frequency")
# 가장 높은 빈도를 갖는 pixel value를 찾아서 대표색상 유추하기
peaks = []
for i, c in enumerate(colors):
hist = cv2.calcHist([image], [i], None, [256], [0, 256])
peak = np.argmax(hist)
peaks.append(int(peak))
rgb_color = np.array([peaks[2], peaks[1], peaks[0]], dtype=np.uint8).reshape(1, 1, 3) # RGB order
rgb_color_img = np.tile(rgb_color, (100, 100, 1))
plt.imshow(rgb_color_img)
plt.axis('off')
plt.title("Dominant Color")
결과




이렇게 대표색상이 잘 유추된 경우도 있고,

조금.. 이상한 색상이 유추되기도 한다.
2. 문제점 파악
- 색상 히스토그램
| 색상 히스토그램만으로 대표색을 추출했을 때의 문제점 | |
| 항목 | 설명 |
| 채널 독립성 문제 | 일반적인 색상 히스토그램은 보통 R, G, B 각각 채널별로 따로 본다. → 전체 색상 조합을 고려하지 못함. (R, G, B 독립 가정) |
| 색 조합 표현 불가 | 예를 들어 (200, 150, 100) 같은 색은 단일 채널(R/G/B) peak만 보고는 제대로 찾기 어렵다. |
| 다수의 색 혼합 무시 | 복잡한 장면(여러 색 혼합)에서는 주요 색을 정확히 뽑기 힘들다. (밝기나 명암 차이로 왜곡 가능) |
| 그림자/광량 영향 큼 | 밝은 부분(High Value)나 어두운 부분(Low Value)만 많아도 peak에 영향받는다. |
"R, G, B 각각 peak는 찾지만, 진짜 의미 있는 색 조합은 못 잡음."
- K-means
| K-means만으로 대표색을 추출했을 때의 문제점 | |
| 항목 | 설명 |
| 작은 군집 문제 | 데이터가 적은 군집(=거의 없는 색)도 똑같이 중요한 것처럼 클러스터를 만든다. |
| 비율 반영 안됨 | 각 색상(클러스터)이 이미지 전체에서 차지하는 비율을 고려하지 않음. |
| 대표성 오류 | 실제로는 이미지에 거의 없는 색이 클러스터 중심으로 잡힐 수 있음. |
| Overfitting 가능성 | K를 너무 크게 잡으면, 비슷한 색끼리도 억지로 나눠서 대표색이 많아짐. |
"색상은 나누지만, 많이 쓰인 색인지 적게 쓰인 색인지 구분을 못 한다."
3. K-means와 색상 히스토그램 가중합 기반 대표색 추출
- 이미지 전체를 K-Means로 군집화
- 각 클러스터가 가진 픽셀 수 비율을 히스토그램처럼 사용하여 대표색 결정
- (히스토그램처럼 각 클러스터에 속한 픽셀 수를 세서, 많이 쓰인 색을 중요하게 다룸)
- np.unique(labels, return_counts=True)를 통해 각 클러스터의 빈도를 계산
→ 가장 높은 비율을 가진 클러스터의 중심을 대표색으로 채택
"KMeans는 색상을 잘 나누고, 히스토그램은 사용량을 반영한다.
둘을 같이 쓰면 '정확하고 의미 있는 대표색'을 뽑을 수 있다."
코드
K-means를 사용하여 대표색을 추출했을 때의 코드처럼기준이 되는 색상을 초기 중심점으로 주었다.
initial_centroids = np.array([
[0, 0, 0], # black (검정색)
[0, 0, 128], # navy blue (남색)
[128, 128, 128], # gray (회색)
[255, 255, 255], # white (흰색)
[220, 20, 60], # crimson (진한 빨간색)
[0, 128, 0], # dark green (진녹색)
[255, 215, 0], # gold/yellow (금색, 노란색 계열)
])
# KMeans 적용 (initial_centroids 사용)
kmeans = KMeans(n_clusters=len(initial_centroids), init=initial_centroids, n_init=1, random_state=42)
kmeans.fit(img_data)
# 각 클러스터의 중심 색상과 그 비율
unique, counts = np.unique(kmeans.labels_, return_counts=True)
total_pixels = np.sum(counts)
proportions = counts / total_pixels
# 비율 기준 내림차순 정렬
sorted_indices = np.argsort(-proportions)
# Top-3 dominant colors
top_3_colors = kmeans.cluster_centers_[sorted_indices[:3]].astype(int)
n_init = 1로 준 이유는, 처음 설정한 중심점이 변하지 않도록 하기 위함이다.
내가 원하는 목적은, 제시된 색들을 기준으로 하여 분류하고자 하기 때문에,
초기 중심점(initial_centroids)을 한 번만 사용하여 클러스터링을 수행하고 결과를 그대로 사용하도록 한다.
K-means로 군집화한 후,
각 클러스터가 가진 픽셀 수 비율을 구하여 제일 높은 비율을 가진 클러스터의 중심점 3개를 뽑아 사용했다.
결과
지금까지 실험한 것 중에서 가장 정확하게 나왔다.






엉뚱한 색도 없이 Top-3 Color가 잘 추출된 것을 확인할 수 있었다.
창문, 도로 등 차량의 대표색 추출을 방해하는 요소들을 제거한다면, 정확도가 더 올라갈 것으로 예상된다.
따라서 segmentation 모델을 만들어서 창문, 도로 등을 제외하고,
색상을 뽑고자 하는 객체만을 마스킹하는 모델을 만들어 사용해보려고 한다.
'Project Portfolio' 카테고리의 다른 글
| [차량속성모델 만들기 2] 차량의 종류와 색상 멀티태스크 모델 만들기, RESNET50, Yolo Segmentation 적용 (0) | 2025.05.19 |
|---|---|
| [차량속성모델 만들기 1] 차량의 색상 모델 만들기, RESNET50, Yolo Segmentation 적용 (0) | 2025.05.19 |
| [대표색상 뽑기] Kmeans로 색상 정보 추출하기 (1) | 2025.04.23 |
| 유저 피드백 반영하기(채팅, 마이페이지 업그레이드, 주문취소와 환불처리) (0) | 2023.07.07 |
| [16주차 WIL] 최종프로젝트 4주차 트러블슈팅 (배포관련) 정리 (0) | 2023.07.04 |