mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Update Kmeans.
* Small fixes with arrays handling. * Add generic distance function.
This commit is contained in:
parent
6591558af4
commit
0950d6e52a
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user