-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinit.cpp
More file actions
75 lines (66 loc) · 2.89 KB
/
init.cpp
File metadata and controls
75 lines (66 loc) · 2.89 KB
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
#include "kmeans.hpp"
#include "bitmap.hpp"
#include "init.hpp"
// Calculates distance from pixel to every chosen centroid, returns the minimum
long chooseClosestCentroid(Pixel &pixel, Centroid* centers, const short ¢ersChosen) {
long min = std::numeric_limits<long>::max();
for (short centerIndex = 0; centerIndex < centersChosen; centerIndex++)
if (long currDistance = computeDistance(pixel, centers[centerIndex]); currDistance < min) {
min = currDistance;
pixel.nearestCenter = ¢ers[centerIndex];
}
return min;
}
// Normalizes vector - divides all the distances by their sum. Alternatively, you could divide them all
// by their maximum distance
void normalizeVector(long double* distances, const long &numberOfPixels, const long double& sum) {
for (long index = 0; index < numberOfPixels; index++)
distances[index] /= sum;
}
// Sums up the distances from the distances vector
long double sumDistances(Pixel* pixels, const long &numberOfPixels, double long* dist, Centroid* centroids, short &chosenCentroids) {
long double returnSum = 0.l;
for (long px = 0l; px < numberOfPixels; px++) {
// Now the coordinates for the closest centroid are stored in pixels[px]
dist[px] = chooseClosestCentroid(pixels[px], centroids, chosenCentroids);
returnSum += dist[px];
}
return returnSum;
}
// Chooses centroids with the k-means++ initialization method
Centroid* chooseCentroids(Pixel* pixels, const long &numberOfPixels, const short &clusters) {
if (clusters < 2)
throw "Should be a minimum of 2 clusters for this to work";
// Choose random initial centroid
Centroid *centroids = new Centroid[clusters];
centroids[0] = pixels[genI()];
short chosenCentroids = 1;
for (short clusterno = 1; clusterno < clusters; clusterno++) {
// Distances from every pixel to its nearest centroid and sum the distances
long double *distances = new long double[numberOfPixels];
long double sum = sumDistances(pixels, numberOfPixels, distances, centroids, chosenCentroids);
if (sum == 0) {
std::cerr << "Wait a minute" << ", ";
sum += 0.0001;
}
normalizeVector(distances, numberOfPixels, sum);
// Choose a real number between [0, 1] and iterate all the distances from every data point to
// the closest cluster already chosen. Then, choose the first element in the list such that the sum
// of the values in the normalized vector (here, distances) up to that element is greaten than or equal
// to randNumber. That data point will be the next centroid
long double randNumber = genR();
long double normSum = 0.l;
for (long pxIndex = 0l; pxIndex < numberOfPixels; pxIndex++) {
normSum += distances[pxIndex];
if (normSum >= randNumber) {
centroids[clusterno] = pixels[pxIndex];
chosenCentroids++;
break;
}
} // End choosing centroid with probability D^2(x)
if (distances)
delete[] distances;
distances = nullptr;
} // End choosing the next centroid loop
return centroids;
}