Using cv2.kmeans, reduce number of color on image
지난번 "이미지 그림화" 포스팅에 더 개선된 알고리즘을 적용합니다.
실행 시간도 단축되었고, 그림화 및 색상 단순화 효과도 성능이 개선되었습니다.
지난 포스팅 https://tech-diary.tistory.com/19
K Means 알고리즘 ?
- k-means 알고리즘은 수많은 데이터를 k개로 클러스터링(clustering = 군집화) 해주는 알고리즘
- 다양한 데이터셋에 적용이 가능합니다.
- 비지도 학습 기반 알고리즘이기 때문에, 별도의 훈련 과정이 필요하지 않습니다.
더 자세히 알고 싶다면....
위키백과 참고하시면 되겠습니다.
https://ko.wikipedia.org/wiki/K-%ED%8F%89%EA%B7%A0_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98
이미지에서 수십만 가지 색상 데이터를 k개로 줄이기 위해서 cv2.kmeans() 모듈을 적용했습니다.
K-Means 알고리즘을 적용한 "이미지 색상 개수 감소" 함수 (cv2.kmeans 이용)
def kmeansColorCluster(image, clusters, rounds):
"""
Parameters
image <np.ndarray> : 이미지
clusters <int> : 클러스터 개수 (군집화 개수)
rounds <int> : 알고리즘을 몇 번 실행할지 (보통 1)
returns
clustered Image <np.ndarray> : 결과 이미지
SSE <float> : 오차 제곱 합
"""
height, width = image.shape[:2]
samples = np.zeros([ height * width, 3 ], dtype=np.float32)
count = 0
for x in range(height):
for y in range(width):
samples[count] = image[x][y]
count += 1
'''
# compactness : SSE = 오차 제곱 합
# labels : 레이블 배열 (0과 1로 표현)
# centers : 클러스터 중심 좌표 (k개로 군집화된 색상들)
'''
compactness, labels, centers = cv2.kmeans(
samples, # 비지도 학습 데이터 정렬
clusters, # 군집화 개수
None, # 각 샘플의 군집 번호 정렬
# criteria : kmeans 알고리즘 반복 종료 기준 설정
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,
10000, # max_iter
0.0001), # epsilon
# attempts : 다른 초기 중앙값을 이용해 반복 실행할 횟수
attempts = rounds,
# flags : 초기 중앙값 설정 방법
flags = cv2.KMEANS_PP_CENTERS)
centers = np.uint8(centers)
res = centers[labels.flatten()]
# 결과 이미지, 초기 중앙값, 오차제곱합 반환
return res.reshape((image.shape)), centers, round(compactness, 4)
경우에 맞게 변경하면 좋을 파라미터를 설명하겠습니다.
criteria : kmeans 알고리즘의 종료 기준입니다. 튜플 ( type, max_iter, epsilon ) 3개 값을 정해주어야 합니다.
- type : 종료 기준 타입입니다. 3가지 경우가 있습니다.
- type 1) TERM_CRITERIA_EPS = 정확도가 epsilon에 도달하면 종료
- type 2) TERM_CRITERIA_MAX_ITER = 반복 횟수가 max_iter에 도달하면 종료
- type 3) TERM_CRITERIA_EPS + TERM_CRITERIA_MAX_ITER = 위 두 가지 타입 중 하나라도 만족하면 종료
- epsilon : kmeans clustering의 정확도
- max_iter : kmeans clustering의 반복 횟수
flags : 초기 중앙값 설정 방법 (kmeans에서 초기 k개의 중앙값을 어떻게 설정하느냐에 따라 결과 차이가 존재합니다.)
- flag 1) cv2.KMEANS_RANDOM_CENTERS = 초기 중앙값을 랜덤 지정 (가장 기본적인 방법)
- flag 2) cv2.KMEANS_PP_CENTERS = K-means++ 알고리즘을 이용하여 지정 (시간이 소요되지만, 랜덤 지정보다 정확도가 좋음)
- flag 3) cv2.KMEANS_USE_INITIAL_LABELS = 사용자가 k개의 중앙값 지정
예시를 살펴보겠습니다.
영화 어바웃 타임 포스터를 가지고 테스트해보겠습니다.
원본 이미지
64개 클러스터링
24개 클러스터링
16개 클러스터링
8개 클러스터링
- 클러스터 개수(= K 값)가 줄어들수록, 이미지가 더 그림처럼 변경된 것을 확인할 수 있습니다.
- 적절한 K 값은 SSE(오차제곱합)이 가장 작은 값을 값으로 설정하면 좋겠죠.
- 고정된 K 값에서 가장 성능이 높게 클러스터링 하기 위해서는 attempts 즉, 반복 횟수를 증가시켜주면 됩니다. 초기 중앙값을 다르게 설정하여 가장 성능이 좋게 군집화한 결과를 반환하게 됩니다.
시간 복잡도
cv2.kmeans의 시간 복잡도는
- 클러스터링 개수 (K 값이 커질수록 증가)
- 데이터 백터 개수 image size (이미지 크기가 커질수록 증가)
- 이미지 차원 (2차원 이미지(=흑백 이미지)보다 3차원 이미지(=RGB 컬러 이미지) 일수록 증가)
위 3가지 요소에 비례하여 증가합니다.
cv2.kmeans 모듈에 대해 상세히 알고 싶다면
공식 문서를 참조하면 되겠습니다.
https://docs.opencv.org/master/d1/d5c/tutorial_py_kmeans_opencv.html
'Python tech > Computer Vision' 카테고리의 다른 글
[Python CV] 세그멘테이션을 통해 이미지 잘라내고 회전하기 (2) | 2021.08.04 |
---|---|
[Python opencv] cv2 색상 구분 기준으로 라인 그리기 (0) | 2021.05.16 |
[Python OpenCV] 이미지를 그림화 하기 (색 일반화) (0) | 2021.04.05 |
[camelot] line_scale이란? (opencv로 라인 추출) (0) | 2021.03.09 |
[camelot] read_pdf() 파라미터 (0) | 2021.02.08 |