Python tech/Computer Vision

[Python opencv] K-means 활용, 이미지 색상 개수 줄이기

콜레오네 2021. 5. 16. 20:05

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개 클러스터링

64개 색상으로 군집화

24개 클러스터링

24개 색상으로 군집화

16개 클러스터링

16개 색상으로 군집화

8개 클러스터링

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

 

OpenCV: K-Means Clustering in OpenCV

Goal Learn to use cv.kmeans() function in OpenCV for data clustering Understanding Parameters Input parameters samples : It should be of np.float32 data type, and each feature should be put in a single column. nclusters(K) : Number of clusters required at

docs.opencv.org

 

반응형