-
Notifications
You must be signed in to change notification settings - Fork 53
/
MeanShift.cpp
123 lines (107 loc) · 3.95 KB
/
MeanShift.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <stdio.h>
#include <math.h>
#include "MeanShift.h"
using namespace std;
#define CLUSTER_EPSILON 0.5
double euclidean_distance(const vector<double> &point_a, const vector<double> &point_b){
double total = 0;
for(int i=0; i<point_a.size(); i++){
const double temp = (point_a[i] - point_b[i]);
total += temp*temp;
}
return sqrt(total);
}
double euclidean_distance_sqr(const vector<double> &point_a, const vector<double> &point_b){
double total = 0;
for(int i=0; i<point_a.size(); i++){
const double temp = (point_a[i] - point_b[i]);
total += temp*temp;
}
return (total);
}
double gaussian_kernel(double distance, double kernel_bandwidth){
double temp = exp(-1.0/2.0 * (distance*distance) / (kernel_bandwidth*kernel_bandwidth));
return temp;
}
void MeanShift::set_kernel( double (*_kernel_func)(double,double) ) {
if(!_kernel_func){
kernel_func = gaussian_kernel;
} else {
kernel_func = _kernel_func;
}
}
void MeanShift::shift_point(const Point &point,
const std::vector<Point> &points,
double kernel_bandwidth,
Point &shifted_point) {
shifted_point.resize( point.size() ) ;
for(int dim = 0; dim<shifted_point.size(); dim++){
shifted_point[dim] = 0;
}
double total_weight = 0;
for(int i=0; i<points.size(); i++){
const Point& temp_point = points[i];
double distance = euclidean_distance(point, temp_point);
double weight = kernel_func(distance, kernel_bandwidth);
for(int j=0; j<shifted_point.size(); j++){
shifted_point[j] += temp_point[j] * weight;
}
total_weight += weight;
}
const double total_weight_inv = 1.0/total_weight;
for(int i=0; i<shifted_point.size(); i++){
shifted_point[i] *= total_weight_inv;
}
}
std::vector<MeanShift::Point> MeanShift::meanshift(const std::vector<Point> &points,
double kernel_bandwidth,
double EPSILON){
const double EPSILON_SQR = EPSILON*EPSILON;
vector<bool> stop_moving(points.size(), false);
vector<Point> shifted_points = points;
double max_shift_distance;
Point point_new;
do {
max_shift_distance = 0;
for(int i=0; i<points.size(); i++){
if (!stop_moving[i]) {
shift_point(shifted_points[i], points, kernel_bandwidth, point_new);
double shift_distance_sqr = euclidean_distance_sqr(point_new, shifted_points[i]);
if(shift_distance_sqr > max_shift_distance){
max_shift_distance = shift_distance_sqr;
}
if(shift_distance_sqr <= EPSILON_SQR) {
stop_moving[i] = true;
}
shifted_points[i] = point_new;
}
}
printf("max_shift_distance: %f\n", sqrt(max_shift_distance));
} while (max_shift_distance > EPSILON_SQR);
return shifted_points;
}
vector<Cluster> MeanShift::cluster(const std::vector<Point> &points,
const std::vector<Point> &shifted_points)
{
vector<Cluster> clusters;
for (int i = 0; i < shifted_points.size(); i++) {
int c = 0;
for (; c < clusters.size(); c++) {
if (euclidean_distance(shifted_points[i], clusters[c].mode) <= CLUSTER_EPSILON) {
break;
}
}
if (c == clusters.size()) {
Cluster clus;
clus.mode = shifted_points[i];
clusters.push_back(clus);
}
clusters[c].original_points.push_back(points[i]);
clusters[c].shifted_points.push_back(shifted_points[i]);
}
return clusters;
}
vector<Cluster> MeanShift::cluster(const std::vector<Point> &points, double kernel_bandwidth){
vector<Point> shifted_points = meanshift(points, kernel_bandwidth);
return cluster(points, shifted_points);
}