-
Notifications
You must be signed in to change notification settings - Fork 0
/
db_scan.py
162 lines (140 loc) · 5.57 KB
/
db_scan.py
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
'''
DBSCAN-clustering of 3D-points.
(c) 2019-2023, INSERM
written by Volker Baecker at Montpellier Ressources Imagerie, Biocampus Montpellier, INSERM, CNRS, University of Montpellier (www.mri.cnrs.fr)
The points must be in the X, Y, Z and NR columns
of the ImageJ system results-table. By default the columns
"X", "Y", "Z" and "NR" are used. However other column names
can be provided.
X, Y, Z: The column names of the columns containing the 3D coordinates of the points
NR: The column containing the indices or ids of the points. If the table does not have this column, it is created.
The DBSCAN-slustering is run with a maximum distance and a
minimum number of points for a cluster.
The script will create two tables as results. The table clusters and the table unclustered. The table clusters will contain
all points that belong to a cluster. The column 'C' in the clusters table specifies the cluster to which the point belongs.
The table unclustered contains all points that have not been associated with a cluster.
'''
from ij import IJ, WindowManager
from ij.measure import ResultsTable
from org.apache.commons.math3.ml.clustering import DoublePoint
from org.apache.commons.math3.ml.clustering import DBSCANClusterer
import jarray
def main():
XColumn = 'Centroid.X'
YColumn = 'Centroid.Y'
ZColumn = 'Centroid.Z'
NRColumn = 'Label'
minPts = 4
maxDist = 3
run(maxDist, minPts, XColumn, YColumn, ZColumn, NRColumn)
def run(maxDist, minPts, XColumn='X', YColumn='Y', ZColumn='Z', NRColumn='NR'):
'''
Run the DBSCAN-clustering.
Parameters:
maxDist: The maximum distance for the DBScan-clustering algorithm
minPts: The minimum number of points a cluster must have
XColumn: The name of column containing the x-coordinates
YColumn: The name of column containing the y-coordinates
ZColumn: The name of column containing the z-coordinates
NRColumn: The name of column containing the indices or ids of the points
'''
points = pointList3DFromRT(XColumn, YColumn, ZColumn)
clusterer = DBSCANClusterer(maxDist, minPts)
clusters = clusterer.cluster(points)
reportClustersAsTable(clusters, points, XColumn, YColumn, ZColumn, NRColumn)
def pointList3DFromRT(XColumn='X', YColumn='Y', ZColumn='Z'):
'''
Create a list of 3D-coordinates from the ImageJ system results table and return it.
'''
rt = ResultsTable.getActiveTable()
xIndex = getColumnIndex(XColumn)
yIndex = getColumnIndex(YColumn)
zIndex = getColumnIndex(ZColumn)
dplist = []
for i in range(0, rt.size()):
columns = rt.getRowAsString(i).split('\t')
x = float(columns[xIndex])
y = float(columns[yIndex])
z = float(columns[zIndex])
array = []
array.append(x)
array.append(y)
array.append(z)
jArray = jarray.array(array, 'd')
dp = DoublePoint(jArray)
dplist.append(dp)
return dplist
def reportClustersAsTable(clusters, allPoints, XColumn='X', YColumn='Y', ZColumn='Z', NRColumn='NR'):
'''
Report the clustered and unclustered points in the tables 'clusters' and 'unclustered'.
'''
rt_clustered = ResultsTable()
counter = 1;
clusterCounter = 1
clusteredPoints = []
for c in clusters:
for dp in c.getPoints():
rt_clustered.incrementCounter()
p = dp.getPoint()
rt_clustered.addValue(NRColumn, counter)
rt_clustered.addValue(XColumn, p[0])
rt_clustered.addValue(YColumn, p[1])
rt_clustered.addValue(ZColumn, p[2])
rt_clustered.addValue("C", clusterCounter)
counter = counter + 1;
clusteredPoints.append([p[0], p[1], p[2]])
clusterCounter = clusterCounter + 1
rt = ResultsTable.getActiveTable()
X, Y, Z = getColumns(XColumn, YColumn, ZColumn)
if not rt.columnExists(NRColumn):
for i in range(0, len(X)):
rt.setValue(NRColumn, i, i+1)
rt.updateResults()
NR = getColumn(NRColumn)
unclusteredPoints = [[point.getPoint()[0], point.getPoint()[1], point.getPoint()[2]] for point in allPoints if [point.getPoint()[0], point.getPoint()[1], point.getPoint()[2]] not in clusteredPoints]
counter = 1;
rt = ResultsTable()
for p in unclusteredPoints:
rt.incrementCounter()
rt.addValue(NRColumn, counter)
rt.addValue(XColumn, p[0])
rt.addValue(YColumn, p[1])
rt.addValue(ZColumn, p[2])
counter = counter + 1;
rt.show("unclustered")
rt_clustered.show("clusters")
WindowManager.getWindow("Results").close()
def getColumnIndex(column):
rt = ResultsTable.getActiveTable()
headings = rt.getHeadings()
for i, heading in enumerate(headings, start=0):
if heading==column:
return i
return None
def getColumn(aC):
rt = ResultsTable.getResultsTable()
anIndex = getColumnIndex(aC)
column = []
for i in range(0, rt.size()):
columns = rt.getRowAsString(i).split('\t')
v = float(columns[anIndex])
column.append(v)
return column
def getColumns(xC, yC, zC):
rt = ResultsTable.getResultsTable()
xIndex = getColumnIndex(xC)
yIndex = getColumnIndex(yC)
zIndex = getColumnIndex(zC)
columnX = []
columnY = []
columnZ = []
for i in range(0, rt.size()):
columns = rt.getRowAsString(i).split('\t')
x = float(columns[xIndex])
y = float(columns[yIndex])
z = float(columns[zIndex])
columnX.append(x)
columnY.append(y)
columnZ.append(z)
return columnX, columnY, columnZ
main()