반응형
import cv2 as cv
import numpy as np
import random
import math
import copy

roi = cv.imread('sunflower.png') # 이미지 불러오기

k = 6 # 분류될 군집의 갯수

Z = [] # 각 군집의 대표값
X = [] # 샘플 집합. 여기서는 이미지픽셀
Z_xlist = [] # 각 군집에 해당되는 샘플을 저장할 리스트
prev_list = [] # 리스트의 이전상태를 기록할 리스트

for i in range(roi.shape[0]):
    for j in range(roi.shape[1]):
        x = (roi.item(i,j,0),roi.item(i,j,1),roi.item(i,j,2),(i,j)) # 이미지의 각 픽셀의 rgb값+이미지 좌표로 저장
        X.append(x) # 샘플리스트에 저장

checked = [] # 좌표 중복을 방지하기 위한 리스트
for i in range(k): # K개의 군집 초기화
    while True: # 랜덤하게 한 좌표를 뽑아서 Z를 초기화
        iy = random.randint(0,roi.shape[0]-1)
        ix = random.randint(0,roi.shape[1]-1)
        if (iy,ix) not in checked: # 체크한 좌표가 아니면 기록후 무한반복 탈출
            checked.append((iy,ix))
            break
    pos = checked[-1] # 방금 찾은 좌표로 설정
    value = ((roi.item(pos[0],pos[1],0),roi.item(pos[0],pos[1],1),roi.item(pos[0],pos[1],2)),(0,0,0))
    # Z 값은 방금 찾은 좌표의 rgb값 + 각 rgb의 총합(초기에는 0)
    Z.append(value)
    Z_xlist.append([]) # 각 군집에 해당되는 x는 아직 없음

while True:
    for x in X: # 모든 샘플에 대해 검사
        z_list = [] # 각 군집 대표값과 샘플의 유사성을 저장할 리스트
        for z in Z: # 각 군집 대표값과 유사성 측정후 저장
            dist = math.sqrt((x[0] - z[0][0])**2 + (x[1] - z[0][1])**2 + (x[2] - z[0][2])**2)
            # 유클리드 거리로 색의 유사성을 측정했으므로 0에 가까울수록 유사함.
            z_list.append(dist)
        idx = z_list.index(min(z_list)) # 최소값이 가장 유사한 군집
        z_value, z_sum = Z[idx] # 군집 대표값, 총합 가져옴
        z_sum = (z_sum[0] + x[0],z_sum[1] + x[1],z_sum[2] + x[2]) # x의 픽셀값을 총합에 더함
        Z[idx] = (z_value,z_sum) # 군집 갱신. 총합만 달라짐
        Z_xlist[idx].append(x) # 샘플을 해당 군집에 저장
    if prev_list == Z_xlist: # 탈출조건; 군집리스트가 변화가 없으면 알고리즘을 중단.
        break
    prev_list = copy.deepcopy(Z_xlist) # 군집 리스트변화를 측정하기 위해 현재 리스트 기록
    for idx, z in enumerate(Z): # 각 Z값 갱신
        z_value, z_sum = z
        z_value = (z_sum[0] / len(Z_xlist[idx]),
        z_sum[1] / len(Z_xlist[idx]),
        z_sum[2] / len(Z_xlist[idx])
        ) # 대표값은 각 채널값의 평균.
        z = (z_value, (0,0,0)) # 다시 샘플들을 검사해야하므로 총합은 0이고 대표값만 수정
    Z_xlist.clear() # 샘플리스트 초기화
    for i in range(k):
        Z_xlist.append([])

result = np.zeros((roi.shape[0],roi.shape[1],roi.shape[2]),dtype=np.uint8) # 결과이미지

for idx, xlist in enumerate(Z_xlist):
    rand = random.Random()
    rand.seed(idx*10) # 일정한 색 출력을 위해 시드 고정. 시드값은 K의 인덱스 * 10
    b = rand.randint(0,255)
    g = rand.randint(0,255)
    r = rand.randint(0,255)
    for x in xlist: # 해당 군집의 샘플의 위치를 알아내서 군집색으로 표시
        i, j = x[3] 
        result.itemset(i,j,0,b)
        result.itemset(i,j,1,g)
        result.itemset(i,j,2,r)

cv.imshow('roi',roi) # 기존 이미지
cv.imshow('res',result) # 군집화된 이미지
cv.waitKey(0)
cv.destroyAllWindows()

K-Means 알고리즘을 적용하여 컬러영상을 분할하는 프로그램이다.

6개의 군집으로 이미지 화소들을 분할한다.

 

결과 이미지[좌: 원본 이미지, 우: 결과 이미지]

반응형

'영상처리' 카테고리의 다른 글

Canny Edge Detection (Python) 수정  (0) 2022.06.23
Distance Transform  (0) 2021.04.09
Canny Edge Detection (Python)  (0) 2020.04.20
Image Rotation(Python)  (0) 2020.03.23

+ Recent posts