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; } vec_t;
typedef struct cluster { typedef struct cluster {
int x, y, w, h;
array_t *points; array_t *points;
point_t centroid;
} cluster_t; } 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 */ /* FAST/FREAK Keypoint */
typedef struct kp { typedef struct kp {
uint16_t x; 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); void imlib_phasecorrelate(image_t *img0, image_t *img1, float *x_offset, float *y_offset, float *response);
/* Clustering functions */ /* 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 */ /* Integral image functions */
void imlib_integral_image_alloc(struct integral_image *sum, int w, int h); void imlib_integral_image_alloc(struct integral_image *sum, int w, int h);

View File

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