Update Kmeans.

* Small fixes with arrays handling.
* Add generic distance function.
This commit is contained in:
iabdalkader 2016-09-16 03:31:34 +02:00
parent 6591558af4
commit 0950d6e52a
2 changed files with 55 additions and 46 deletions

View File

@ -281,10 +281,13 @@ typedef struct _vector {
} vec_t;
typedef struct cluster {
int x, y, w, h;
array_t *points;
point_t centroid;
} cluster_t;
// Return the distance between a cluster centroid and some object.
typedef float (*cluster_dist_t)(int cx, int cy, void *obj);
/* FAST/FREAK Keypoint */
typedef struct kp {
uint16_t x;
@ -481,7 +484,7 @@ float imlib_template_match_ex(image_t *image, image_t *template, rectangle_t *ro
void imlib_phasecorrelate(image_t *img0, image_t *img1, float *x_offset, float *y_offset, float *response);
/* Clustering functions */
array_t *cluster_kmeans(array_t *points, int k);
array_t *cluster_kmeans(array_t *points, int k, cluster_dist_t dist_func);
/* Integral image functions */
void imlib_integral_image_alloc(struct integral_image *sum, int w, int h);

View File

@ -9,6 +9,7 @@
#include <float.h>
#include <limits.h>
#include <arm_math.h>
#include <stdio.h>
#include "imlib.h"
#include "array.h"
#include "xalloc.h"
@ -20,9 +21,10 @@ static cluster_t *cluster_alloc(int cx, int cy)
cluster_t *c=NULL;
c = xalloc(sizeof(*c));
if (c != NULL) {
/* initial centroid */
c->centroid.x = cx;
c->centroid.y = cy;
c->x = cx;
c->y = cy;
c->w = 0;
c->h = 0;
array_alloc(&c->points, NULL);
}
return c;
@ -35,14 +37,14 @@ static void cluster_free(void *c)
xfree(cl);
}
static void cluster_reset(array_t *clusters)
static void cluster_reset(array_t *clusters, array_t *points)
{
int k = array_length(clusters);
/* reset clusters */
for (int j=0; j<k; j++) {
// Reset all clusters
for (int j=0; j<array_length(clusters); j++) {
cluster_t *cl = array_at(clusters, j);
// array_resize(cl->points, 0);
while (array_length(cl->points)) {
array_push_back(points, array_pop_back(cl->points));
}
array_free(cl->points);
array_alloc(&cl->points, NULL);
}
@ -50,26 +52,34 @@ static void cluster_reset(array_t *clusters)
static int cluster_update(array_t *clusters)
{
int k = array_length(clusters);
/* update clusters */
for (int j=0; j<k; j++) {
point_t sum={0,0};
// Update clusters
for (int j=0; j<array_length(clusters); j++) {
cluster_t *cl = array_at(clusters, j);
point_t old_c = cl->centroid;
int cx = cl->x, cy = cl->y;
int cl_size = array_length(cl->points);
/* sum all points in this cluster */
// Sum all points in this cluster
for (int i=0; i<cl_size; i++) {
point_t *p = array_at(cl->points, i);
sum.x += p->x;
sum.y += p->y;
kp_t *p = array_at(cl->points, i);
cl->x += p->x;
cl->y += p->y;
// Find out the max x and y while we're at it
if (p->x > cl->w) {
cl->w = p->x;
}
if (p->y > cl->h) {
cl->h = p->y;
}
}
cl->centroid.x = sum.x/cl_size;
cl->centroid.y = sum.y/cl_size;
if (point_equal(&cl->centroid, &old_c)) {
/* cluster centroid didn't move */
// Update centroid
cl->x = cl->x/cl_size;
cl->y = cl->y/cl_size;
// Update cluster size
cl->w = (cl->w - cl->x) * 2;
cl->h = (cl->h - cl->y) * 2;
if (cl->x == cx && cl->y == cy) {
// Cluster centroid did not change
return 0;
}
}
@ -77,54 +87,50 @@ static int cluster_update(array_t *clusters)
return 1;
}
static void cluster_points(array_t *clusters, array_t *points)
static void cluster_points(array_t *clusters, array_t *points, cluster_dist_t dist_func)
{
int n = array_length(points);
int k = array_length(clusters);
for (int i=0; i<n; i++) {
// Add objects to cluster
while (array_length(points)) {
float distance = FLT_MAX;
cluster_t *cl_nearest = NULL;
point_t *p = array_at(points, i);
kp_t *p = array_pop_back(points);
for (int j=0; j<k; j++) {
for (int j=0; j<array_length(clusters); j++) {
cluster_t *cl = array_at(clusters, j);
float d = point_distance(p, &cl->centroid);
float d = dist_func(cl->x, cl->y, p);
if (d < distance) {
distance = d;
cl_nearest = cl;
}
}
if (cl_nearest == NULL) {
__asm__ volatile ("BKPT");
}
/* copy point and add to cluster */
// Add pointer to point to cluster.
// Note: Objects in the cluster are not free'd
array_push_back(cl_nearest->points, p);
}
}
array_t *cluster_kmeans(array_t *points, int k)
array_t *cluster_kmeans(array_t *points, int k, cluster_dist_t dist_func)
{
// Alloc clusters array
array_t *clusters=NULL;
/* alloc clusters array */
array_alloc(&clusters, cluster_free);
/* select K clusters randomly */
// Select K clusters randomly
for (int i=0; i<k; i++) {
int pidx = rng_randint(0, array_length(points)-1);
point_t *p = array_at(points, pidx);
kp_t *p = array_at(points, pidx);
array_push_back(clusters, cluster_alloc(p->x, p->y));
}
int cl_changed = 1;
do {
/* reset clusters */
cluster_reset(clusters);
// Reset clusters
cluster_reset(clusters, points);
/* add points to clusters */
cluster_points(clusters, points);
// Add points to clusters
cluster_points(clusters, points, dist_func);
/* update centroids */
// Update centroids
cl_changed = cluster_update(clusters);
} while (cl_changed);