From 0950d6e52ad95e34b74d96f9117c31f462e105e0 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 16 Sep 2016 03:31:34 +0200 Subject: [PATCH] Update Kmeans. * Small fixes with arrays handling. * Add generic distance function. --- src/omv/img/imlib.h | 7 +++- src/omv/img/kmeans.c | 94 +++++++++++++++++++++++--------------------- 2 files changed, 55 insertions(+), 46 deletions(-) diff --git a/src/omv/img/imlib.h b/src/omv/img/imlib.h index 7ce3867ad..dd468d9c4 100644 --- a/src/omv/img/imlib.h +++ b/src/omv/img/imlib.h @@ -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); diff --git a/src/omv/img/kmeans.c b/src/omv/img/kmeans.c index c1984f248..e217c0a13 100644 --- a/src/omv/img/kmeans.c +++ b/src/omv/img/kmeans.c @@ -9,6 +9,7 @@ #include #include #include +#include #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; jpoints, 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; jcentroid; + 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; ipoints, 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; icentroid); + 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; ix, 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);