K-means algorithm 란?
k-평균 클러스터링 알고리즘은 클러스터링 방법 중 분할법에 속한다. 분할법은 주어진 데이터를 여러 파티션 (그룹) 으로 나누는 방법이다. 예를 들어 n개의 데이터 오브젝트를 입력받았다고 가정하자. 이 때 분할법은 입력 데이터를 n보다 작거나 같은 k개의 그룹으로 나누는데, 이 때 각 군집은 클러스터를 형성하게 된다. 다시 말해, 데이터를 한 개 이상의 데이터 오브젝트로 구성된 k개의 그룹으로 나누는 것이다. 이 때 그룹을 나누는 과정은 거리 기반의 그룹간 비유사도 (dissimilarity) 와 같은 비용 함수 (cost function) 을 최소화하는 방식으로 이루어지며, 이 과정에서 같은 그룹 내 데이터 오브젝트 끼리의 유사도는 증가하고, 다른 그룹에 있는 데이터 오브젝트와의 유사도는 감소하게 된다.[7] k-평균 알고리즘은 각 그룹의 중심 (centroid)과 그룹 내의 데이터 오브젝트와의 거리의 제곱합을 비용 함수로 정하고, 이 함수값을 최소화하는 방향으로 각 데이터 오브젝트의 소속 그룹을 업데이트 해 줌으로써 클러스터링을 수행하게 된다. 출저 : 위키피디아
적용 이미지 예시 ( OpenCV 공식 홈페이지 )
이미지 선 성분 검출을 위해서 서전에 이 작업을 거치면 비교적 원하는 결과를 얻을 수 있다.
OpenCVSharp ver 3.2에서는 Kmeans Method를 지원한다.
이 Method의 Parameter의 의미는 여기에서 참조 하길 바란다.
아래는 C#으로 구현된 OpenCVSharp을 활용한 K-means
public static void Kmeans(Mat input, Mat result, int k)
{
using (Mat points = new Mat())
{
using (Mat labels = new Mat())
{
using (Mat centers = new Mat())
{
int width = input.Cols;
int height = input.Rows;
points.Create(width * height, 1, MatType.CV_32FC3);
centers.Create(k, 1, points.Type());
result.Create(height, width, input.Type());
int i = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++, i++)
{
Vec3f vec3f = new Vec3f
{
Item0 = input.At<Vec3b>(y, x).Item0,
Item1 = input.At<Vec3b>(y, x).Item1,
Item2 = input.At<Vec3b>(y, x).Item2
};
points.Set<Vec3f>(i, vec3f);
}
}
Cv2.Kmeans(points, k, labels, new TermCriteria(CriteriaType.Eps | CriteriaType.MaxIter, 10, 1.0), 3, KMeansFlags.PpCenters, centers);
i = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++, i++)
{
int idx = labels.Get<int>(i);
Vec3b vec3b = new Vec3b();
int tmp = Convert.ToInt32(Math.Round(centers.At<Vec3f>(idx).Item0));
tmp = tmp > 255 ? 255 : tmp < 0 ? 0 : tmp;
vec3b.Item0 = Convert.ToByte(tmp);
tmp = Convert.ToInt32(Math.Round(centers.At<Vec3f>(idx).Item1));
tmp = tmp > 255 ? 255 : tmp < 0 ? 0 : tmp;
vec3b.Item1 = Convert.ToByte(tmp);
tmp = Convert.ToInt32(Math.Round(centers.At<Vec3f>(idx).Item2));
tmp = tmp > 255 ? 255 : tmp < 0 ? 0 : tmp;
vec3b.Item2 = Convert.ToByte(tmp);
result.Set<Vec3b>(y, x, vec3b);
}
}
}
}
}
}