#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
void normalization_points(float point[][3], int rows)
{
//聚类前对数据做最大最小值归一化 保证每个维度量纲一致
// points – 原始数据点云
// rows – 传入参数的行数
// 聚类 只关注[x, y, v]
//归一化最值范围
float x_min = -20; //单位 m
float x_max = 20;
float y_min = 0;
float y_max = 50;
float v_max = 20; //单位 m/s
for (int i=0; i<rows; i++)
{
point[i][0] = (point[i][0] - x_min) / (x_max - x_min);
point[i][1] = (point[i][1] - y_min) / (y_max - y_min);
point[i][2] = fabsf(point[i][2]/ v_max);
}
}
float cal_distance(float point[][3], int firstPoint, int secondPoint)
{
float temp = sqrt( pow((double)(point[firstPoint][0] - point[secondPoint][0]), 2) + pow((double)(point[firstPoint][1] - point[secondPoint][1]), 2) + pow((double)(point[firstPoint][2] - point[secondPoint][2]), 2));
return temp;
}
void dbscan_cluster(float point[][3], int point_num, int MinPts, float neighborhood)
{
//预分配内存
int clusterIndex = (int)malloc(sizeof(int) * point_num); //聚类蔟标签
int dataType = (int)malloc(sizeof(int) * point_num); //区分是否为核心点
int visited_data = (int)malloc(sizeof(int) * point_num); //访问标志,访问过的为1,未访问的为0
memset(clusterIndex, 0, sizeof(int) * point_num);
memset(dataType, 0, sizeof(int) * point_num);
memset(visited_data, 0, sizeof(int) * point_num);
/* 求核心点 */
for(int i = 0; i<point_num; i++)
{
int inter_point_num = 0;
for(int j = 0; j<point_num; j++)
{
float distance = cal_distance(point, i, j);
if(distance <= neighborhood)
{
inter_point_num++;
}
}
if(inter_point_num >=MinPts) //点数大于MinPts 为核心点
{
dataType[i] = 2; //核心点的标签为2
}
}
/* 由核心点依次找密度可达点 */
int cluster_num = 0;
for(int i=0; i<point_num; i++)
{
if((dataType[i]==2) && (!visited_data[i]))//若为核心点且还未分配类别,则由核心点查找密度可达点
{
visited_data[1] = 0;//
int *record_single_cluster = (int*)malloc(sizeof(int) * point_num); //存储可达点索引
int length = 0;
memset(record_single_cluster, 0, sizeof(int) * point_num);
//遍历查找密度可达点
for(int j=0; j<point_num; j++)
{
if(!visited_data[j])
{
float temp = cal_distance(point, i, j);
if(temp < neighborhood)
{
record_single_cluster[length] = j;//记录当前序号
length++;
}
}
}
//若length > minPts,存为一个类别
if(length > MinPts)
{
cluster_num++;//类别+1
for(int j=0; j<length; j++)
{
visited_data[record_single_cluster[j]] = 1;
clusterIndex[record_single_cluster[j]] = cluster_num;
}
}
free(record_single_cluster);
record_single_cluster = NULL;
}
}
for(int i=0; i<point_num; i++)
{
printf("%d\n", clusterIndex[i]);
}
/* 聚类完毕 */
/* cluster_num为类别总数,clusterIndex存储的为每个点的聚类类别,0为噪声 */
free(clusterIndex);
clusterIndex = NULL;
free(dataType);
dataType = NULL;
free(visited_data);
visited_data = NULL;
}
int main()
{
float point[13][3] = {
{1,1,1},{1.1,1.1,1.1},{1,1.2,1.1},{15,15.1,18.1},{15.2,15.5,17.9},{1.3,1.1,1},{1.01,1.02,1.03},{5,5,5},{10.1,9.1,11.1},{5.01,5.02,5.03},{5.02,5.05,5.01},{5.02,5.01,5.05},{10,9,11}};
int point_num = 13;
normalization_points(point, point_num);
int MinPts = 3;
float neighborhood = 0.1;
dbscan_cluster(point, point_num, MinPts, neighborhood);
return 0;
}