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;
|
} 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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user