74 lines
2.2 KiB
Python
74 lines
2.2 KiB
Python
from ketrface.util import *
|
|
|
|
MIN_PTS = 5
|
|
MAX_DISTANCE = 0.25
|
|
|
|
Undefined = 0
|
|
Edge = -1
|
|
Noise = -2
|
|
|
|
# Union of two lists of dicts
|
|
def Union(A, B):
|
|
C = []
|
|
for key in A + B:
|
|
if key not in C:
|
|
C.append(key)
|
|
return C
|
|
|
|
# https://en.wikipedia.org/wiki/DBSCAN
|
|
def DBSCAN(points, eps = MAX_DISTANCE, minPts = MIN_PTS, verbose = True):
|
|
clusters = [] # Cluster list
|
|
perc = -1
|
|
total = len(points)
|
|
for i, P in enumerate(points):
|
|
if verbose == True:
|
|
new_perc = int(100 * (i+1) / total)
|
|
if new_perc != perc:
|
|
perc = new_perc
|
|
print(f'Clustering points {perc}% ({i}/{total} processed) complete with {len(clusters)} identities.')
|
|
|
|
if P['cluster'] != Undefined: # Previously processed in inner loop
|
|
continue
|
|
N = RangeQuery(points, P, eps) # Find neighbors
|
|
if len(N) < minPts: # Density check
|
|
P['cluster'] = Noise # Label as Noise
|
|
continue
|
|
|
|
C = { # Define new cluster
|
|
'id': len(clusters),
|
|
'faces': [ P ],
|
|
'cluster': Undefined
|
|
}
|
|
clusters.append(C)
|
|
|
|
P['cluster'] = C # Label initial point
|
|
S = N # Neighbors to expand (exclude P)
|
|
S.remove(P)
|
|
|
|
for Q in S: # Process every seed point
|
|
if Q['cluster'] == Noise: # Change Noise to border point
|
|
Q['cluster'] = C
|
|
C['faces'].append(Q)
|
|
if Q['cluster'] != Undefined: # Previously processed (border point)
|
|
continue
|
|
Q['cluster'] = C # Label neighbor
|
|
C['faces'].append(Q)
|
|
N = RangeQuery(points, Q, eps) # Find neighbors
|
|
if len(N) >= minPts: # Density check (if Q is a core point)
|
|
S = Union(S, N) # Add new neighbors to seed set
|
|
|
|
return clusters
|
|
|
|
def RangeQuery(points, Q, eps):
|
|
neighbors = []
|
|
for P in points: # Scan all points in the database
|
|
if P in neighbors:
|
|
continue
|
|
distance = findCosineDistance( # Compute distance and check epsilon
|
|
Q['descriptors'],
|
|
P['descriptors'])
|
|
if distance <= eps:
|
|
neighbors += [ P ] # Add to result
|
|
return neighbors
|
|
|