├── .DS_Store
├── .Rhistory
├── .gitignore
├── CMakeLists.txt
├── CompilationRecipes.md
├── GraphAnalyzer.R
├── License.txt
├── MitoGraph.cxx
├── MitoThinning.cxx
├── MitoThinning.h
├── README.md
├── ThirdPartLicenses.txt
├── data
└── MitoGraphTest001.tif
├── doc
├── Readme.md
└── mitograph.png
├── includes.h
├── includes
└── dirent.h
├── ssThinning.cxx
├── ssThinning.h
└── tools
├── seg2para
├── CMakeLists.txt
└── seg2para.cpp
└── skell2img
├── CMakeLists.txt
├── includes.h
└── skell2img.cxx
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vianamp/MitoGraph/70819e5f517e968fd11870b3d99764f827a7a289/.DS_Store
--------------------------------------------------------------------------------
/.Rhistory:
--------------------------------------------------------------------------------
1 | fit2 <- lm(AvgDegree ~ MitoToCellSurRatio + Media, data=MitoTable)
2 | anova(fit1, fit2)
3 | cv.lm(df=mydata, fit1, m=3) # 3 fold cross-validation
4 | ??cv.lm
5 | library(DAAG)
6 | cv.lm(df=mydata, fit1, m=3) # 3 fold cross-validation
7 | cv.lm(df=MitoTable, fit1, m=3) # 3 fold cross-validation
8 | cv <- cv.lm(df=MitoTable, fit1, m=3) # 3 fold cross-validation
9 | cv.lm(df=MitoTable, fit1, m=3) # 3 fold cross-validation
10 | cv <- cv.lm(df=MitoTable, fit1, m=3) # 3 fold cross-validation
11 | cv
12 | cv$cvpred
13 | cv <- cv.lm(df=MitoTable, fit1, m=3) # 3 fold cross-validation
14 | ?cv.lm
15 | cv <- cv.lm(df=MitoTable, fit1, m=5) # 3 fold cross-validation
16 | fit <- lm(AvgDegree ~ MitoToCellSurRatio + Type + Media, data=MitoTable)
17 | library(bootstrap)
18 | install.packages("bootstrap")
19 | library(bootstrap)
20 | theta.fit <- function(x,y){lsfit(x,y)}
21 | theta.predict <- function(fit,x){cbind(1,x)%*%fit$coef}
22 | X <- as.matrix(mydata[c("x1","x2","x3")])
23 | X <- as.matrix(MitoTable[c("MitoToCellSurRatio","Type","Media")])
24 | y <- as.matrix(MitoTable[c("AvgDegree")])
25 | results <- crossval(X,y,theta.fit,theta.predict,ngroup=10)
26 | library(MASS)
27 | fit <- lm(AvgDegree ~ MitoToCellSurRatio + Type + Media, data=MitoTable)
28 | step <- stepAIC(fit, direction="both")
29 | step$anova # display results
30 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type MitoToCellSurRatio*Media + MitoLength, data=MitoTable)
31 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type MitoToCellSurRatio*Media + MitoLength, data=MitoTable)
32 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type MitoToCellSurRatio*Media, data=MitoTable)
33 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media + MitoLength, data=MitoTable)
34 | step <- stepAIC(fit, direction="both")
35 | step$anova # display results
36 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable)
37 | step <- stepAIC(fit, direction="both")
38 | step$anova # display results
39 | library(leaps)
40 | install.packages("leaps")
41 | library(leaps)
42 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=10)
43 | summary(leaps)
44 | plot(leaps,scale="r2")
45 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable)
46 | step <- stepAIC(fit, direction="both")
47 | step$anova # display results
48 | # All Subsets Regression
49 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=10)
50 | # view results
51 | summary(leaps)
52 | leaps$first
53 | leaps$xnames
54 | leaps$intercept
55 | leaps$np
56 | leaps$d
57 | leaps$rbar
58 | leaps$thetab
59 | leaps$ress
60 | leaps$ir
61 | leaps$lindep
62 | leaps$call
63 | ?leaps
64 | leaps[2]
65 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=1)
66 | leaps
67 | summary(leaps)
68 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=1)
69 | # view results
70 | summary(leaps)
71 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=10)
72 | # view results
73 | summary(leaps)
74 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=6)
75 | # view results
76 | summary(leaps)
77 | plot(leaps,scale="r2")
78 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=6)
79 | # view results
80 | summary(leaps)
81 | # plot a table of models showing variables in each model.
82 | # models are ordered by the selection statistic.
83 | plot(leaps,scale="r2")
84 | plot(leaps,scale="aic")
85 | plot(leaps,scale="bic")
86 | library(relaimpo)
87 | install.packages("relaimpo")
88 | library(relaimpo)
89 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable)
90 | calc.relimp(fit,type=c("lmg","last","first","pratt"),rela=TRUE)
91 | calc.relimp(fit,type=c("lmg"),rela=TRUE)
92 | impo <- calc.relimp(fit,type=c("lmg"),rela=TRUE)
93 | impo
94 | str(impo)
95 | impo@lmg
96 | boot <- boot.relimp(fit, b = 1000, type = c("lmg"), rank = TRUE, diff = TRUE, rela = TRUE)
97 | boot <- boot.relimp(fit, b = 50, type = c("lmg"), rank = TRUE, diff = TRUE, rela = TRUE)
98 | booteval.relimp(boot) # print result
99 | plot(booteval.relimp(boot,sort=TRUE)) # plot result
100 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=6)
101 | # view results
102 | summary(leaps)
103 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable)
104 | step <- stepAIC(fit, direction="both")
105 | step$anova # display results
106 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + Media, data=MitoTable)
107 | step <- stepAIC(fit, direction="both")
108 | step$anova # display results
109 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable)
110 | step <- stepAIC(fit, direction="both")
111 | step$anova # display results
112 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=6)
113 | # view results
114 | summary(leaps)
115 | plot(leaps,scale="r2")
116 | plot(leaps,scale="bic")
117 | plot(leaps,scale="r2")
118 | fit <- lm(AvgDegree ~ MitoToCellSurRatio * (Type + Media), data=MitoTable)
119 | step <- stepAIC(fit, direction="both")
120 | step$anova # display results
121 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + Media, data=MitoTable)
122 | boot <- boot.relimp(fit, b = 50, type = c("lmg"), rank = TRUE, diff = TRUE, rela = TRUE)
123 | booteval.relimp(boot) # print result
124 | plot(booteval.relimp(boot,sort=TRUE)) # plot result
125 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio * (Type + Media), data=MitoTable,nbest=6)
126 | summary(leaps)
127 | leaps$np
128 | leaps$nrbar
129 | leaps$first
130 | leaps$last
131 | leaps$vorder
132 | str(leaps)
133 | source('/Volumes/TOSH/UCI/MyData/NewScopeUnbudded/Analysis/GenTable.R', echo=TRUE)
134 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,col=interaction(Date,Media))) + geom_point()
135 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,col=interaction(Date,Media))) + geom_point() + geom_smooth(method="lm")
136 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,col=interaction(Type))) + geom_point() + geom_smooth(method="lm")
137 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,col=interaction(Type,Media))) + geom_point() + geom_smooth(method="lm")
138 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,col=interaction(Type,Media,Date))) + geom_point() + geom_smooth(method="lm")
139 | ggplot(MitoTable,aes(MitoToCellSurRatio,avgDegree,col=interaction(Type,Media,Date))) + geom_point() + geom_smooth(method="lm")
140 | M <- subset(MitoTable,interaction(Date,Type,Media)=="24.WT.Glucose")
141 | source('/Volumes/TOSH/UCI/MyData/NewScopeUnbudded/Analysis/GenTable.R', echo=TRUE)
142 | fit1 <- lm(M,CellVolume~MitoVolLen)
143 | fit1 <- lm(data=M,CellVolume~MitoVolLen)
144 | fit2 <- lm(data=M,MitoVolLen~CellVolume)
145 | plot(fit1)
146 | plot(fit2)
147 | fit1$coefficients
148 | fit1$coefficients[1]
149 | sumamry(fit1)
150 | summamy(fit1)
151 | summary(fit1)
152 | q<-summary(fit1)
153 | q
154 | fit1$coefficients[1]
155 | fit1$coefficients[2]
156 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept = fit1$coefficients[1], slope = fit1$coefficients[2])
157 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept = fit1$coefficients[1], slope = fit1$coefficients[2])
158 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_abline(intercept = fit1$coefficients[1], slope = fit1$coefficients[2])
159 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept = fit1$coefficients[1], slope = fit1$coefficients[2])
160 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept = 10)
161 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(aes(intercept = fit1$coefficients[1], slope = fit1$coefficients[2]))
162 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=10)
163 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=4)
164 | ggplot(M,aes(CellVolume,MitoVolLen,group=1)) + geom_point() + geom_abline(intercept=4)
165 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point(aes(group=1)) + geom_abline(intercept=4)
166 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point(aes(group=1)) + geom_abline(intercept=4)
167 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(intercept=4)
168 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(aes(intercept=4))
169 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(aes(slope=4))
170 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(aes(slope=0.4))
171 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(aes(slope=0.1))
172 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(aes(slope=fit1$coefficients[2]))
173 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(aes(slope=fit2$coefficients[2]))
174 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(slope=fit2$coefficients[2])
175 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(intercept=fit2$coefficients[1],slope=fit2$coefficients[2])
176 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=-c1[1]/c[2],slope=1/c2[2])
177 | fit1 <- lm(data=M,CellVolume~MitoVolLen)
178 | c1 <- fit1$coefficients
179 | fit2 <- lm(data=M,MitoVolLen~CellVolume)
180 | c2 <- fit2$coefficients
181 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=-c1[1]/c[2],slope=1/c2[2])
182 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=-c1[1]/c2[2],slope=1/c2[2])
183 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=c2[1],slope=c2[2])
184 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2])
185 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2]) + geom_abline(intercept=c2[1],slope=c2[2])
186 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() +
187 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2]) +
188 | geom_abline(intercept=c2[1],slope=c2[2]) +
189 | geom_abline(intercept=c2[1],slope=(c1[2]*c2[2]+1)/(2*c1[2]))
190 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() +
191 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2]) +
192 | geom_abline(intercept=c2[1],slope=c2[2]) +
193 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]))
194 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() +
195 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],type=2)
196 | ?geom_abline
197 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() +
198 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2)
199 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() +
200 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) +
201 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) +
202 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]))
203 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() +
204 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) +
205 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) +
206 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2)
207 | library(graphics)
208 | (pc.cr <- princomp(USArrests)) # inappropriate
209 | princomp(USArrests, cor = TRUE) # =^= prcomp(USArrests, scale=TRUE)
210 | summary(pc.cr <- princomp(USArrests, cor = TRUE))
211 | loadings(pc.cr) # note that blank entries are small but not zero
212 | plot(pc.cr) # shows a screeplot.
213 | biplot(pc.cr)
214 | princomp(~ ., data = USArrests, cor = TRUE)
215 | ## NA-handling
216 | USArrests[1, 2] <- NA
217 | pc.cr <- princomp(~ Murder + Assault + UrbanPop,
218 | data = USArrests, na.action = na.exclude, cor = TRUE)
219 | pc.cr$scores[1:5, ]
220 | ## (Simple) Robust PCA:
221 | ## Classical:
222 | (pc.cl <- princomp(stackloss))
223 | ## Robust:
224 | (pc.rob <- princomp(stackloss, covmat = MASS::cov.rob(stackloss)))
225 | df <- data.frame(iris) # iris dataset
226 | pca <- prcomp(df[,1:4], retx=T, scale.=T) # scaled pca [exclude species col]
227 | scores <- pca$x[,1:3] # scores for first three PC's
228 | # k-means clustering [assume 3 clusters]
229 | km <- kmeans(scores, centers=3, nstart=5)
230 | ggdata <- data.frame(scores, Cluster=km$cluster, Species=df$Species)
231 | # stat_ellipse is not part of the base ggplot package
232 | source("https://raw.github.com/low-decarie/FAAV/master/r/stat-ellipse.R")
233 | ggplot(ggdata) +
234 | geom_point(aes(x=PC1, y=PC2, color=factor(Cluster)), size=5, shape=20) +
235 | stat_ellipse(aes(x=PC1,y=PC2,fill=factor(Cluster)),
236 | geom="polygon", level=0.95, alpha=0.2) +
237 | guides(color=guide_legend("Cluster"),fill=guide_legend("Cluster"))
238 | source("https://raw.github.com/low-decarie/FAAV/master/r/stat-ellipse.R")
239 | set.seed(101)
240 | n <- 1000
241 | x <- rnorm(n, mean=2)
242 | y <- 1.5 + 0.4*x + rnorm(n)
243 | df <- data.frame(x=x, y=y, group="A")
244 | x <- rnorm(n, mean=2)
245 | y <- 1.5*x + 0.4 + rnorm(n)
246 | df <- rbind(df, data.frame(x=x, y=y, group="B"))
247 | #calculating ellipses
248 | library(ellipse)
249 | df_ell <- data.frame()
250 | install.packages("ellipse")
251 | library(ellipse)
252 | df_ell <- data.frame()
253 | for(g in levels(df$group)){
254 | df_ell <- rbind(df_ell, cbind(as.data.frame(with(df[df$group==g,], ellipse(cor(x, y),
255 | scale=c(sd(x),sd(y)),
256 | centre=c(mean(x),mean(y))))),group=g))
257 | }
258 | #drawing
259 | library(ggplot2)
260 | p <- ggplot(data=df, aes(x=x, y=y,colour=group)) + geom_point(size=1.5, alpha=.6) +
261 | geom_path(data=df_ell, aes(x=x, y=y,colour=group), size=1, linetype=2)
262 | p <- ggplot(data=df, aes(x=x, y=y,colour=group)) + geom_point(size=1.5, alpha=.6) +
263 | geom_path(data=df_ell, aes(x=x, y=y,colour=group), size=1, linetype=2)
264 | df_ell
265 | source_url("https://raw.github.com/JoFrhwld/FAAV/master/r/stat-ellipse.R")
266 | ??source_url
267 | install.packages("devtools")
268 | source_url("https://raw.github.com/JoFrhwld/FAAV/master/r/stat-ellipse.R")
269 | library(devtools)
270 | source_url("https://raw.github.com/JoFrhwld/FAAV/master/r/stat-ellipse.R")
271 | set.seed(20130226)
272 | n <- 200
273 | x1 <- rnorm(n, mean = 2)
274 | y1 <- 1.5 + 0.4 * x1 + rnorm(n)
275 | x2 <- rnorm(n, mean = -1)
276 | y2 <- 3.5 - 1.2 * x2 + rnorm(n)
277 | class <- rep(c("A", "B"), each = n)
278 | df <- data.frame(x = c(x1, x2), y = c(y1, y2), colour = class)
279 | # get code for "stat_ellipse"
280 | library(devtools)
281 | library(ggplot2)
282 | source_url("https://raw.github.com/JoFrhwld/FAAV/master/r/stat-ellipse.R")
283 | qplot(data = df, x = x, y = y, colour = class) + stat_ellipse()
284 | qplot(data = M, x = CellVolume, y = MitoVolLen) + stat_ellipse()
285 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() +
286 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) +
287 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) +
288 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) +
289 | stat_ellipse()
290 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() +
291 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) +
292 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) +
293 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) +
294 | stat_ellipse(alpha=0.4)
295 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() +
296 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) +
297 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) +
298 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) +
299 | stat_ellipse(geom = "polygon", alpha = 1/2)
300 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,fill=Media)) + geom_point() +
301 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) +
302 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) +
303 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) +
304 | stat_ellipse(geom = "polygon", alpha = 1/2)
305 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() +
306 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) +
307 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) +
308 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) +
309 | stat_ellipse(geom = "polygon", alpha = 1/2)
310 | M <- subset(MitoTable,interaction(Date)=="24")
311 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() +
312 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) +
313 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) +
314 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) +
315 | stat_ellipse(geom = "polygon", alpha = 1/2)
316 | fit1 <- lm(data=M,CellVolume~MitoVolLen*Media)
317 | c1 <- fit1$coefficients
318 | fit2 <- lm(data=M,MitoVolLen~CellVolume*Media)
319 | c2 <- fit2$coefficients
320 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() +
321 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) +
322 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) +
323 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) +
324 | stat_ellipse(geom = "polygon", alpha = 1/2)
325 | M <- subset(MitoTable,interaction(Date)=="24")
326 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() +
327 | stat_ellipse(geom = "polygon", alpha = 1/2)
328 | M <- subset(MitoTable,interaction(Date)=="00")
329 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() +
330 | stat_ellipse(geom = "polygon", alpha = 1/2)
331 | princomp(M,aes(CellVolume,MitoVolLen,col=Media))
332 | ?princomp
333 | princomp(~ ., data = USArrests, cor = TRUE)
334 | ## NA-handling
335 | USArrests[1, 2] <- NA
336 | pc.cr <- princomp(~ Murder + Assault + UrbanPop,
337 | data = USArrests, na.action=na.exclude, cor = TRUE)
338 | pc.cr$scores[1:5, ]
339 | ## (Simple) Robust PCA:
340 | ## Classical:
341 | (pc.cl <- princomp(stackloss))
342 | ## Robust:
343 | (pc.rob <- princomp(stackloss, covmat = MASS::cov.rob(stackloss)))
344 | ## The variances of the variables in the
345 | ## USArrests data vary by orders of magnitude, so scaling is appropriate
346 | (pc.cr <- princomp(USArrests)) # inappropriate
347 | princomp(USArrests, cor = TRUE) # =^= prcomp(USArrests, scale=TRUE)
348 | ## Similar, but different:
349 | ## The standard deviations differ by a factor of sqrt(49/50)
350 | summary(pc.cr <- princomp(USArrests, cor = TRUE))
351 | loadings(pc.cr) ## note that blank entries are small but not zero
352 | plot(pc.cr) # shows a screeplot.
353 | biplot(pc.cr)
354 | princomp(USArrests)
355 | princomp(MitoTable)
356 | M <- data.frame(M$CellVolume,M$MitoLength)
357 | princomp(M)
358 | p <- princomp(M)
359 | p$center
360 | p$scale
361 | p$loadings
362 | ld<-p$loadings
363 | ld
364 | summary(ld)
365 | ld
366 | ld@Comp.1
367 | list(ld)
368 | ld[1]
369 | ld[2]
370 | ld[3]
371 | ld[5]
372 | ld[4]
373 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() +
374 | stat_ellipse(geom = "polygon", alpha = 1/2) +
375 | geom_smooth(method="lm")
376 | M <- subset(MitoTable,interaction(Date)=="00")
377 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() +
378 | stat_ellipse(geom = "polygon", alpha = 1/2) +
379 | geom_smooth(method="lm")
380 | source('/Volumes/TOSH/UCI/MyData/NewScopeUnbudded/Analysis/GenTable.R', echo=TRUE)
381 | source_url("https://raw.github.com/JoFrhwld/FAAV/master/r/stat-ellipse.R")
382 | M <- subset(MitoTable,interaction(Date)=="24")
383 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() +
384 | stat_ellipse(geom = "polygon", alpha = 1/2) +
385 | geom_smooth(method="lm")
386 | M <- subset(MitoTable,interaction(Date)=="24")
387 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() +
388 | stat_ellipse(geom = "polygon", alpha = 1/2) +
389 | geom_smooth(method="lm")
390 | M <- subset(MitoTable,interaction(Date)=="72")
391 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() +
392 | stat_ellipse(geom = "polygon", alpha = 1/2) +
393 | geom_smooth(method="lm")
394 | M <- subset(MitoTable,interaction(Date)!="72")
395 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() +
396 | stat_ellipse(geom = "polygon", alpha = 1/2) +
397 | geom_smooth(method="lm")
398 | M <- subset(MitoTable,interaction(Date)=="00")
399 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() +
400 | stat_ellipse(geom = "polygon", alpha = 1/2) +
401 | geom_smooth(method="lm")
402 | M <- subset(MitoTable,interaction(Date)=="24")
403 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() +
404 | stat_ellipse(geom = "polygon", alpha = 1/2) +
405 | geom_smooth(method="lm")
406 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point()
407 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() +
408 | stat_ellipse(geom = "polygon", alpha = 1/2) +
409 | geom_smooth(method="lm") +
410 | facet_grid(Media~Type)
411 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() +
412 | stat_ellipse(geom = "polygon", alpha = 1/2) +
413 | #geom_smooth(method="lm") +
414 | facet_grid(Media~Type)
415 | ggplot(M,aes(avgDegree,MitoToCellSurRatio,col=interaction(Media,Type))) + geom_point() +
416 | stat_ellipse(geom = "polygon", alpha = 1/2) +
417 | #geom_smooth(method="lm") +
418 | facet_grid(Media~Type)
419 | M <- subset(MitoTable,interaction(Date)=="00")
420 | ggplot(M,aes(avgDegree,MitoToCellSurRatio,col=interaction(Media,Type))) + geom_point() +
421 | stat_ellipse(geom = "polygon", alpha = 1/2) +
422 | #geom_smooth(method="lm") +
423 | facet_grid(Media~Type)
424 | M <- subset(MitoTable,Date=="00"|Date=="24")
425 | M <- subset(MitoTable,Date=="00"|Date=="24")
426 | ggplot(M,aes(avgDegree,MitoToCellSurRatio,col=interaction(Media,Type,Date))) + geom_point() +
427 | stat_ellipse(geom = "polygon", alpha = 1/2) +
428 | #geom_smooth(method="lm") +
429 | facet_grid(Media~Type)
430 | ggplot(M,aes(MitoToCellSurRatio,avgDegree,col=interaction(Media,Type,Date))) + geom_point() +
431 | stat_ellipse(geom = "polygon", alpha = 1/2) +
432 | #geom_smooth(method="lm") +
433 | facet_grid(Media~Type)
434 | source('/Volumes/TOSH/UCI/MyData/NewScopeUnbudded/Analysis/GenTable.R', echo=TRUE)
435 | rm(list=ls())
436 | library(igraph)
437 | library(ggplot2)
438 | library(devtools)
439 | source_url("https://raw.github.com/JoFrhwld/FAAV/master/r/stat-ellipse.R")
440 | source('~/.active-rstudio-document', echo=TRUE)
441 | setwd("~/GitHub/MitoGraph/")
442 | M <- read.table("RFP-020914_1_40_024.width.width")
443 | M <- read.table("RFP-020914_1_40_024.width")
444 | source('~/.active-rstudio-document', echo=TRUE)
445 | source('~/.active-rstudio-document', echo=TRUE)
446 | source('~/.active-rstudio-document', echo=TRUE)
447 | source('~/.active-rstudio-document', echo=TRUE)
448 | source('~/.active-rstudio-document', echo=TRUE)
449 | source('~/.active-rstudio-document', echo=TRUE)
450 | source('~/.active-rstudio-document', echo=TRUE)
451 | source('~/.active-rstudio-document', echo=TRUE)
452 | source('~/.active-rstudio-document', echo=TRUE)
453 | source('~/.active-rstudio-document', echo=TRUE)
454 | source('~/.active-rstudio-document', echo=TRUE)
455 | setwd("~/GitHub/MitoGraph/")
456 | M <- read.table("temp2.width",col.names=c("width","intensity"))
457 | setwd("~/GitHub/MitoGraph/")
458 | M <- read.table("temp2.width",col.names=c("id","length",width","intensity"))
459 | M <- read.table("temp2.width",col.names=c("id","length","width","intensity"))
460 | library(ggplot2)
461 | ggplot(M,aes(intensity,width)) + geom_point() + geom_smooth(method="loess")
462 | dim(M)
463 | setwd("~/GitHub/MitoGraph/")
464 | M <- read.table("temp1.width",col.names=c("id","length","width","intensity"))
465 | library(ggplot2)
466 | ggplot(M,aes(intensity,width)) + geom_point() + geom_smooth(method="loess")
467 | ggplot(M,aes(intensity,width,col=as.factor(id))) + geom_point() + geom_smooth(method="loess")
468 | M <- read.table("temp2.width",col.names=c("id","length","width","intensity"))
469 | ggplot(M,aes(intensity,width,col=as.factor(id))) + geom_point() + geom_smooth(method="loess")
470 | ggplot(M,aes(intensity,width,col=length)) + geom_point() + geom_smooth(method="loess")
471 | M
472 | plot(M$width~M$intensity)
473 | M <- read.table("temp2.width",col.names=c("id","length","width","intensity"))
474 | ggplot(M,aes(intensity,width,col=length)) + geom_point() + geom_smooth(method="loess")
475 | mean(M$length)
476 | ggplot(M,aes(intensity,width,col=length)) + geom_point() + geom_smooth(method="lm")
477 | source('~/.active-rstudio-document', echo=TRUE)
478 | mean(M$length)
479 | source('~/.active-rstudio-document', echo=TRUE)
480 | source('~/.active-rstudio-document', echo=TRUE)
481 | source('~/.active-rstudio-document', echo=TRUE)
482 | source('~/.active-rstudio-document', echo=TRUE)
483 | source('~/.active-rstudio-document', echo=TRUE)
484 | source('~/.active-rstudio-document', echo=TRUE)
485 | source('~/.active-rstudio-document', echo=TRUE)
486 | M11 <- read.table("temp2.width",col.names=c("id","length","width","intensity"))
487 | M12 <- subset(M11,length > mean(M12$length))
488 | M21 <- read.table("temp2.width",col.names=c("id","length","width","intensity"))
489 | M22 <- subset(M21,length > mean(M21$length))
490 | source('~/.active-rstudio-document', echo=TRUE)
491 | source('~/.active-rstudio-document', echo=TRUE)
492 | source('~/.active-rstudio-document', echo=TRUE)
493 | source('~/.active-rstudio-document', echo=TRUE)
494 | f11 <- ggplot(M11,aes(intensity,width,col=length)) + geom_point() + geom_smooth(method="lm") +
495 | scale_x_continuous(limits = c(2500,7500), expand = c(0, 0)) +
496 | scale_y_continuous(limits = c(0.00,0.40), expand = c(0, 0))
497 | grid.arrange(f11,f12,f21,f22,ncol=2,clip=TRUE)
498 | source('~/.active-rstudio-document', echo=TRUE)
499 | f <- lm(M22$width~M22$intensity)
500 | summary(f)
501 | f11 <- summary(f11)
502 | f12 <- summary(f12)
503 | f21 <- summary(f21)
504 | f22 <- summary(f22)
505 | f11 <- summary(f11)
506 | f11
507 | f11 <- lm(M11$width~M11$intensity)
508 | f11
509 | f11 <- summary(f11)
510 | f11
511 | f11$r.squared
512 | f11$adj.r.squared
513 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /build/
2 | data/.DS_Store
3 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
3 |
4 | PROJECT(MitoGraph)
5 |
6 | FIND_PACKAGE(VTK)
7 | INCLUDE(${VTK_USE_FILE})
8 | INCLUDE_DIRECTORIES(${VTK_INCLUDE_DIRS})
9 |
10 | ADD_EXECUTABLE(MitoGraph MitoGraph MitoThinning ssThinning)
11 |
12 | if(VTK_LIBRARIES)
13 | TARGET_LINK_LIBRARIES(MitoGraph ${VTK_LIBRARIES})
14 | else()
15 | TARGET_LINK_LIBRARIES(MitoGraph vtkHybrid vtkWidgets)
16 | endif()
17 |
18 |
--------------------------------------------------------------------------------
/CompilationRecipes.md:
--------------------------------------------------------------------------------
1 | ## Recipe for MacOS 12.5.1 Chipset M2
2 |
3 | ```
4 | mkdir mitograph
5 | cd mitograph
6 | wget https://www.vtk.org/files/release/8.2/VTK-8.2.0.tar.gz
7 | tar -xvf VTK-8.2.0.tar.gz && cd VTK-8.2.0
8 | mkdir build && cd build
9 | brew install cmake
10 | brew install libpng
11 | export CFLAGS="-DPNG_ARM_NEON_OPT=0"
12 | export CXXFLAGS="-DPNG_ARM_NEON_OPT=0"
13 | cmake -DPNG_PNG_INCLUDE_DIR=/opt/homebrew/include -DPNG_LIBRARY_RELEASE=/opt/homebrew/lib/libpng.dylib ..
14 | make
15 | sudo make install
16 | cd ../..
17 | git clone https://github.com/vianamp/MitoGraph.git && cd MitoGraph
18 | mkdir build && cd build
19 | cmake ..
20 | make
21 | ```
22 |
23 | ## Recipe for Windows 10
24 |
25 | 1. Install CMake
26 | 2. Install Visual Studio 17 2022
27 | 3. Download VTK 8.2.0 Source Code
28 | 4. Open CMake (cmake-gui).
29 | 5. Set the source directory to the VTK source directory.
30 | 6. Set the build directory to where you want to build the binaries (e.g., C:/vtk-build).
31 | 7. Click Configure and select your Visual Studio version
32 | 8. Click Generate and then Open Project.
33 | 9. In Visual Studio, build the project (ALL_BUILD).
34 |
35 |
--------------------------------------------------------------------------------
/GraphAnalyzer.R:
--------------------------------------------------------------------------------
1 | #
2 | # External arguments
3 | #
4 |
5 | options(warn=-1)
6 | suppressMessages(library(igraph))
7 |
8 | # args = '/Users/mviana/Desktop/MitoGraph/data/MitoGraphTest001'
9 | args = commandArgs(trailingOnly=TRUE)
10 |
11 | FileName <- args[1]
12 |
13 | #
14 | # Loading graph
15 | #
16 |
17 | G <- read.table(paste(FileName,'.gnet',sep=''), skip=1, col.names=c('Source','Target','Length'))
18 | G <- graph.data.frame(as.data.frame(G), directed=F)
19 |
20 | #
21 | # Loading volume information
22 | #
23 |
24 | Vol <- data.frame(read.table(paste(FileName,'.cc',sep=''), skip=1))
25 | names(Vol) <- c('node','cc','vol_cc')
26 |
27 | ids <- as.numeric(V(G)$name)
28 | V(G)$cc_vol <- Vol$vol_cc[match(ids,Vol$node)]
29 |
30 | #
31 | # Connected component analysis
32 | #
33 |
34 | List <- decompose(G)
35 |
36 | Table <- NULL
37 | for (g in List) {
38 | Table <- rbind(Table,data.frame(vcount(g), ecount(g), sum(E(g)$Length), max(V(g)$cc_vol)))
39 | }
40 |
41 | names(Table) <- c('nodes','edges','length_(um)','vol_from_img_(um3)')
42 |
43 | Table <- Table[order(Table[,4], decreasing=T),]
44 |
45 | #
46 | # Loading global measurements
47 | #
48 |
49 | Global <- data.frame(read.table(paste(FileName,'.mitograph',sep=''), skip=1))
50 |
51 | names(Global) <- c('vol_from_voxels_(um)', 'avg_width_(um)', 'std_width_(um)', 'total_length_(um)', 'vol_from_length_(um3)')
52 |
53 | Global$nodes <- vcount(G)
54 |
55 | Global$edges <- ecount(G)
56 |
57 | Global$components <- length(List)
58 |
59 | output_file <- paste(FileName,'.mitograph',sep='')
60 |
61 | cat('::MitoGraph\n',file=output_file, append=F)
62 | cat(paste(Sys.time(),'\n'),file=output_file, append=T)
63 | cat('\n',file=output_file, append=T)
64 | cat('GLOBAL STATISTICS:\n',file=output_file, append=T)
65 | cat('\n',file=output_file, append=T)
66 | write.table(Global,output_file,
67 | append=T,
68 | row.names=F,
69 | col.names=T,
70 | sep="\t",
71 | quote=F)
72 | cat('\n',file=output_file, append=T)
73 | cat('COMPONENTS STATISTICS:\n',file=output_file, append=T)
74 | cat('\n',file=output_file, append=T)
75 | write.table(Table,output_file,
76 | append=T,
77 | row.names=F,
78 | col.names=T,
79 | sep="\t",
80 | quote=F)
81 |
82 |
--------------------------------------------------------------------------------
/License.txt:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
--------------------------------------------------------------------------------
/MitoThinning.cxx:
--------------------------------------------------------------------------------
1 | // =====================================================================================================
2 | // MitoThinning: This routine receives as input an ImageData binary from MitoGraph main routine a and
3 | // apply a thinning process over it, resulting in a new but topologically equivalent image.
4 | //
5 | // Matheus P. Viana - vianamp@gmail.com - 2014.06.10
6 | // Susanne Rafelski Lab, University of California Irvine
7 | // =====================================================================================================
8 |
9 | #include "MitoThinning.h"
10 |
11 | int ssdx[26] = {-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1};
12 | int ssdy[26] = {-1,-1,-1,-1,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1};
13 | int ssdz[26] = { 1, 1, 1, 0, 0, 0,-1,-1,-1, 1, 1, 1, 0, 0,-1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1};
14 |
15 | // Routine used to save .gnet and .coo files representing
16 | // the skeleton of the mitochondrial network.
17 | void ExportGraphFiles(vtkSmartPointer PolyData, long int nnodes, const char Prefix[]);
18 |
19 | // Routine to create the file _nodes.vtk. This file contains
20 | // little speres located at the junctions (nodes) coordinates
21 | // and might have the nodes label depending on if the variable
22 | // export_node_labels is true or false.
23 | void ExportNodes(vtkSmartPointer PolyData, long int nnodes, long int *ValidId, _mitoObject *mitoObject);
24 |
25 | // Routine used to check whether a voxel is locates at the border
26 | // of the binary image or not. A border voxel is defined as those
27 | // that have at least one of their 6-neighbors equal to zero.
28 | bool IsBorder(vtkIdType id, vtkSmartPointer Image);
29 |
30 | // Routine used to smooth the parametric curves that describe the
31 | // skeleton edges. A simple average filter is used to do the job.
32 | // Sigma represents the number of times the filter is applied.
33 | void SmoothEdgesCoordinates(vtkSmartPointer PolyData, double sigma);
34 |
35 | // Estimate the mitochondrial volume by counting the number of
36 | // pixels in the binary image used as input for thinning.
37 | void GetVolumeFromVoxels(vtkSmartPointer Image, std::vector *Atts);
38 |
39 | // Estimate the mitochondrial volume by using the skeleton
40 | // total length and assuming constant radius.
41 | //void GetVolumeFromSkeletonLength(vtkSmartPointer PolyData, double *attributes);
42 |
43 | // Calculate the length of a given edge.
44 | //double GetEdgeLength(vtkIdType edge, vtkSmartPointer PolyData);
45 |
46 | // Returns the number of voxels around the voxel (x,y,z) with
47 | // value given different of "value".
48 | char GetNumberOfNeighborsWithoutValue(vtkSmartPointer Image, int x, int y, int z, long int value);
49 |
50 | // Returns the number of voxels around the voxel (x,y,z) with
51 | // value different of "value" in the vector "Volume".
52 | char GetNumberOfNeighborsWithoutValue(vtkSmartPointer Image, vtkSmartPointer Volume, int x, int y, int z, long int value);
53 |
54 | // Returns the number of voxels around the voxel (x,y,z) with
55 | // value given by "value".
56 | char GetNumberOfNeighborsWithValue(vtkSmartPointer Image, int x, int y, int z, long int value);
57 |
58 | // Returns the number of voxels around the voxel (x,y,z) with
59 | // value "value" in the vector "Volume".
60 | char GetNumberOfNeighborsWithValue(vtkSmartPointer Image, vtkSmartPointer Volume, int x, int y, int z, long int value);
61 |
62 | // Returns one neighbor of (x,y,z) with value "value" in the
63 | // vector "Volume".
64 | vtkIdType GetOneNeighborWithValue(int x, int y, int z, vtkSmartPointer Image, vtkSmartPointer Volume, long int value);
65 |
66 | // Returns one neighbor of (x,y,z) with value different of
67 | // "value" in the vector "Volume".
68 | vtkIdType GetOneNeighborWithoutValue(int x, int y, int z, vtkSmartPointer Image, vtkSmartPointer Volume, long int value);
69 |
70 | // Returns one neighbor of (x,y,z) with value different of
71 | // "value".
72 | vtkIdType GetOneNeighborWithoutValue(int x, int y, int z, vtkSmartPointer Image, long int value);
73 |
74 | // Merge together junctions that touch each other.
75 | bool JunctionsMerge(std::list Junctions, vtkSmartPointer Image, vtkSmartPointer Volume);
76 |
77 | // Track an edge starting at voxel (x,y,z) in the volume "Volume".
78 | std::list GetEdgeStartingAt(int x, int y, int z, vtkSmartPointer Image, vtkSmartPointer Volume);
79 |
80 | // Returns an adjacency edge "edge_label".
81 | long int GetOneAdjacentEdge(vtkSmartPointer PolyData, long int edge_label, long int junction_label, bool *found_on_left);
82 |
83 | // Track all the nodes and edges of a 3D structured thinned by
84 | // the routine Thinning3D.
85 | vtkSmartPointer Skeletonization(vtkSmartPointer Image, _mitoObject *mitoObject);
86 |
87 | // Replace two edges A and B attached to a node of degree 2
88 | // with one edge C that corresponds to A + B. The degree of the
89 | // node is set to -1 and A and B are moreved from PolyData.
90 | bool MergeEdgesOfDegree2Nodes(vtkSmartPointer PolyData, long int nedges_before_filtering, int *K);
91 |
92 | // After merging edges attached to nodes of degree 2, the original
93 | // edges must be deleted throught this routine.
94 | void RemoveCellsWithInvalidNodes(vtkSmartPointer PolyData, int *K);
95 |
96 | /* ================================================================
97 | I/O ROUTINES
98 | =================================================================*/
99 |
100 | void SaveImageData(vtkSmartPointer Image, const char FileName[], bool _resample) {
101 | #ifdef DEBUG
102 | printf("Saving ImageData File...\n");
103 | #endif
104 |
105 | vtkSmartPointer Flip = vtkSmartPointer::New();
106 | Flip -> SetInputData(Image);
107 | Flip -> SetFilteredAxis(1);
108 | Flip -> PreserveImageExtentOn();
109 | Flip -> Update();
110 |
111 | vtkSmartPointer writer = vtkSmartPointer::New();
112 | writer -> SetFileName(FileName);
113 |
114 | // TIF writer does not support data of type double
115 | if (Image -> GetScalarType() == VTK_DOUBLE) {
116 |
117 | double range[2];
118 | Image -> GetScalarRange( range );
119 | vtkSmartPointer ShiftFilter = vtkSmartPointer::New();
120 | ShiftFilter -> SetInputData(Flip->GetOutput());
121 | ShiftFilter -> SetScale( 65535./(range[1]-range[0]));
122 | ShiftFilter -> SetShift( -range[0] );
123 | ShiftFilter -> SetOutputScalarTypeToUnsignedShort();
124 | ShiftFilter -> Update();
125 |
126 | writer -> SetInputData(ShiftFilter->GetOutput());
127 |
128 | } else {
129 |
130 | if (_resample) {
131 | #ifdef DEBUG
132 | printf("\tResampling data...%f\t%f\n",_dxy,_dz);
133 | #endif
134 | vtkSmartPointer Resample = vtkSmartPointer::New();
135 | Resample -> SetInterpolationModeToLinear();
136 | Resample -> SetDimensionality(3);
137 | Resample -> SetInputData(Flip->GetOutput());
138 | Resample -> SetAxisMagnificationFactor(0,1.0);
139 | Resample -> SetAxisMagnificationFactor(1,1.0);
140 | Resample -> SetAxisMagnificationFactor(2,_dz/_dxy);
141 | Resample -> Update();
142 |
143 | vtkSmartPointer ImageResampled = Resample -> GetOutput();
144 | ImageResampled -> SetSpacing(1,1,1);
145 |
146 | writer -> SetInputData(ImageResampled);
147 | } else {
148 |
149 | writer -> SetInputData(Flip->GetOutput());
150 |
151 | }
152 |
153 | }
154 |
155 | writer -> Write();
156 |
157 | #ifdef DEBUG
158 | printf("\tFile Saved!\n");
159 | #endif
160 | }
161 |
162 | void SavePolyData(vtkSmartPointer PolyData, const char FileName[]) {
163 |
164 | #ifdef DEBUG
165 | printf("Saving PolyData...\n");
166 | #endif
167 |
168 | #ifdef DEBUG
169 | printf("\t#Points in PolyData file: %llu.\n",(vtkIdType)PolyData->GetNumberOfPoints());
170 | #endif
171 |
172 | vtkSmartPointer Writer = vtkSmartPointer::New();
173 | #ifndef DEBUG
174 | Writer -> SetFileType(VTK_BINARY);
175 | #endif
176 | Writer -> SetFileName(FileName);
177 | Writer -> SetInputData(PolyData);
178 | Writer -> Write();
179 |
180 | #ifdef DEBUG
181 | printf("\tFile Saved!\n");
182 | #endif
183 | }
184 |
185 | void ExportGraphFiles(vtkSmartPointer PolyData, long int nnodes, long int *ValidId, const char Prefix[]) {
186 |
187 | #ifdef DEBUG
188 | printf("Saving .coo file...\n");
189 | #endif
190 |
191 | char _fullpath[256];
192 |
193 | vtkPoints *Points = PolyData -> GetPoints();
194 |
195 | double r[3];
196 | long int node, exact_nnodes = 0;
197 | for (node = 0; node < nnodes; node++) {
198 | if (ValidId[node]>=0) exact_nnodes++;
199 | }
200 |
201 | sprintf(_fullpath,"%s.coo",Prefix);
202 | FILE *fcoo = fopen(_fullpath,"w");
203 | for (node = 0; node < nnodes; node++) {
204 | if (ValidId[node]>=0) {
205 | Points -> GetPoint(node,r);
206 | fprintf(fcoo,"%1.4f\t%1.4f\t%1.4f\n",_dxy*r[0],_dxy*r[1],_dz*r[2]);
207 | }
208 | }
209 | fclose(fcoo);
210 |
211 | double length;
212 | vtkIdType edge, npoints, i, j;
213 | sprintf(_fullpath,"%s.gnet",Prefix);
214 | FILE *fgnet = fopen(_fullpath,"w");
215 | fprintf(fgnet,"%ld\n",exact_nnodes);
216 | for (edge = 0; edge < PolyData -> GetNumberOfCells(); edge++) {
217 | npoints = PolyData -> GetCell(edge) -> GetNumberOfPoints();
218 | i = PolyData -> GetCell(edge) -> GetPointId(0);
219 | j = PolyData -> GetCell(edge) -> GetPointId(npoints-1);
220 | if ( ValidId[i] >= 0 && ValidId[j] >= 0 ) {
221 | length = GetEdgeLength(edge,PolyData);
222 | fprintf(fgnet,"%ld\t%ld\t%1.5f\n",ValidId[i],ValidId[j],length);
223 | }
224 | }
225 | fclose(fgnet);
226 |
227 | }
228 |
229 | void ExportNodes(vtkSmartPointer PolyData, long int nnodes, long int *ValidId, _mitoObject *mitoObject) {
230 |
231 | #ifdef DEBUG
232 | if (_export_nodes_label) {
233 | printf("Exporting nodes and their labels...\n");
234 | } else {
235 | printf("Exporting nodes...\n");
236 | }
237 | #endif
238 |
239 | vtkPoints *Points = PolyData -> GetPoints();
240 | vtkSmartPointer Append = vtkSmartPointer::New();
241 | Append -> SetOutputPointsPrecision(vtkAlgorithm::DEFAULT_PRECISION);
242 |
243 | double r[3];
244 | long int node;
245 | char node_txt[16];
246 | for (node = 0; node < nnodes; node++) {
247 | if ( ValidId[node] >= 0 ) {
248 | Points -> GetPoint(node,r);
249 |
250 | #ifdef DEBUG
251 | printf("Node = %d\n",(int)node);
252 | #endif
253 |
254 | vtkSmartPointer Node = vtkSmartPointer::New();
255 | if (_scale_polydata_before_save) {
256 | Node -> SetRadius(2*_dxy);
257 | Node -> SetCenter(_dxy*(r[0]+mitoObject->Ox),_dxy*(r[1]+mitoObject->Oy),_dz*(r[2]+mitoObject->Oz));
258 | } else {
259 | Node -> SetRadius(2.0);
260 | Node -> SetCenter(r[0]+mitoObject->Ox,r[1]+mitoObject->Oy,r[2]+mitoObject->Oz);
261 | }
262 |
263 | Node -> SetThetaResolution(6);
264 | Node -> SetPhiResolution(6);
265 | Node -> Update();
266 | Append -> AddInputData(Node->GetOutput());
267 | Append -> Update();
268 |
269 | if (_export_nodes_label) {
270 | sprintf(node_txt,"%ld",ValidId[node]);
271 | vtkSmartPointer PolyText = vtkSmartPointer::New();
272 | PolyText -> SetText(node_txt);
273 | PolyText -> Update();
274 |
275 | vtkSmartPointer T = vtkSmartPointer::New();
276 | if (_scale_polydata_before_save) {
277 | T -> Translate(_dxy*(r[0]+1+mitoObject->Ox),_dxy*(r[1]+1+mitoObject->Oy),_dz*(r[2]+mitoObject->Oz));
278 | T -> Scale(2*_dxy,2*_dxy,1);
279 | } else {
280 | T -> Translate(r[0]+2+mitoObject->Ox,r[1]+mitoObject->Oy,r[2]+mitoObject->Oz);
281 | T -> Scale(2,2,1);
282 | }
283 |
284 | vtkSmartPointer Trans = vtkSmartPointer::New();
285 | Trans -> SetInputData(PolyText->GetOutput());
286 | Trans -> SetTransform(T);
287 | Trans -> Update();
288 |
289 | Append -> AddInputData(Trans -> GetOutput());
290 | Append -> Update();
291 | }
292 | }
293 |
294 | }
295 |
296 | SavePolyData(Append->GetOutput(),(mitoObject->FileName+"_nodes.vtk").c_str());
297 | }
298 |
299 |
300 | /* ================================================================
301 | IMAGE TRANSFORMATION
302 | =================================================================*/
303 |
304 | void CleanImageBoundaries(vtkSmartPointer ImageData) {
305 | #ifdef DEBUG
306 | printf("Cleaning the image boundaries...\n");
307 | #endif
308 | int p, q;
309 | int *Dim = ImageData -> GetDimensions();
310 | for ( p = Dim[0]; p--; ) {
311 | for ( q = Dim[1]; q--; ) {
312 | ImageData -> SetScalarComponentFromDouble(p,q,0,0,0);
313 | ImageData -> SetScalarComponentFromDouble(p,q,Dim[2]-1,0,0);
314 | }
315 | }
316 | for ( p = Dim[0]; p--; ) {
317 | for ( q = Dim[2]; q--; ) {
318 | ImageData -> SetScalarComponentFromDouble(p,0,q,0,0);
319 | ImageData -> SetScalarComponentFromDouble(p,Dim[1]-1,q,0,0);
320 | }
321 | }
322 | for ( p = Dim[1]; p--; ) {
323 | for ( q = Dim[2]; q--; ) {
324 | ImageData -> SetScalarComponentFromDouble(0,p,q,0,0);
325 | ImageData -> SetScalarComponentFromDouble(Dim[0]-1,p,q,0,0);
326 | }
327 | }
328 | }
329 |
330 | /* ================================================================
331 | AUXILIAR ROUTINES
332 | =================================================================*/
333 |
334 |
335 | bool IsBorder(vtkIdType id, vtkSmartPointer Image) {
336 | double r[3];
337 | int x, y, z;
338 | Image -> GetPoint(id,r);
339 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2];
340 | if(!Image->GetScalarComponentAsDouble(x,y,z,0)) return false;
341 | if(!Image->GetScalarComponentAsDouble(x+1,y,z,0)) return true;
342 | if(!Image->GetScalarComponentAsDouble(x-1,y,z,0)) return true;
343 | if(!Image->GetScalarComponentAsDouble(x,y+1,z,0)) return true;
344 | if(!Image->GetScalarComponentAsDouble(x,y-1,z,0)) return true;
345 | if(!Image->GetScalarComponentAsDouble(x,y,z+1,0)) return true;
346 | if(!Image->GetScalarComponentAsDouble(x,y,z-1,0)) return true;
347 | return false;
348 | }
349 |
350 | void SmoothEdgesCoordinates(vtkSmartPointer PolyData, double sigma){
351 |
352 | double r1[3], r2[3], r3[3];
353 | long int id, line, nlines, n, s;
354 | vtkPoints *Points = PolyData -> GetPoints();
355 |
356 | vtkCell *Line;
357 | nlines = PolyData -> GetNumberOfCells();
358 |
359 | for (line = 0; line < nlines; line++){
360 | Line = PolyData -> GetCell(line);
361 | n = Line -> GetNumberOfPoints();
362 | double *X = new double[n];
363 | double *Y = new double[n];
364 | double *Z = new double[n];
365 | for (s = 0; s < int(sigma); s++) {
366 | for (id = 1; id < n-1; id++ ) {
367 | Points -> GetPoint(Line->GetPointId(id-1),r1);
368 | Points -> GetPoint(Line->GetPointId(id+0),r2);
369 | Points -> GetPoint(Line->GetPointId(id+1),r3);
370 | X[id] = 0.125*(r1[0]+6*r2[0]+r3[0]);
371 | Y[id] = 0.125*(r1[1]+6*r2[1]+r3[1]);
372 | Z[id] = (1.0/3.0)*(r1[2]+r2[2]+r3[2]);
373 | }
374 | for (id = 1; id < n-1; id++ ) {
375 | Points -> SetPoint(Line->GetPointId(id),X[id],Y[id],Z[id]);
376 | }
377 | }
378 | delete[] X; delete[] Y; delete[] Z;
379 | }
380 | PolyData -> Modified();
381 | }
382 |
383 | void GetVolumeFromVoxels(vtkSmartPointer Image, std::vector *Atts) {
384 | double v;
385 | unsigned long int nv = 0;
386 | for (vtkIdType id=Image->GetNumberOfPoints();id--;) {
387 | v = Image -> GetPointData() -> GetScalars() -> GetTuple1(id);
388 | if (v) nv++;
389 | }
390 | attribute newAtt = {"Volume from voxels",nv * (_dxy * _dxy * _dz)};
391 | Atts -> push_back(newAtt);
392 | }
393 | /*
394 | void GetVolumeFromSkeletonLength(vtkSmartPointer PolyData, double *attributes) {
395 | double r1[3], r2[3], length = 0.0;
396 | vtkPoints *Points = PolyData -> GetPoints();
397 | for (vtkIdType edge=PolyData->GetNumberOfCells();edge--;) {
398 | length += GetEdgeLength(edge,PolyData);
399 | }
400 | attributes[1] = length;
401 | attributes[2] = length * (acos(-1.0)*pow(_rad,2));
402 | }
403 | */
404 | double GetEdgeLength(vtkIdType edge, vtkSmartPointer PolyData) {
405 | double r1[3], r2[3];
406 | double length = 0.0;
407 | for (vtkIdType n = 1; n < PolyData->GetCell(edge)->GetNumberOfPoints(); n++) {
408 | PolyData -> GetPoint(PolyData->GetCell(edge)->GetPointId(n-1),r1);
409 | PolyData -> GetPoint(PolyData->GetCell(edge)->GetPointId(n ),r2);
410 | length += sqrt(pow(_dxy*(r2[0]-r1[0]),2)+pow(_dxy*(r2[1]-r1[1]),2)+pow(_dz*(r2[2]-r1[2]),2));
411 | }
412 | return length;
413 | }
414 |
415 | /* ================================================================
416 | THINNING 3D
417 | =================================================================*/
418 |
419 | vtkSmartPointer Thinning3D(vtkSmartPointer ImageData, _mitoObject *mitoObject) {
420 |
421 | #ifdef DEBUG
422 | SaveImageData(ImageData,(mitoObject->FileName+"_binary.tif").c_str());
423 | #endif
424 |
425 | vtkIdType N = ImageData -> GetNumberOfPoints();
426 | GetVolumeFromVoxels(ImageData,&mitoObject->attributes);
427 |
428 | int x, y, z;
429 | double r[3], v, vl;
430 | vtkIdType ndels, id;
431 | ssThinVox *STV = new ssThinVox();
432 |
433 | CleanImageBoundaries(ImageData);
434 |
435 | int i, j, ***Vol = new int**[3];
436 | for (i = 0; i < 3; i++) {
437 | Vol[i] = new int*[3];
438 | for (j = 0; j < 3; j++) {
439 | Vol[i][j] = new int[3];
440 | }
441 | }
442 |
443 | #ifdef DEBUG
444 | printf("Starting thinning process...\n");
445 | #endif
446 |
447 | std::list ToBeDeleted;
448 | std::list OnTheSurface;
449 | std::list::iterator itId;
450 |
451 | do {
452 | ndels = 0;
453 | for (id = N; id--;) {
454 | if (IsBorder(id, ImageData)) {
455 | OnTheSurface.insert(OnTheSurface.begin(),id);
456 | }
457 | }
458 |
459 | for (int direction = 6; direction--;) {
460 | for ( itId=OnTheSurface.begin(); itId!=OnTheSurface.end(); itId++) {
461 | id = *itId;
462 | ImageData -> GetPoint(id,r);
463 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2];
464 | v = ImageData -> GetScalarComponentAsDouble(x,y,z,0);
465 | if (v) {
466 | for (i = 26; i--;) {
467 | vl = ImageData -> GetScalarComponentAsDouble(x+ssdx[i],y+ssdy[i],z+ssdz[i],0);
468 | Vol[1+ssdx[i]][1+ssdy[i]][1+ssdz[i]] = (vl) ? 1 : 0;
469 | }
470 | if ( STV -> match(direction,Vol) ) ToBeDeleted.insert(ToBeDeleted.begin(),id);
471 | }
472 | }
473 | itId = ToBeDeleted.begin();
474 | while (itId != ToBeDeleted.end()) {
475 | ndels++;
476 | ImageData -> GetPoint(*itId,r);
477 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2];
478 | ImageData -> SetScalarComponentFromDouble(x,y,z,0,0);
479 | ToBeDeleted.erase(itId++);
480 | }
481 | }
482 |
483 | #ifdef DEBUG
484 | printf("\t#Surface = %llu / #Deletions = %llu\n",(long long int)OnTheSurface.size(),ndels);
485 | #endif
486 |
487 | OnTheSurface.clear();
488 |
489 | } while(ndels);
490 |
491 | delete STV;
492 |
493 | #ifdef DEBUG
494 | printf("Thinning done!\n");
495 | #endif
496 |
497 | OnTheSurface.clear();
498 | ToBeDeleted.clear();
499 |
500 | return Skeletonization(ImageData,mitoObject);
501 |
502 | }
503 |
504 | /* ================================================================
505 | SKELETONIZATION
506 | =================================================================*/
507 |
508 | char GetNumberOfNeighborsWithoutValue(vtkSmartPointer Image, int x, int y, int z, long int value) {
509 | double r[3];
510 | char nn = 0;
511 | for (char k = 26; k--;) {
512 | if (Image->GetScalarComponentAsDouble(x+ssdx[k],y+ssdy[k],z+ssdz[k],0) != value) nn++;
513 | }
514 | return nn;
515 | }
516 |
517 | char GetNumberOfNeighborsWithoutValue(vtkSmartPointer Image, vtkSmartPointer Volume, int x, int y, int z, long int value) {
518 | double r[3];
519 | char nn = 0;
520 | vtkIdType idk;
521 | for (char k = 26; k--;) {
522 | idk = Image->FindPoint(x+ssdx[k],y+ssdy[k],z+ssdz[k]);
523 | if (Volume->GetTuple1(idk) != value) nn++;
524 | }
525 | return nn;
526 | }
527 |
528 | char GetNumberOfNeighborsWithValue(vtkSmartPointer Image, int x, int y, int z, long int value) {
529 | double r[3];
530 | char nn = 0;
531 | for (char k = 26; k--;) {
532 | if (Image->GetScalarComponentAsDouble(x+ssdx[k],y+ssdy[k],z+ssdz[k],0) == value) nn++;
533 | }
534 | return nn;
535 | }
536 |
537 | char GetNumberOfNeighborsWithValue(vtkSmartPointer Image, vtkSmartPointer Volume, int x, int y, int z, long int value) {
538 | double r[3];
539 | char nn = 0;
540 | vtkIdType idk;
541 | for (char k = 26; k--;) {
542 | idk = Image -> FindPoint(x+ssdx[k],y+ssdy[k],z+ssdz[k]);
543 | if (Volume->GetTuple1(idk) == value) nn++;
544 | }
545 | return nn;
546 | }
547 |
548 | vtkIdType GetOneNeighborWithValue(int x, int y, int z, vtkSmartPointer Image, vtkSmartPointer Volume, long int value) {
549 | vtkIdType idk;
550 | for (char k = 26; k--;) {
551 | idk = Image -> FindPoint(x+ssdx[k],y+ssdy[k],z+ssdz[k]);
552 | if (Volume -> GetTuple1(idk) == value) {
553 | return idk;
554 | }
555 | }
556 | return 0; // We can do it because, by construction the voxel at id 0 should always be empty
557 | }
558 |
559 | vtkIdType GetOneNeighborWithoutValue(int x, int y, int z, vtkSmartPointer Image, vtkSmartPointer Volume, long int value) {
560 | vtkIdType idk;
561 | for (char k = 26; k--;) {
562 | idk = Image -> FindPoint(x+ssdx[k],y+ssdy[k],z+ssdz[k]);
563 | if (Volume -> GetTuple1(idk) && Volume -> GetTuple1(idk) != value) {
564 | return idk;
565 | }
566 | }
567 | return 0; // We can do it because, by construction the voxel at id 0 should always be empty
568 | }
569 |
570 | vtkIdType GetOneNeighborWithoutValue(int x, int y, int z, vtkSmartPointer Image, long int value) {
571 | vtkIdType idk;
572 | for (char k = 26; k--;) {
573 | idk = Image -> FindPoint(x+ssdx[k],y+ssdy[k],z+ssdz[k]);
574 | if (Image->GetScalarComponentAsDouble(x+ssdx[k],y+ssdy[k],z+ssdz[k],0)!=value) return idk;
575 | }
576 | return 0; // We can do it because, by construction the voxel at id 0 should always be empty
577 | }
578 |
579 | bool JunctionsMerge(std::list Junctions, vtkSmartPointer Image, vtkSmartPointer Volume) {
580 | char nk;
581 | double r[3];
582 | vtkIdType id;
583 | int x, y, z, k;
584 | bool _has_changed = false;
585 | std::list::iterator itId;
586 | long int junction_label, neigh_junction_label;
587 | for (itId=Junctions.begin(); itId!=Junctions.end(); itId++) {
588 | Image -> GetPoint(*itId,r);
589 | junction_label = Volume -> GetTuple1(*itId);
590 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2];
591 | for (k = 0; k < 26; k++) {
592 | id = Image->FindPoint(x+ssdx[k],y+ssdy[k],z+ssdz[k]);
593 | neigh_junction_label = Volume -> GetTuple1(id);
594 | if (junction_label < neigh_junction_label) {
595 | _has_changed = true;
596 | Volume -> SetTuple1(id,junction_label);
597 | }
598 | }
599 | }
600 | Volume -> Modified();
601 | return _has_changed;
602 | }
603 |
604 | std::list GetEdgeStartingAt(int x, int y, int z, vtkSmartPointer Image, vtkSmartPointer Volume) {
605 | double r[3];
606 | vtkIdType idk;
607 | std::list Edge;
608 | do {
609 | idk = GetOneNeighborWithValue(x,y,z,Image,Volume,-1);
610 | if (idk) {
611 | Volume -> SetTuple1(idk,0);
612 | Edge.insert(Edge.end(),idk);
613 | Image -> GetPoint(idk,r);
614 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2];
615 | }
616 | } while(idk);
617 | return Edge;
618 | }
619 |
620 | long int GetOneAdjacentEdge(vtkSmartPointer PolyData, long int edge_label, long int original_source, bool *_common_source) {
621 | vtkCell *Edge;
622 | long int source, target;
623 | for (long int edge = PolyData->GetNumberOfCells();edge--;) {
624 | if (edge != edge_label) {
625 | Edge = PolyData -> GetCell((vtkIdType)edge);
626 | source = Edge -> GetPointId(0);
627 | target = Edge -> GetPointId(Edge->GetNumberOfPoints()-1);
628 | if (original_source==source) {
629 | *_common_source = true;
630 | return edge;
631 | }
632 | if (original_source==target) {
633 | *_common_source = false;
634 | return edge;
635 | }
636 | }
637 | }
638 | return -1;
639 | }
640 |
641 | vtkSmartPointer Skeletonization(vtkSmartPointer Image, _mitoObject *mitoObject) {
642 |
643 | #ifdef DEBUG
644 | SaveImageData(Image,(mitoObject->FileName+"_thinned.tif").c_str());
645 | #endif
646 |
647 | double r[3];
648 | int x, y, z;
649 | vtkIdType id;
650 | long int junction_label = 1;
651 | vtkIdType N = Image -> GetNumberOfPoints();
652 | std::list Junctions;
653 | std::list::iterator itId;
654 |
655 | // Inside this IF statement, isolated voxels and isolated pairs of voxels
656 | // are expanded. If this is not done, these voxels will not be detected.
657 | // This requires O(N).
658 | if (_improve_skeleton_quality) {
659 |
660 | #ifdef DEBUG
661 | printf("Improving skeletonization [step 1: isolated single and pair of voxels]\n");
662 | #endif
663 |
664 | char nn;
665 | double rn[3];
666 | vtkIdType idn;
667 | int xn, yn, zn;
668 | for (id = N; id--;) {
669 | Image -> GetPoint(id,r);
670 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2];
671 | if (Image->GetScalarComponentAsDouble(x,y,z,0)) {
672 | nn = GetNumberOfNeighborsWithoutValue(Image,x,y,z,0);
673 | if (nn==0) {
674 | // Expanding isolated voxel
675 | Image -> SetScalarComponentFromDouble(x+1,y,z,0,255);
676 | Image -> SetScalarComponentFromDouble(x-1,y,z,0,255);
677 | } else if (nn==1) {
678 | idn = GetOneNeighborWithoutValue(x,y,z,Image,0);
679 | Image -> GetPoint(idn,rn);
680 | xn = (int)rn[0]; yn = (int)rn[1]; zn = (int)rn[2];
681 | if (GetNumberOfNeighborsWithoutValue(Image,xn,yn,zn,0)==1) {
682 | // Expanding isolated pair of voxels
683 | Image -> SetScalarComponentFromDouble(x-(int)(rn[0]-r[0]),y-(int)(rn[1]-r[1]),z-(int)(rn[2]-r[2]),0,255);
684 | Image -> SetScalarComponentFromDouble(xn+(int)(rn[0]-r[0]),yn+(int)(rn[1]-r[1]),zn+(int)(rn[2]-r[2]),0,255);
685 | }
686 | }
687 | }
688 | }
689 | }
690 |
691 | vtkSmartPointer Volume = vtkSmartPointer::New();
692 | Volume -> SetNumberOfComponents(1);
693 | Volume -> SetNumberOfTuples(N);
694 |
695 | // Inside this IF statement, we label all connected components
696 | // and we search for those cc that don't have junctions. If any
697 | // is found, we force it to have a junction by adding its first
698 | // voxel to the list Junctions. This fixes the problem of not
699 | // detecting loop-shaped ccs.
700 | if (_improve_skeleton_quality) {
701 | #ifdef DEBUG
702 | printf("Improving skeletonization [step 2: verifying connected components]\n");
703 | #endif
704 | long int n_fixed = 0;
705 | std::vector CSz;
706 | long int cc, ncc = LabelConnectedComponents(Image,Volume,CSz,26,0);
707 |
708 | bool *HasJunction = new bool[ncc];
709 | for (cc = ncc; cc--;) HasJunction[cc] = 0;
710 | for (id = N; id--;) {
711 | Image -> GetPoint(id,r);
712 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2];
713 | cc = (long int)Volume -> GetTuple1(id);
714 | if (cc) {
715 | if (GetNumberOfNeighborsWithValue(Image,Volume,x,y,z,cc) != 2) {
716 | HasJunction[(unsigned long int)(-cc-1)] = true;
717 | }
718 | }
719 | Image -> SetScalarComponentFromDouble(x,y,z,0,-cc);
720 | }
721 | for (id = N; id--;) {
722 | Image -> GetPoint(id,r);
723 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2];
724 | cc = (long int)Volume -> GetTuple1(id);
725 | if (cc) {
726 | if (!HasJunction[(unsigned long int)(-cc-1)]) {
727 | HasJunction[(unsigned long int)(-cc-1)] = true;
728 | Junctions.insert(Junctions.begin(),id);
729 | Volume -> SetTuple1(id,junction_label);
730 | junction_label++;
731 | n_fixed++;
732 | } else {
733 | Volume -> SetTuple1(id,-1);
734 | }
735 | } else {
736 | Volume -> SetTuple1(id,0);
737 | }
738 | }
739 | delete[] HasJunction;
740 |
741 | #ifdef DEBUG
742 | printf("\t#Components fixed = %ld\n",n_fixed);
743 | #endif
744 |
745 | Image -> GetPointData() -> GetScalars() -> Modified();
746 |
747 | } else {
748 |
749 | for (id = N; id--;) {
750 | if (Image -> GetPointData() -> GetScalars() -> GetTuple1(id)) {
751 | Volume -> SetTuple1(id,-1);
752 | } else {
753 | Volume -> SetTuple1(id,0);
754 | }
755 | }
756 | Volume -> Modified();
757 |
758 | }
759 |
760 | #ifdef DEBUG
761 | printf("Starting skeletonization...\n");
762 | printf("\tSearching for junctions...\n");
763 | #endif
764 |
765 | for (id = N; id--;) {
766 | Image -> GetPoint(id,r);
767 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2];
768 | if (Image->GetScalarComponentAsDouble(x,y,z,0)) {
769 | if (GetNumberOfNeighborsWithoutValue(Image,x,y,z,0) != 2) {
770 | Junctions.insert(Junctions.begin(),id);
771 | Volume -> SetTuple1(id,junction_label);
772 | junction_label++;
773 | }
774 | }
775 | }
776 | Volume -> Modified();
777 |
778 | if (!Junctions.size()) {
779 | printf("Z-stack seems to be empty. Aborting...\n");
780 | return 0;
781 | }
782 |
783 | #ifdef DEBUG
784 | printf("\t#Junctions before merging = %ld\n",Junctions.size());
785 | #endif
786 |
787 | // MERGING: During the merging process, voxels belonging to
788 | // the same junction are merged together forming nodes.
789 | while (JunctionsMerge(Junctions,Image,Volume));
790 |
791 | // Listing all nodes label we have until this point
792 | std::list Labels;
793 | std::list::iterator itLabel;
794 | for (itId=Junctions.begin(); itId!=Junctions.end(); itId++) {
795 | Labels.insert(Labels.begin(),(long int)Volume->GetTuple1(*itId));
796 | }
797 |
798 | // UNIQUE of labels
799 | Labels.sort(); // must sort first
800 | Labels.unique();
801 | long int NumberOfNodes = Labels.size();
802 |
803 | #ifdef DEBUG
804 | printf("\t#Junctions (nodes) after merging = %ld\n",NumberOfNodes);
805 | #endif
806 |
807 | // COORDINATES of nodes
808 | // Vectors with static size to make the average calculation easy.
809 | long int node;
810 | double *X = new double[NumberOfNodes]; //Vector for x-coordinate
811 | double *Y = new double[NumberOfNodes]; //Vector for y-coordinate
812 | double *Z = new double[NumberOfNodes]; //Vector for z-coordinate
813 | double *S = new double[NumberOfNodes]; //Vector for junctions size
814 | int *K = new int[NumberOfNodes]; //Vector for junctions degree
815 | for (node = 0; node < NumberOfNodes; node++) {
816 | K[node] = 0;
817 | X[node] = Y[node] = Z[node] = S[node] = 0.0;
818 | }
819 |
820 | for (itId=Junctions.begin(); itId!=Junctions.end(); itId++) {
821 | junction_label = (long int)Volume -> GetTuple1(*itId);
822 | itLabel = std::find(Labels.begin(),Labels.end(),junction_label);
823 | node = (long int)std::distance(Labels.begin(),itLabel);
824 | Volume -> SetTuple1(*itId,node+1);
825 | Image -> GetPoint(*itId,r);
826 | X[node] += r[0];
827 | Y[node] += r[1];
828 | Z[node] += r[2];
829 | S[node] ++;
830 | }
831 | Volume -> Modified();
832 |
833 | // Dynamic list to make easy the insertion of the coordinates
834 | // of remaining voxels detected during the edge tracking process.
835 | std::list PointsListX;
836 | std::list PointsListY;
837 | std::list PointsListZ;
838 | for (node=0;node EdgeArray = vtkSmartPointer::New();
848 |
849 | bool _should_add;
850 | itId = Junctions.begin();
851 | long int voxel_label = NumberOfNodes;
852 | long int junction_label_left, junction_label_right;
853 | long int source_node, target_node;
854 | while (itId != Junctions.end()) {
855 | Image -> GetPoint(*itId,r);
856 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2];
857 | if (GetNumberOfNeighborsWithValue(Image,Volume,x,y,z,-1)) {
858 | _should_add = true;
859 |
860 | //Tracking new edge
861 | std::list Edge = GetEdgeStartingAt(x,y,z,Image,Volume);
862 |
863 | //Identifying junctions on left side of the edge
864 | source_node = Volume -> GetTuple1(*itId);
865 |
866 | //Identifying junctions on right side of the edge
867 | Image -> GetPoint(Edge.back(),r);
868 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2];
869 | target_node = Volume -> GetTuple1(GetOneNeighborWithoutValue(x,y,z,Image,Volume,source_node));
870 |
871 | // When target_node is equal to 0 at this point, we are
872 | // dealing with loops. These loops can be real loops or noise
873 | // loops of very small length. This very short loops are often
874 | // related to noise around junctions or 1-voxel holes in the
875 | // data.
876 | // @@PARAMETER: Minimum loop length (in voxels)
877 | if (!target_node) {
878 | target_node = source_node;
879 | if (Edge.size() < 3) _should_add = false;
880 | }
881 |
882 | if (_should_add) {
883 | // Creating new cell for this edge
884 | EdgeArray -> InsertNextCell(Edge.size()+2);
885 | // Adding node 1
886 | EdgeArray -> InsertCellPoint(source_node-1);
887 | // Addint the new points coordinates as well as the edge itself
888 | for (std::list::iterator itIde=Edge.begin(); itIde!=Edge.end(); itIde++) {
889 | Image -> GetPoint(*itIde,r);
890 | PointsListX.insert(PointsListX.end(),r[0]);
891 | PointsListY.insert(PointsListY.end(),r[1]);
892 | PointsListZ.insert(PointsListZ.end(),r[2]);
893 | EdgeArray -> InsertCellPoint(voxel_label);
894 | voxel_label++;
895 | }
896 | // Adding node 2
897 | EdgeArray -> InsertCellPoint(target_node-1);
898 | // Updating nodes degree
899 | K[source_node-1]++;
900 | K[target_node-1]++;
901 | }
902 |
903 | } else {
904 | Junctions.erase(itId++);
905 | }
906 | }
907 |
908 | vtkSmartPointer Points = vtkSmartPointer::New();
909 | Points -> SetNumberOfPoints(PointsListX.size());
910 |
911 | #ifdef DEBUG
912 | printf("#Points in vtkPoints = %lld\n",Points -> GetNumberOfPoints());
913 | #endif
914 |
915 | voxel_label = 0;
916 | std::list::iterator itX = PointsListX.begin();
917 | std::list::iterator itY = PointsListY.begin();
918 | std::list::iterator itZ = PointsListZ.begin();
919 | while (itX != PointsListX.end()) {
920 | Points -> SetPoint(voxel_label,*itX,*itY,*itZ);
921 | itX++; itY++; itZ++;
922 | voxel_label++;
923 | }
924 | Points -> Modified();
925 |
926 | PointsListX.clear();
927 | PointsListY.clear();
928 | PointsListZ.clear();
929 |
930 | // Creating raw polyData
931 | vtkSmartPointer PolyData = vtkPolyData::New();
932 | PolyData -> SetPoints(Points);
933 | PolyData -> SetLines(EdgeArray);
934 | PolyData -> Modified();
935 | PolyData -> BuildLinks();
936 |
937 | long int nedges_before_filtering = PolyData -> GetNumberOfCells();
938 |
939 | #ifdef DEBUG
940 | printf("\t#Edges before filtering = %ld\n",nedges_before_filtering);
941 | SavePolyData(PolyData,(mitoObject->FileName+"_skeleton_raw.vtk").c_str());
942 | #endif
943 |
944 | // PolyData filtering by removing degree-2 nodes. These nodes rise
945 | // for two reasons: 1) very short edges that are not detected,
946 | // although the bifurcation is detected. 2) Short loops that were
947 | // removed.
948 |
949 | #ifdef DEBUG
950 | printf("\t#Filtering...\n");
951 | #endif
952 |
953 | while (
954 | MergeEdgesOfDegree2Nodes(PolyData,nedges_before_filtering,K)
955 | );
956 |
957 | #ifdef DEBUG
958 | printf("\t#Creating new ids...\n");
959 | #endif
960 |
961 | //Creating a list with final Ids of nodes after degree-2 nodes
962 | //deletetion.
963 | long int valid_id = 0;
964 | long int *ValidId = new long int[NumberOfNodes];
965 | for (node = 0; node < NumberOfNodes; node++) {
966 | if (K[node] > 0) {
967 | //printf("%d] - k = %d\n",(int)node,(int)K[node]);
968 | ValidId[node] = valid_id;
969 | valid_id++;
970 | } else {
971 | ValidId[node] = -1;
972 | }
973 | }
974 |
975 | // for (node = 0; node < NumberOfNodes; node++) {
976 | // printf("%d\t%d\n",(int)node,(int)ValidId[node]);
977 | // }
978 |
979 | //Creating an array called nodes used to mark true nodes
980 |
981 | vtkSmartPointer TrueNode = vtkSmartPointer::New();
982 | TrueNode -> SetNumberOfComponents(1);
983 | TrueNode -> SetNumberOfTuples(PolyData->GetNumberOfPoints());
984 | TrueNode -> FillComponent(0,-1);
985 | TrueNode -> SetName("Nodes");
986 |
987 | valid_id = 0;
988 | for (node = 0; node < NumberOfNodes; node++) {
989 | if (ValidId[node]>-1) {
990 | TrueNode -> SetTuple1(node,valid_id);
991 | valid_id++;
992 | }
993 | }
994 |
995 | TrueNode -> Modified();
996 |
997 | PolyData -> GetPointData() -> AddArray(TrueNode);
998 |
999 | // Export graph files
1000 |
1001 | #ifdef DEBUG
1002 | printf("\t#Edges after filtering = %lld\n",PolyData->GetNumberOfCells());
1003 | printf("Skeletonization done!\n");
1004 | #endif
1005 |
1006 | SmoothEdgesCoordinates(PolyData,3);
1007 |
1008 | if (_export_graph_files) ExportGraphFiles(PolyData,NumberOfNodes,ValidId,mitoObject->FileName.c_str());
1009 |
1010 | ExportNodes(PolyData,NumberOfNodes,ValidId,mitoObject);
1011 |
1012 | return PolyData;
1013 | }
1014 |
1015 | bool MergeEdgesOfDegree2Nodes(vtkSmartPointer PolyData, long int nedges_before_filtering, int *K) {
1016 |
1017 | // Given this edge: (source) o---->----o (target), it's necessary
1018 | // to check whether either source or target are nodes of degree 2.
1019 |
1020 | std::list Merg;
1021 | std::list::iterator itId;
1022 |
1023 | vtkCell *Edge, *NeighEdge;
1024 | long int i, source, target, edge, edge_length, neigh_edge, neigh_edge_length;
1025 | bool _common_source, _merged = false;
1026 |
1027 | for (edge = 0; edge < PolyData -> GetNumberOfCells(); edge++) {
1028 |
1029 | Edge = PolyData -> GetCell(edge);
1030 | edge_length = Edge -> GetNumberOfPoints();
1031 | source = (long int)Edge -> GetPointId(0);
1032 | target = (long int)Edge -> GetPointId(Edge->GetNumberOfPoints()-1);
1033 |
1034 | if (K[source]==2 && source!=target) {
1035 |
1036 | // [ neigh | original ]
1037 | // o----?----o---->-----o
1038 | // s t
1039 |
1040 | _merged = true;
1041 | neigh_edge = GetOneAdjacentEdge(PolyData,edge,source,&_common_source);
1042 | NeighEdge = PolyData -> GetCell((vtkIdType)neigh_edge);
1043 | neigh_edge_length = NeighEdge -> GetNumberOfPoints();
1044 |
1045 | if (_common_source) {// o----<----o---->----o
1046 | for (i=0;iGetCell(edge)->GetPointId(i));
1048 | for (i=1;iGetCell(neigh_edge)->GetPointId(i));
1050 | } else { // o---->----o---->----o
1051 | for (i=0;iGetCell(neigh_edge)->GetPointId(i));
1053 | for (i=1;iGetCell(edge)->GetPointId(i));
1055 | }
1056 | K[source] = -1; // Tagged as not valid node
1057 |
1058 | } else if (K[target]==2 && source!=target) {
1059 |
1060 | // [ original | neigh ]
1061 | // o---->-----o----?----o
1062 | // s t
1063 |
1064 | _merged = true;
1065 | neigh_edge = GetOneAdjacentEdge(PolyData,edge,target,&_common_source);
1066 | NeighEdge = PolyData -> GetCell((vtkIdType)neigh_edge);
1067 | neigh_edge_length = NeighEdge -> GetNumberOfPoints();
1068 |
1069 | if (_common_source) {// o---->----o---->----o
1070 | for (i=0;iGetCell(edge)->GetPointId(i));
1072 | for (i=1;iGetCell(neigh_edge)->GetPointId(i));
1074 | } else {// o---->----o----<----o
1075 | for (i=0;iGetCell(edge)->GetPointId(i));
1077 | for (i=neigh_edge_length-1;i--;)
1078 | Merg.insert(Merg.end(),PolyData->GetCell(neigh_edge)->GetPointId(i));
1079 | }
1080 | K[target] = -1; // Tagged as not valid node
1081 | }
1082 |
1083 | if (_merged) {
1084 | i = 0;
1085 | // Removing the two pieces that were merged together
1086 | PolyData -> BuildLinks();
1087 | PolyData -> DeleteCell(edge);
1088 | PolyData -> DeleteCell(neigh_edge);
1089 | PolyData -> RemoveDeletedCells();
1090 | // Adding the new "merged" edge
1091 | std::vector IdList(Merg.size());
1092 | for (itId=Merg.begin(); itId!=Merg.end(); itId++) {
1093 | IdList[i] = *itId;
1094 | i++;
1095 | }
1096 | PolyData -> InsertNextCell(VTK_POLY_LINE,Merg.size(),IdList.data());
1097 | Merg.clear();
1098 | return true;
1099 | }
1100 |
1101 | }
1102 | return false;
1103 | }
1104 |
1105 | long int LabelConnectedComponents(vtkSmartPointer ImageData, vtkSmartPointer Volume, std::vector &CSz, int ngbh, double threshold) {
1106 |
1107 | #ifdef DEBUG
1108 | printf("\tCalculating connected components...\n");
1109 | #endif
1110 |
1111 | int *Dim = ImageData -> GetDimensions();
1112 |
1113 | vtkIdType i, s, ido, id;
1114 |
1115 | int x, y, z;
1116 | double v, r[3];
1117 | bool find = true;
1118 | long long int ro[3];
1119 | long int scluster, label;
1120 | ro[0] = Dim[0] * Dim[1] * Dim[2];
1121 | ro[1] = Dim[0] * Dim[1];
1122 |
1123 | vtkSmartPointer CurrA = vtkSmartPointer::New();
1124 | vtkSmartPointer NextA = vtkSmartPointer::New();
1125 |
1126 | Volume -> CopyComponent(0,ImageData->GetPointData()->GetScalars(),0);
1127 | Volume -> Modified();
1128 |
1129 | label = 0;
1130 | while (find) {
1131 | for (s = 0; s < CurrA->GetNumberOfIds(); s++) {
1132 | ido = CurrA -> GetId(s);
1133 | ImageData -> GetPoint(ido,r);
1134 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2];
1135 | for (i = 0; i < ngbh; i++) {
1136 | id = ImageData -> FindPoint(x+ssdx_sort[i],y+ssdy_sort[i],z+ssdz_sort[i]);
1137 | v = Volume -> GetTuple1(id);
1138 | if (v > threshold) {
1139 | NextA -> InsertNextId(id);
1140 | Volume -> SetTuple1(id,-label);
1141 | scluster++;
1142 | }
1143 | }
1144 | }
1145 | if (!NextA->GetNumberOfIds()) {
1146 | find = false;
1147 | for (id=ro[0]; id--;) {
1148 | v = Volume -> GetTuple1(id);
1149 | if (v > threshold) {
1150 | find = true;
1151 | ro[0] = id;
1152 | break;
1153 | }
1154 | }
1155 | if (label) {
1156 | CSz.push_back(scluster);
1157 | }
1158 | if (find) {
1159 | label++;
1160 | scluster = 1;
1161 | Volume -> SetTuple1(id,-label);
1162 | CurrA -> InsertNextId(id);
1163 | }
1164 | } else {
1165 | CurrA -> Reset();
1166 | CurrA -> DeepCopy(NextA);
1167 | NextA -> Reset();
1168 | }
1169 | }
1170 |
1171 | #ifdef DEBUG
1172 | printf("\tNumber of detected components: %ld\n",(long int)CSz.size());
1173 | #endif
1174 |
1175 | //return (long int)CSz->GetNumberOfTuples();
1176 | return (long int)CSz.size();
1177 | }
1178 |
--------------------------------------------------------------------------------
/MitoThinning.h:
--------------------------------------------------------------------------------
1 | #ifndef MITOTHINNING_H
2 | #define MITOTHINNING_H
3 |
4 | #include "includes.h"
5 |
6 | extern double _rad;
7 | extern double _dxy, _dz;
8 | extern bool _export_graph_files;
9 | extern bool _scale_polydata_before_save;
10 | extern bool _export_nodes_label;
11 | extern double _div_threshold;
12 | extern bool _improve_skeleton_quality;
13 |
14 | extern int ssdx_sort[26];
15 | extern int ssdy_sort[26];
16 | extern int ssdz_sort[26];
17 |
18 | // Thinning algorithm based on the paper: "A 3D 6-subinteration thinning
19 | // algorithm for extracting medial lines", by Kálman Palágyi and Attila
20 | // Kuba.
21 | vtkSmartPointer Thinning3D(vtkSmartPointer ImageData, _mitoObject *mitoObject);
22 |
23 | // Routine used to save an ImageData
24 | void SaveImageData(vtkSmartPointer Image, const char FileName[], bool _resample = false);
25 |
26 | // Routine used to save a PolyData
27 | void SavePolyData(vtkSmartPointer PolyData, const char FileName[]);
28 |
29 | // Calculate the length of a given edge.
30 | double GetEdgeLength(vtkIdType edge, vtkSmartPointer PolyData);
31 |
32 | // Label connected components in Image. Results are stored
33 | // in Volume as negative labels. The routine returns the total
34 | // number of connected components.
35 | long int LabelConnectedComponents(vtkSmartPointer ImageData, vtkSmartPointer Volume, std::vector &CSz, int ngbh, double threshold);
36 |
37 | // Routine to delete all voxels located at boundaries of the
38 | // image volume. Otherwise the algorithm will have problems
39 | // checking the 3D neighborhood of those voxels.
40 | void CleanImageBoundaries(vtkSmartPointer ImageData);
41 |
42 | #endif
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | MitoGraph is a fully automated image processing method and software dedicated to calculating the three-dimensional morphology of mitochondria in live cells. MitoGraph is currently optimized and validated only for quantifying the volume and topology of tubular mitochondrial networks in budding yeast [1,2]. However, MitoGraph can also be applied to mitochondria in other cell types and possibly other intracellular (or tissue) structures, with proper validation. MitoGraph is continuously being updated. Please contact us if you have questions that go beyond those discussed in [1,2] or any request that would make MitoGraph a better tool for your research.
6 |
7 | Matheus Viana - vianamp@gmail.com - 06.25.2024
8 |
9 | ### v3.1 Release
10 |
11 | ✓ MitoGraph is now compatible to Windows 10
12 |
13 | ✓ Extra flag `-export_image_binary` to export the segmented version of the input
14 |
15 | ### v3.0 Release
16 |
17 | ✓ Adaptive threshold
18 |
19 | ✓ Support binary and VTK input
20 |
21 | ✓ Support 2D image data
22 |
23 | ✓ Export skeleton coordinates as text file
24 |
25 | ✓ Save skeleton with information of mitochondrial tubules width, pixel intensity, edge length and nodes position
26 |
27 | ### v2.1 Release
28 |
29 | ✓ Extra flag that lets you use __R__ to perform basic analysis of MitoGraph output
30 |
31 | ---
32 |
33 | ### How to Install
34 |
35 | Please follow the steps bellow to install MitoGraph.
36 |
37 | 1. Download the latest version of MitoGraph available for Mac OSX 10.10 or later
38 |
39 | 2. Create a folder in your Desktop and name it MitoGraph
40 |
41 | 3. Move the downloaded file to the folder MitoGraph in your and unzip it
42 |
43 | ---
44 |
45 | ### Testing Data, ImageJ Macros and Other Tools
46 |
47 | Before running MitoGraph on your own dataset, you may want to check the tools we made available for preparing your data and our test datasets.
48 |
49 |
50 |
51 |
52 |
53 | * MitoGraph Tools: in this repository you will find an example dataset to test MitoGraph on. There is also two ImageJ scripts that help you to prepare your data to make them similar to our test dataset.
54 |
55 | ---
56 |
57 | ### How to Run MitoGraph
58 |
59 | Download the test dataset mentioned in the previous section and unzip the downloaded file in your Desktop. Type the following command in the terminal of your Mac OS (spotlight + terminal)
60 |
61 | `cd ~/Desktop/MitoGraph`
62 |
63 | `./MitoGraph -xy 0.056 -z 0.2 -path ~/Desktop/MitoGraphTools-1.0`
64 |
65 | The flag `-xy` specifies the pixel size in microns and the flag `-z` specifies the z-spacing also in microns of your images. Finally, the flag `-path` indicates the folder that contains the images you want to analyze.
66 |
67 | #### Optional Flags
68 |
69 | `-scales a b c` where a, b and c are numeric values specifying the initial, final and total number of scales which should be used by MitoGraph [1]. For example: `-scales 1.5 2.0 6`. Default values are a=1.0, b=1.5 and c=6.
70 |
71 | `-threshold a` where a is numeric value in the range [0,1] for the post-divergence threshold. For example: `-threshold 0.1`. Default value is a=0.1667.
72 |
73 | `-adaptive a` where a is a numeric integer value specifying that the input image should be split into a x a blocks before the segmentation. This is useful for images with high variablity of pixel intensity.
74 |
75 | `-binary`: indicates that the input is a binary image.
76 |
77 | `-vtk`: indicates that the input data is of __VTK Imagedata__ type instead of TIFF.
78 |
79 | `-labels_off`: turns off the labels of nodes in the output file __filename_nodes.vtk__.
80 |
81 | `-analyze`: uses R to do a per connected component analysis of MitoGraph output. This flag requires __R__ and its package __igraph__ to be installed in your system.
82 |
83 | ---
84 |
85 | ### MitoGraph Outputs
86 |
87 | The output of MitoGraph will be saved in the directory specified with `-path`.
88 |
89 | **Single files:**
90 |
91 | * __mitograph.config__ - Stores the parameters used to run MitoGraph and the date and time when the analysis was complete.
92 |
93 | **Text files that can be open in any Text Editor (one file per sample):**
94 |
95 | * __filename.gnet__ - Connection list of type `node_i` `node_j` of the graph that represents the mitochondria. First line of this file gives the total number of nodes.
96 | * __filename.coo__ - Coordinates xyz of nodes in the graph.
97 | * __filename.mitograph__ - Mitochondrial attributes: volume from voxels, average width (µm), std width (µm), total length (µm) and volume from length (µm3). This file also shows per component statistics when the flag `-analyze` is used.
98 | * __filename.txt__ - Coordinates of all the points along the mitochondrial skeleton as well as the local width (µm) and original pixel intensity.
99 | * __filename.cc__ - Connected component which each node belong to and the component volume (µm3). Only when the flag `-analyze` is used.
100 |
101 | **Image files (one file per sample):**
102 |
103 | * __filename.png__ - Max projection of mitochondria after MitoGraph binarization. Should be used for fast assessment of MitoGraph segmentation result.
104 |
105 | **VTK files that can be open using Paraview [3] (one file per sample):**
106 |
107 | * __filename_Nodes.vtk__ - Nodes of the graph that represents the mitochondria and their labels.
108 | * __filename_skeleton.vtk__ - Mitochondrial skeleton. This file contains information about mitochondrial tubule width, pixel intensity, edge length and nodes position that can be viewd in Paraview by setting the coloring mode.
109 | * __filename_mitosurface.vtk__ - Mitochondrial surface.
110 |
111 | ---
112 |
113 | ### Contributions to MitoGraph
114 |
115 | * With help of Hill Lab, we also provide an example dataset of mitochondria in mammalian cells and R scripts that will help you to analyze the data generated by MitoGraph. Please, check this out in MitoGraph-Contrib-RScripts.
116 |
117 | ---
118 |
119 | ### References
120 |
121 | [1] - Matheus P Viana, Swee Lim, Susanne M Rafelski, Quantifying Mitochondrial Content in Living Cells (2015), Biophysical Methods in Cell Biology, (125) - 77-93 (http://www.sciencedirect.com/science/article/pii/S0091679X14000041)
122 |
123 | [2] - Viana, M.P., Brown, A.I., Mueller, I.A., Goul, C., Koslover, E.F. and Rafelski, S.M., 2020. Mitochondrial Fission and Fusion Dynamics Generate Efficient, Robust, and Evenly Distributed Network Topologies in Budding Yeast Cells. Cell Systems (https://www.cell.com/cell-systems/fulltext/S2405-4712(20)30035-1)
124 |
125 | [3] - https://www.paraview.org/
126 |
--------------------------------------------------------------------------------
/ThirdPartLicenses.txt:
--------------------------------------------------------------------------------
1 | Vizualization Toolkit - VTK
2 | ---------------------------
3 |
4 | Copyright (c) 1993-2008 Ken Martin, Will Schroeder, Bill Lorensen
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | * Redistributions of source code must retain the above copyright notice,
11 | this list of conditions and the following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above copyright notice,
14 | this list of conditions and the following disclaimer in the documentation
15 | and/or other materials provided with the distribution.
16 |
17 | * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
18 | of any contributors may be used to endorse or promote products derived
19 | from this software without specific prior written permission.
20 |
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/data/MitoGraphTest001.tif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vianamp/MitoGraph/70819e5f517e968fd11870b3d99764f827a7a289/data/MitoGraphTest001.tif
--------------------------------------------------------------------------------
/doc/Readme.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/doc/mitograph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vianamp/MitoGraph/70819e5f517e968fd11870b3d99764f827a7a289/doc/mitograph.png
--------------------------------------------------------------------------------
/includes.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #ifdef _WIN32
8 | #include "includes/dirent.h"
9 | #else
10 | #include
11 | #endif
12 |
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 | #include
46 | #include
47 | #include
48 | #include
49 | #include
50 | #include
51 | #include
52 | #include
53 | #include
54 |
55 | #ifndef _MITOGRAPH_ENV_VARS
56 |
57 | #define _MITOGRAPH_ENV_VARS
58 |
59 | struct attribute { std::string name; double value; };
60 |
61 | struct _mitoObject {
62 | std::string Type;
63 | std::string Folder;
64 | std::string FileName;
65 | bool _analyze;
66 | bool _binary_input;
67 | double Ox;
68 | double Oy;
69 | double Oz;
70 | double _sigmai;
71 | double _sigmaf;
72 | double _dsigma;
73 | int _nsigma;
74 | bool _adaptive_threshold;
75 | int _nblks;
76 |
77 | std::vector attributes;
78 | };
79 |
80 | #endif
81 |
82 | // #define DEBUG
83 | #include "ssThinning.h"
84 | #include "MitoThinning.h"
85 |
--------------------------------------------------------------------------------
/includes/dirent.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Dirent interface for Microsoft Visual Studio
3 | *
4 | * Copyright (C) 1998-2019 Toni Ronkko
5 | * This file is part of dirent. Dirent may be freely distributed
6 | * under the MIT license. For all details and documentation, see
7 | * https://github.com/tronkko/dirent
8 | */
9 | #ifndef DIRENT_H
10 | #define DIRENT_H
11 |
12 | /* Hide warnings about unreferenced local functions */
13 | #if defined(__clang__)
14 | # pragma clang diagnostic ignored "-Wunused-function"
15 | #elif defined(_MSC_VER)
16 | # pragma warning(disable:4505)
17 | #elif defined(__GNUC__)
18 | # pragma GCC diagnostic ignored "-Wunused-function"
19 | #endif
20 |
21 | /*
22 | * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
23 | * Windows Sockets 2.0.
24 | */
25 | #ifndef WIN32_LEAN_AND_MEAN
26 | # define WIN32_LEAN_AND_MEAN
27 | #endif
28 | #include
29 |
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 |
41 | /* Indicates that d_type field is available in dirent structure */
42 | #define _DIRENT_HAVE_D_TYPE
43 |
44 | /* Indicates that d_namlen field is available in dirent structure */
45 | #define _DIRENT_HAVE_D_NAMLEN
46 |
47 | /* Entries missing from MSVC 6.0 */
48 | #if !defined(FILE_ATTRIBUTE_DEVICE)
49 | # define FILE_ATTRIBUTE_DEVICE 0x40
50 | #endif
51 |
52 | /* File type and permission flags for stat(), general mask */
53 | #if !defined(S_IFMT)
54 | # define S_IFMT _S_IFMT
55 | #endif
56 |
57 | /* Directory bit */
58 | #if !defined(S_IFDIR)
59 | # define S_IFDIR _S_IFDIR
60 | #endif
61 |
62 | /* Character device bit */
63 | #if !defined(S_IFCHR)
64 | # define S_IFCHR _S_IFCHR
65 | #endif
66 |
67 | /* Pipe bit */
68 | #if !defined(S_IFFIFO)
69 | # define S_IFFIFO _S_IFFIFO
70 | #endif
71 |
72 | /* Regular file bit */
73 | #if !defined(S_IFREG)
74 | # define S_IFREG _S_IFREG
75 | #endif
76 |
77 | /* Read permission */
78 | #if !defined(S_IREAD)
79 | # define S_IREAD _S_IREAD
80 | #endif
81 |
82 | /* Write permission */
83 | #if !defined(S_IWRITE)
84 | # define S_IWRITE _S_IWRITE
85 | #endif
86 |
87 | /* Execute permission */
88 | #if !defined(S_IEXEC)
89 | # define S_IEXEC _S_IEXEC
90 | #endif
91 |
92 | /* Pipe */
93 | #if !defined(S_IFIFO)
94 | # define S_IFIFO _S_IFIFO
95 | #endif
96 |
97 | /* Block device */
98 | #if !defined(S_IFBLK)
99 | # define S_IFBLK 0
100 | #endif
101 |
102 | /*
103 | * Symbolic link. Be ware that S_IFLNK value and S_ISLNK() macro are only
104 | * usable with dirent - they do not work with stat() function call!
105 | */
106 | #if !defined(S_IFLNK)
107 | # define S_IFLNK (_S_IFDIR | _S_IFREG)
108 | #endif
109 |
110 | /* Socket */
111 | #if !defined(S_IFSOCK)
112 | # define S_IFSOCK 0
113 | #endif
114 |
115 | /* Read user permission */
116 | #if !defined(S_IRUSR)
117 | # define S_IRUSR S_IREAD
118 | #endif
119 |
120 | /* Write user permission */
121 | #if !defined(S_IWUSR)
122 | # define S_IWUSR S_IWRITE
123 | #endif
124 |
125 | /* Execute user permission */
126 | #if !defined(S_IXUSR)
127 | # define S_IXUSR 0
128 | #endif
129 |
130 | /* User full permissions */
131 | #if !defined(S_IRWXU)
132 | # define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
133 | #endif
134 |
135 | /* Read group permission */
136 | #if !defined(S_IRGRP)
137 | # define S_IRGRP 0
138 | #endif
139 |
140 | /* Write group permission */
141 | #if !defined(S_IWGRP)
142 | # define S_IWGRP 0
143 | #endif
144 |
145 | /* Execute group permission */
146 | #if !defined(S_IXGRP)
147 | # define S_IXGRP 0
148 | #endif
149 |
150 | /* Group full permissions */
151 | #if !defined(S_IRWXG)
152 | # define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
153 | #endif
154 |
155 | /* Read others permission */
156 | #if !defined(S_IROTH)
157 | # define S_IROTH 0
158 | #endif
159 |
160 | /* Write others permission */
161 | #if !defined(S_IWOTH)
162 | # define S_IWOTH 0
163 | #endif
164 |
165 | /* Execute others permission */
166 | #if !defined(S_IXOTH)
167 | # define S_IXOTH 0
168 | #endif
169 |
170 | /* Other full permissions */
171 | #if !defined(S_IRWXO)
172 | # define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
173 | #endif
174 |
175 | /* Maximum length of file name */
176 | #if !defined(PATH_MAX)
177 | # define PATH_MAX MAX_PATH
178 | #endif
179 | #if !defined(FILENAME_MAX)
180 | # define FILENAME_MAX MAX_PATH
181 | #endif
182 | #if !defined(NAME_MAX)
183 | # define NAME_MAX FILENAME_MAX
184 | #endif
185 |
186 | /* File type flags for d_type */
187 | #define DT_UNKNOWN 0
188 | #define DT_REG S_IFREG
189 | #define DT_DIR S_IFDIR
190 | #define DT_FIFO S_IFIFO
191 | #define DT_SOCK S_IFSOCK
192 | #define DT_CHR S_IFCHR
193 | #define DT_BLK S_IFBLK
194 | #define DT_LNK S_IFLNK
195 |
196 | /* Macros for converting between st_mode and d_type */
197 | #define IFTODT(mode) ((mode) & S_IFMT)
198 | #define DTTOIF(type) (type)
199 |
200 | /*
201 | * File type macros. Note that block devices and sockets cannot be
202 | * distinguished on Windows, and the macros S_ISBLK and S_ISSOCK are only
203 | * defined for compatibility. These macros should always return false on
204 | * Windows.
205 | */
206 | #if !defined(S_ISFIFO)
207 | # define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
208 | #endif
209 | #if !defined(S_ISDIR)
210 | # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
211 | #endif
212 | #if !defined(S_ISREG)
213 | # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
214 | #endif
215 | #if !defined(S_ISLNK)
216 | # define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
217 | #endif
218 | #if !defined(S_ISSOCK)
219 | # define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
220 | #endif
221 | #if !defined(S_ISCHR)
222 | # define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
223 | #endif
224 | #if !defined(S_ISBLK)
225 | # define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
226 | #endif
227 |
228 | /* Return the exact length of the file name without zero terminator */
229 | #define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
230 |
231 | /* Return the maximum size of a file name */
232 | #define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
233 |
234 |
235 | #ifdef __cplusplus
236 | extern "C" {
237 | #endif
238 |
239 |
240 | /* Wide-character version */
241 | struct _wdirent {
242 | /* Always zero */
243 | long d_ino;
244 |
245 | /* Position of next file in a directory stream */
246 | long d_off;
247 |
248 | /* Structure size */
249 | unsigned short d_reclen;
250 |
251 | /* Length of name without \0 */
252 | size_t d_namlen;
253 |
254 | /* File type */
255 | int d_type;
256 |
257 | /* File name */
258 | wchar_t d_name[PATH_MAX+1];
259 | };
260 | typedef struct _wdirent _wdirent;
261 |
262 | struct _WDIR {
263 | /* Current directory entry */
264 | struct _wdirent ent;
265 |
266 | /* Private file data */
267 | WIN32_FIND_DATAW data;
268 |
269 | /* True if data is valid */
270 | int cached;
271 |
272 | /* True if next entry is invalid */
273 | int invalid;
274 |
275 | /* Win32 search handle */
276 | HANDLE handle;
277 |
278 | /* Initial directory name */
279 | wchar_t *patt;
280 | };
281 | typedef struct _WDIR _WDIR;
282 |
283 | /* Multi-byte character version */
284 | struct dirent {
285 | /* Always zero */
286 | long d_ino;
287 |
288 | /* Position of next file in a directory stream */
289 | long d_off;
290 |
291 | /* Structure size */
292 | unsigned short d_reclen;
293 |
294 | /* Length of name without \0 */
295 | size_t d_namlen;
296 |
297 | /* File type */
298 | int d_type;
299 |
300 | /* File name */
301 | char d_name[PATH_MAX+1];
302 | };
303 | typedef struct dirent dirent;
304 |
305 | struct DIR {
306 | struct dirent ent;
307 | struct _WDIR *wdirp;
308 | };
309 | typedef struct DIR DIR;
310 |
311 |
312 | /* Dirent functions */
313 | static DIR *opendir(const char *dirname);
314 | static _WDIR *_wopendir(const wchar_t *dirname);
315 |
316 | static struct dirent *readdir(DIR *dirp);
317 | static struct _wdirent *_wreaddir(_WDIR *dirp);
318 |
319 | static int readdir_r(
320 | DIR *dirp, struct dirent *entry, struct dirent **result);
321 | static int _wreaddir_r(
322 | _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);
323 |
324 | static int closedir(DIR *dirp);
325 | static int _wclosedir(_WDIR *dirp);
326 |
327 | static void rewinddir(DIR *dirp);
328 | static void _wrewinddir(_WDIR *dirp);
329 |
330 | static long telldir(DIR *dirp);
331 | static long _wtelldir(_WDIR *dirp);
332 |
333 | static void seekdir(DIR *dirp, long loc);
334 | static void _wseekdir(_WDIR *dirp, long loc);
335 |
336 | static int scandir(const char *dirname, struct dirent ***namelist,
337 | int (*filter)(const struct dirent*),
338 | int (*compare)(const struct dirent**, const struct dirent**));
339 |
340 | static int alphasort(const struct dirent **a, const struct dirent **b);
341 |
342 | static int versionsort(const struct dirent **a, const struct dirent **b);
343 |
344 | static int strverscmp(const char *a, const char *b);
345 |
346 | /* For compatibility with Symbian */
347 | #define wdirent _wdirent
348 | #define WDIR _WDIR
349 | #define wopendir _wopendir
350 | #define wreaddir _wreaddir
351 | #define wclosedir _wclosedir
352 | #define wrewinddir _wrewinddir
353 | #define wtelldir _wtelldir
354 | #define wseekdir _wseekdir
355 |
356 | /* Compatibility with older Microsoft compilers and non-Microsoft compilers */
357 | #if !defined(_MSC_VER) || _MSC_VER < 1400
358 | # define wcstombs_s dirent_wcstombs_s
359 | # define mbstowcs_s dirent_mbstowcs_s
360 | #endif
361 |
362 | /* Optimize dirent_set_errno() away on modern Microsoft compilers */
363 | #if defined(_MSC_VER) && _MSC_VER >= 1400
364 | # define dirent_set_errno _set_errno
365 | #endif
366 |
367 |
368 | /* Internal utility functions */
369 | static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp);
370 | static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp);
371 | static long dirent_hash(WIN32_FIND_DATAW *datap);
372 |
373 | #if !defined(_MSC_VER) || _MSC_VER < 1400
374 | static int dirent_mbstowcs_s(
375 | size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords,
376 | const char *mbstr, size_t count);
377 | #endif
378 |
379 | #if !defined(_MSC_VER) || _MSC_VER < 1400
380 | static int dirent_wcstombs_s(
381 | size_t *pReturnValue, char *mbstr, size_t sizeInBytes,
382 | const wchar_t *wcstr, size_t count);
383 | #endif
384 |
385 | #if !defined(_MSC_VER) || _MSC_VER < 1400
386 | static void dirent_set_errno(int error);
387 | #endif
388 |
389 |
390 | /*
391 | * Open directory stream DIRNAME for read and return a pointer to the
392 | * internal working area that is used to retrieve individual directory
393 | * entries.
394 | */
395 | static _WDIR *
396 | _wopendir(const wchar_t *dirname)
397 | {
398 | wchar_t *p;
399 |
400 | /* Must have directory name */
401 | if (dirname == NULL || dirname[0] == '\0') {
402 | dirent_set_errno(ENOENT);
403 | return NULL;
404 | }
405 |
406 | /* Allocate new _WDIR structure */
407 | _WDIR *dirp = (_WDIR*) malloc(sizeof(struct _WDIR));
408 | if (!dirp)
409 | return NULL;
410 |
411 | /* Reset _WDIR structure */
412 | dirp->handle = INVALID_HANDLE_VALUE;
413 | dirp->patt = NULL;
414 | dirp->cached = 0;
415 | dirp->invalid = 0;
416 |
417 | /*
418 | * Compute the length of full path plus zero terminator
419 | *
420 | * Note that on WinRT there's no way to convert relative paths
421 | * into absolute paths, so just assume it is an absolute path.
422 | */
423 | #if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
424 | /* Desktop */
425 | DWORD n = GetFullPathNameW(dirname, 0, NULL, NULL);
426 | #else
427 | /* WinRT */
428 | size_t n = wcslen(dirname);
429 | #endif
430 |
431 | /* Allocate room for absolute directory name and search pattern */
432 | dirp->patt = (wchar_t*) malloc(sizeof(wchar_t) * n + 16);
433 | if (dirp->patt == NULL)
434 | goto exit_closedir;
435 |
436 | /*
437 | * Convert relative directory name to an absolute one. This
438 | * allows rewinddir() to function correctly even when current
439 | * working directory is changed between opendir() and rewinddir().
440 | *
441 | * Note that on WinRT there's no way to convert relative paths
442 | * into absolute paths, so just assume it is an absolute path.
443 | */
444 | #if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
445 | /* Desktop */
446 | n = GetFullPathNameW(dirname, n, dirp->patt, NULL);
447 | if (n <= 0)
448 | goto exit_closedir;
449 | #else
450 | /* WinRT */
451 | wcsncpy_s(dirp->patt, n+1, dirname, n);
452 | #endif
453 |
454 | /* Append search pattern \* to the directory name */
455 | p = dirp->patt + n;
456 | switch (p[-1]) {
457 | case '\\':
458 | case '/':
459 | case ':':
460 | /* Directory ends in path separator, e.g. c:\temp\ */
461 | /*NOP*/;
462 | break;
463 |
464 | default:
465 | /* Directory name doesn't end in path separator */
466 | *p++ = '\\';
467 | }
468 | *p++ = '*';
469 | *p = '\0';
470 |
471 | /* Open directory stream and retrieve the first entry */
472 | if (!dirent_first(dirp))
473 | goto exit_closedir;
474 |
475 | /* Success */
476 | return dirp;
477 |
478 | /* Failure */
479 | exit_closedir:
480 | _wclosedir(dirp);
481 | return NULL;
482 | }
483 |
484 | /*
485 | * Read next directory entry.
486 | *
487 | * Returns pointer to static directory entry which may be overwritten by
488 | * subsequent calls to _wreaddir().
489 | */
490 | static struct _wdirent *
491 | _wreaddir(_WDIR *dirp)
492 | {
493 | /*
494 | * Read directory entry to buffer. We can safely ignore the return
495 | * value as entry will be set to NULL in case of error.
496 | */
497 | struct _wdirent *entry;
498 | (void) _wreaddir_r(dirp, &dirp->ent, &entry);
499 |
500 | /* Return pointer to statically allocated directory entry */
501 | return entry;
502 | }
503 |
504 | /*
505 | * Read next directory entry.
506 | *
507 | * Returns zero on success. If end of directory stream is reached, then sets
508 | * result to NULL and returns zero.
509 | */
510 | static int
511 | _wreaddir_r(
512 | _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result)
513 | {
514 | /* Validate directory handle */
515 | if (!dirp || dirp->handle == INVALID_HANDLE_VALUE || !dirp->patt) {
516 | dirent_set_errno(EBADF);
517 | *result = NULL;
518 | return -1;
519 | }
520 |
521 | /* Read next directory entry */
522 | WIN32_FIND_DATAW *datap = dirent_next(dirp);
523 | if (!datap) {
524 | /* Return NULL to indicate end of directory */
525 | *result = NULL;
526 | return /*OK*/0;
527 | }
528 |
529 | /*
530 | * Copy file name as wide-character string. If the file name is too
531 | * long to fit in to the destination buffer, then truncate file name
532 | * to PATH_MAX characters and zero-terminate the buffer.
533 | */
534 | size_t i = 0;
535 | while (i < PATH_MAX && datap->cFileName[i] != 0) {
536 | entry->d_name[i] = datap->cFileName[i];
537 | i++;
538 | }
539 | entry->d_name[i] = 0;
540 |
541 | /* Length of file name excluding zero terminator */
542 | entry->d_namlen = i;
543 |
544 | /* Determine file type */
545 | DWORD attr = datap->dwFileAttributes;
546 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
547 | entry->d_type = DT_CHR;
548 | else if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0)
549 | entry->d_type = DT_LNK;
550 | else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
551 | entry->d_type = DT_DIR;
552 | else
553 | entry->d_type = DT_REG;
554 |
555 | /* Read the next directory entry to cache */
556 | datap = dirent_next(dirp);
557 | if (datap) {
558 | /* Compute 31-bit hash of the next directory entry */
559 | entry->d_off = dirent_hash(datap);
560 |
561 | /* Push the next directory entry back to cache */
562 | dirp->cached = 1;
563 | } else {
564 | /* End of directory stream */
565 | entry->d_off = (long) ((~0UL) >> 1);
566 | }
567 |
568 | /* Reset other fields */
569 | entry->d_ino = 0;
570 | entry->d_reclen = sizeof(struct _wdirent);
571 |
572 | /* Set result address */
573 | *result = entry;
574 | return /*OK*/0;
575 | }
576 |
577 | /*
578 | * Close directory stream opened by opendir() function. This invalidates the
579 | * DIR structure as well as any directory entry read previously by
580 | * _wreaddir().
581 | */
582 | static int
583 | _wclosedir(_WDIR *dirp)
584 | {
585 | if (!dirp) {
586 | dirent_set_errno(EBADF);
587 | return /*failure*/-1;
588 | }
589 |
590 | /*
591 | * Release search handle if we have one. Being able to handle
592 | * partially initialized _WDIR structure allows us to use this
593 | * function to handle errors occurring within _wopendir.
594 | */
595 | if (dirp->handle != INVALID_HANDLE_VALUE) {
596 | FindClose(dirp->handle);
597 | }
598 |
599 | /*
600 | * Release search pattern. Note that we don't need to care if
601 | * dirp->patt is NULL or not: function free is guaranteed to act
602 | * appropriately.
603 | */
604 | free(dirp->patt);
605 |
606 | /* Release directory structure */
607 | free(dirp);
608 | return /*success*/0;
609 | }
610 |
611 | /*
612 | * Rewind directory stream such that _wreaddir() returns the very first
613 | * file name again.
614 | */
615 | static void _wrewinddir(_WDIR* dirp)
616 | {
617 | /* Check directory pointer */
618 | if (!dirp || dirp->handle == INVALID_HANDLE_VALUE || !dirp->patt)
619 | return;
620 |
621 | /* Release existing search handle */
622 | FindClose(dirp->handle);
623 |
624 | /* Open new search handle */
625 | dirent_first(dirp);
626 | }
627 |
628 | /* Get first directory entry */
629 | static WIN32_FIND_DATAW *
630 | dirent_first(_WDIR *dirp)
631 | {
632 | /* Open directory and retrieve the first entry */
633 | dirp->handle = FindFirstFileExW(
634 | dirp->patt, FindExInfoStandard, &dirp->data,
635 | FindExSearchNameMatch, NULL, 0);
636 | if (dirp->handle == INVALID_HANDLE_VALUE)
637 | goto error;
638 |
639 | /* A directory entry is now waiting in memory */
640 | dirp->cached = 1;
641 | return &dirp->data;
642 |
643 | error:
644 | /* Failed to open directory: no directory entry in memory */
645 | dirp->cached = 0;
646 | dirp->invalid = 1;
647 |
648 | /* Set error code */
649 | DWORD errorcode = GetLastError();
650 | switch (errorcode) {
651 | case ERROR_ACCESS_DENIED:
652 | /* No read access to directory */
653 | dirent_set_errno(EACCES);
654 | break;
655 |
656 | case ERROR_DIRECTORY:
657 | /* Directory name is invalid */
658 | dirent_set_errno(ENOTDIR);
659 | break;
660 |
661 | case ERROR_PATH_NOT_FOUND:
662 | default:
663 | /* Cannot find the file */
664 | dirent_set_errno(ENOENT);
665 | }
666 | return NULL;
667 | }
668 |
669 | /* Get next directory entry */
670 | static WIN32_FIND_DATAW *
671 | dirent_next(_WDIR *dirp)
672 | {
673 | /* Return NULL if seek position was invalid */
674 | if (dirp->invalid)
675 | return NULL;
676 |
677 | /* Is the next directory entry already in cache? */
678 | if (dirp->cached) {
679 | /* Yes, a valid directory entry found in memory */
680 | dirp->cached = 0;
681 | return &dirp->data;
682 | }
683 |
684 | /* Read the next directory entry from stream */
685 | if (FindNextFileW(dirp->handle, &dirp->data) == FALSE) {
686 | /* End of directory stream */
687 | return NULL;
688 | }
689 |
690 | /* Success */
691 | return &dirp->data;
692 | }
693 |
694 | /*
695 | * Compute 31-bit hash of file name.
696 | *
697 | * See djb2 at http://www.cse.yorku.ca/~oz/hash.html
698 | */
699 | static long
700 | dirent_hash(WIN32_FIND_DATAW *datap)
701 | {
702 | unsigned long hash = 5381;
703 | unsigned long c;
704 | const wchar_t *p = datap->cFileName;
705 | const wchar_t *e = p + MAX_PATH;
706 | while (p != e && (c = *p++) != 0) {
707 | hash = (hash << 5) + hash + c;
708 | }
709 |
710 | return (long) (hash & ((~0UL) >> 1));
711 | }
712 |
713 | /* Open directory stream using plain old C-string */
714 | static DIR *opendir(const char *dirname)
715 | {
716 | /* Must have directory name */
717 | if (dirname == NULL || dirname[0] == '\0') {
718 | dirent_set_errno(ENOENT);
719 | return NULL;
720 | }
721 |
722 | /* Allocate memory for DIR structure */
723 | struct DIR *dirp = (DIR*) malloc(sizeof(struct DIR));
724 | if (!dirp)
725 | return NULL;
726 |
727 | /* Convert directory name to wide-character string */
728 | wchar_t wname[PATH_MAX + 1];
729 | size_t n;
730 | int error = mbstowcs_s(&n, wname, PATH_MAX + 1, dirname, PATH_MAX+1);
731 | if (error)
732 | goto exit_failure;
733 |
734 | /* Open directory stream using wide-character name */
735 | dirp->wdirp = _wopendir(wname);
736 | if (!dirp->wdirp)
737 | goto exit_failure;
738 |
739 | /* Success */
740 | return dirp;
741 |
742 | /* Failure */
743 | exit_failure:
744 | free(dirp);
745 | return NULL;
746 | }
747 |
748 | /* Read next directory entry */
749 | static struct dirent *
750 | readdir(DIR *dirp)
751 | {
752 | /*
753 | * Read directory entry to buffer. We can safely ignore the return
754 | * value as entry will be set to NULL in case of error.
755 | */
756 | struct dirent *entry;
757 | (void) readdir_r(dirp, &dirp->ent, &entry);
758 |
759 | /* Return pointer to statically allocated directory entry */
760 | return entry;
761 | }
762 |
763 | /*
764 | * Read next directory entry into called-allocated buffer.
765 | *
766 | * Returns zero on success. If the end of directory stream is reached, then
767 | * sets result to NULL and returns zero.
768 | */
769 | static int
770 | readdir_r(
771 | DIR *dirp, struct dirent *entry, struct dirent **result)
772 | {
773 | /* Read next directory entry */
774 | WIN32_FIND_DATAW *datap = dirent_next(dirp->wdirp);
775 | if (!datap) {
776 | /* No more directory entries */
777 | *result = NULL;
778 | return /*OK*/0;
779 | }
780 |
781 | /* Attempt to convert file name to multi-byte string */
782 | size_t n;
783 | int error = wcstombs_s(
784 | &n, entry->d_name, PATH_MAX + 1,
785 | datap->cFileName, PATH_MAX + 1);
786 |
787 | /*
788 | * If the file name cannot be represented by a multi-byte string, then
789 | * attempt to use old 8+3 file name. This allows the program to
790 | * access files although file names may seem unfamiliar to the user.
791 | *
792 | * Be ware that the code below cannot come up with a short file name
793 | * unless the file system provides one. At least VirtualBox shared
794 | * folders fail to do this.
795 | */
796 | if (error && datap->cAlternateFileName[0] != '\0') {
797 | error = wcstombs_s(
798 | &n, entry->d_name, PATH_MAX + 1,
799 | datap->cAlternateFileName, PATH_MAX + 1);
800 | }
801 |
802 | if (!error) {
803 | /* Length of file name excluding zero terminator */
804 | entry->d_namlen = n - 1;
805 |
806 | /* Determine file type */
807 | DWORD attr = datap->dwFileAttributes;
808 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
809 | entry->d_type = DT_CHR;
810 | else if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0)
811 | entry->d_type = DT_LNK;
812 | else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
813 | entry->d_type = DT_DIR;
814 | else
815 | entry->d_type = DT_REG;
816 |
817 | /* Get offset of next file */
818 | datap = dirent_next(dirp->wdirp);
819 | if (datap) {
820 | /* Compute 31-bit hash of the next directory entry */
821 | entry->d_off = dirent_hash(datap);
822 |
823 | /* Push the next directory entry back to cache */
824 | dirp->wdirp->cached = 1;
825 | } else {
826 | /* End of directory stream */
827 | entry->d_off = (long) ((~0UL) >> 1);
828 | }
829 |
830 | /* Reset fields */
831 | entry->d_ino = 0;
832 | entry->d_reclen = sizeof(struct dirent);
833 | } else {
834 | /*
835 | * Cannot convert file name to multi-byte string so construct
836 | * an erroneous directory entry and return that. Note that
837 | * we cannot return NULL as that would stop the processing
838 | * of directory entries completely.
839 | */
840 | entry->d_name[0] = '?';
841 | entry->d_name[1] = '\0';
842 | entry->d_namlen = 1;
843 | entry->d_type = DT_UNKNOWN;
844 | entry->d_ino = 0;
845 | entry->d_off = -1;
846 | entry->d_reclen = 0;
847 | }
848 |
849 | /* Return pointer to directory entry */
850 | *result = entry;
851 | return /*OK*/0;
852 | }
853 |
854 | /* Close directory stream */
855 | static int
856 | closedir(DIR *dirp)
857 | {
858 | int ok;
859 |
860 | if (!dirp)
861 | goto exit_failure;
862 |
863 | /* Close wide-character directory stream */
864 | ok = _wclosedir(dirp->wdirp);
865 | dirp->wdirp = NULL;
866 |
867 | /* Release multi-byte character version */
868 | free(dirp);
869 | return ok;
870 |
871 | exit_failure:
872 | /* Invalid directory stream */
873 | dirent_set_errno(EBADF);
874 | return /*failure*/-1;
875 | }
876 |
877 | /* Rewind directory stream to beginning */
878 | static void
879 | rewinddir(DIR *dirp)
880 | {
881 | if (!dirp)
882 | return;
883 |
884 | /* Rewind wide-character string directory stream */
885 | _wrewinddir(dirp->wdirp);
886 | }
887 |
888 | /* Get position of directory stream */
889 | static long
890 | _wtelldir(_WDIR *dirp)
891 | {
892 | if (!dirp || dirp->handle == INVALID_HANDLE_VALUE) {
893 | dirent_set_errno(EBADF);
894 | return /*failure*/-1;
895 | }
896 |
897 | /* Read next file entry */
898 | WIN32_FIND_DATAW *datap = dirent_next(dirp);
899 | if (!datap) {
900 | /* End of directory stream */
901 | return (long) ((~0UL) >> 1);
902 | }
903 |
904 | /* Store file entry to cache for readdir() */
905 | dirp->cached = 1;
906 |
907 | /* Return the 31-bit hash code to be used as stream position */
908 | return dirent_hash(datap);
909 | }
910 |
911 | /* Get position of directory stream */
912 | static long
913 | telldir(DIR *dirp)
914 | {
915 | if (!dirp) {
916 | dirent_set_errno(EBADF);
917 | return -1;
918 | }
919 |
920 | return _wtelldir(dirp->wdirp);
921 | }
922 |
923 | /* Seek directory stream to offset */
924 | static void
925 | _wseekdir(_WDIR *dirp, long loc)
926 | {
927 | if (!dirp)
928 | return;
929 |
930 | /* Directory must be open */
931 | if (dirp->handle == INVALID_HANDLE_VALUE)
932 | goto exit_failure;
933 |
934 | /* Ensure that seek position is valid */
935 | if (loc < 0)
936 | goto exit_failure;
937 |
938 | /* Restart directory stream from the beginning */
939 | FindClose(dirp->handle);
940 | if (!dirent_first(dirp))
941 | goto exit_failure;
942 |
943 | /* Reset invalid flag so that we can read from the stream again */
944 | dirp->invalid = 0;
945 |
946 | /*
947 | * Read directory entries from the beginning until the hash matches a
948 | * file name. Be ware that hash code is only 31 bits longs and
949 | * duplicates are possible: the hash code cannot return the position
950 | * with 100.00% accuracy! Moreover, the method is slow for large
951 | * directories.
952 | */
953 | long hash;
954 | do {
955 | /* Read next directory entry */
956 | WIN32_FIND_DATAW *datap = dirent_next(dirp);
957 | if (!datap) {
958 | /*
959 | * End of directory stream was reached before finding
960 | * the requested location. Perhaps the file in
961 | * question was deleted or moved out of the directory.
962 | */
963 | goto exit_failure;
964 | }
965 |
966 | /* Does the file name match the hash? */
967 | hash = dirent_hash(datap);
968 | } while (hash != loc);
969 |
970 | /*
971 | * File name matches the hash! Push the directory entry back to cache
972 | * from where next readdir() will return it.
973 | */
974 | dirp->cached = 1;
975 | dirp->invalid = 0;
976 | return;
977 |
978 | exit_failure:
979 | /* Ensure that readdir will return NULL */
980 | dirp->invalid = 1;
981 | }
982 |
983 | /* Seek directory stream to offset */
984 | static void
985 | seekdir(DIR *dirp, long loc)
986 | {
987 | if (!dirp)
988 | return;
989 |
990 | _wseekdir(dirp->wdirp, loc);
991 | }
992 |
993 | /* Scan directory for entries */
994 | static int
995 | scandir(
996 | const char *dirname, struct dirent ***namelist,
997 | int (*filter)(const struct dirent*),
998 | int (*compare)(const struct dirent**, const struct dirent**))
999 | {
1000 | int result;
1001 |
1002 | /* Open directory stream */
1003 | DIR *dir = opendir(dirname);
1004 | if (!dir) {
1005 | /* Cannot open directory */
1006 | return /*Error*/ -1;
1007 | }
1008 |
1009 | /* Read directory entries to memory */
1010 | struct dirent *tmp = NULL;
1011 | struct dirent **files = NULL;
1012 | size_t size = 0;
1013 | size_t allocated = 0;
1014 | while (1) {
1015 | /* Allocate room for a temporary directory entry */
1016 | if (!tmp) {
1017 | tmp = (struct dirent*) malloc(sizeof(struct dirent));
1018 | if (!tmp)
1019 | goto exit_failure;
1020 | }
1021 |
1022 | /* Read directory entry to temporary area */
1023 | struct dirent *entry;
1024 | if (readdir_r(dir, tmp, &entry) != /*OK*/0)
1025 | goto exit_failure;
1026 |
1027 | /* Stop if we already read the last directory entry */
1028 | if (entry == NULL)
1029 | goto exit_success;
1030 |
1031 | /* Determine whether to include the entry in results */
1032 | if (filter && !filter(tmp))
1033 | continue;
1034 |
1035 | /* Enlarge pointer table to make room for another pointer */
1036 | if (size >= allocated) {
1037 | /* Compute number of entries in the new table */
1038 | size_t num_entries = size * 2 + 16;
1039 |
1040 | /* Allocate new pointer table or enlarge existing */
1041 | void *p = realloc(files, sizeof(void*) * num_entries);
1042 | if (!p)
1043 | goto exit_failure;
1044 |
1045 | /* Got the memory */
1046 | files = (dirent**) p;
1047 | allocated = num_entries;
1048 | }
1049 |
1050 | /* Store the temporary entry to ptr table */
1051 | files[size++] = tmp;
1052 | tmp = NULL;
1053 | }
1054 |
1055 | exit_failure:
1056 | /* Release allocated entries */
1057 | for (size_t i = 0; i < size; i++) {
1058 | free(files[i]);
1059 | }
1060 |
1061 | /* Release the pointer table */
1062 | free(files);
1063 | files = NULL;
1064 |
1065 | /* Exit with error code */
1066 | result = /*error*/ -1;
1067 | goto exit_status;
1068 |
1069 | exit_success:
1070 | /* Sort directory entries */
1071 | if (size > 1 && compare) {
1072 | qsort(files, size, sizeof(void*),
1073 | (int (*) (const void*, const void*)) compare);
1074 | }
1075 |
1076 | /* Pass pointer table to caller */
1077 | if (namelist)
1078 | *namelist = files;
1079 |
1080 | /* Return the number of directory entries read */
1081 | result = (int) size;
1082 |
1083 | exit_status:
1084 | /* Release temporary directory entry, if we had one */
1085 | free(tmp);
1086 |
1087 | /* Close directory stream */
1088 | closedir(dir);
1089 | return result;
1090 | }
1091 |
1092 | /* Alphabetical sorting */
1093 | static int
1094 | alphasort(const struct dirent **a, const struct dirent **b)
1095 | {
1096 | return strcoll((*a)->d_name, (*b)->d_name);
1097 | }
1098 |
1099 | /* Sort versions */
1100 | static int
1101 | versionsort(const struct dirent **a, const struct dirent **b)
1102 | {
1103 | return strverscmp((*a)->d_name, (*b)->d_name);
1104 | }
1105 |
1106 | /* Compare strings */
1107 | static int
1108 | strverscmp(const char *a, const char *b)
1109 | {
1110 | size_t i = 0;
1111 | size_t j;
1112 |
1113 | /* Find first difference */
1114 | while (a[i] == b[i]) {
1115 | if (a[i] == '\0') {
1116 | /* No difference */
1117 | return 0;
1118 | }
1119 | ++i;
1120 | }
1121 |
1122 | /* Count backwards and find the leftmost digit */
1123 | j = i;
1124 | while (j > 0 && isdigit(a[j-1])) {
1125 | --j;
1126 | }
1127 |
1128 | /* Determine mode of comparison */
1129 | if (a[j] == '0' || b[j] == '0') {
1130 | /* Find the next non-zero digit */
1131 | while (a[j] == '0' && a[j] == b[j]) {
1132 | j++;
1133 | }
1134 |
1135 | /* String with more digits is smaller, e.g 002 < 01 */
1136 | if (isdigit(a[j])) {
1137 | if (!isdigit(b[j])) {
1138 | return -1;
1139 | }
1140 | } else if (isdigit(b[j])) {
1141 | return 1;
1142 | }
1143 | } else if (isdigit(a[j]) && isdigit(b[j])) {
1144 | /* Numeric comparison */
1145 | size_t k1 = j;
1146 | size_t k2 = j;
1147 |
1148 | /* Compute number of digits in each string */
1149 | while (isdigit(a[k1])) {
1150 | k1++;
1151 | }
1152 | while (isdigit(b[k2])) {
1153 | k2++;
1154 | }
1155 |
1156 | /* Number with more digits is bigger, e.g 999 < 1000 */
1157 | if (k1 < k2)
1158 | return -1;
1159 | else if (k1 > k2)
1160 | return 1;
1161 | }
1162 |
1163 | /* Alphabetical comparison */
1164 | return (int) ((unsigned char) a[i]) - ((unsigned char) b[i]);
1165 | }
1166 |
1167 | /* Convert multi-byte string to wide character string */
1168 | #if !defined(_MSC_VER) || _MSC_VER < 1400
1169 | static int
1170 | dirent_mbstowcs_s(
1171 | size_t *pReturnValue, wchar_t *wcstr,
1172 | size_t sizeInWords, const char *mbstr, size_t count)
1173 | {
1174 | /* Older Visual Studio or non-Microsoft compiler */
1175 | size_t n = mbstowcs(wcstr, mbstr, sizeInWords);
1176 | if (wcstr && n >= count)
1177 | return /*error*/ 1;
1178 |
1179 | /* Zero-terminate output buffer */
1180 | if (wcstr && sizeInWords) {
1181 | if (n >= sizeInWords)
1182 | n = sizeInWords - 1;
1183 | wcstr[n] = 0;
1184 | }
1185 |
1186 | /* Length of multi-byte string with zero terminator */
1187 | if (pReturnValue) {
1188 | *pReturnValue = n + 1;
1189 | }
1190 |
1191 | /* Success */
1192 | return 0;
1193 | }
1194 | #endif
1195 |
1196 | /* Convert wide-character string to multi-byte string */
1197 | #if !defined(_MSC_VER) || _MSC_VER < 1400
1198 | static int
1199 | dirent_wcstombs_s(
1200 | size_t *pReturnValue, char *mbstr,
1201 | size_t sizeInBytes, const wchar_t *wcstr, size_t count)
1202 | {
1203 | /* Older Visual Studio or non-Microsoft compiler */
1204 | size_t n = wcstombs(mbstr, wcstr, sizeInBytes);
1205 | if (mbstr && n >= count)
1206 | return /*error*/1;
1207 |
1208 | /* Zero-terminate output buffer */
1209 | if (mbstr && sizeInBytes) {
1210 | if (n >= sizeInBytes) {
1211 | n = sizeInBytes - 1;
1212 | }
1213 | mbstr[n] = '\0';
1214 | }
1215 |
1216 | /* Length of resulting multi-bytes string WITH zero-terminator */
1217 | if (pReturnValue) {
1218 | *pReturnValue = n + 1;
1219 | }
1220 |
1221 | /* Success */
1222 | return 0;
1223 | }
1224 | #endif
1225 |
1226 | /* Set errno variable */
1227 | #if !defined(_MSC_VER) || _MSC_VER < 1400
1228 | static void
1229 | dirent_set_errno(int error)
1230 | {
1231 | /* Non-Microsoft compiler or older Microsoft compiler */
1232 | errno = error;
1233 | }
1234 | #endif
1235 |
1236 | #ifdef __cplusplus
1237 | }
1238 | #endif
1239 | #endif /*DIRENT_H*/
1240 |
--------------------------------------------------------------------------------
/ssThinning.cxx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vianamp/MitoGraph/70819e5f517e968fd11870b3d99764f827a7a289/ssThinning.cxx
--------------------------------------------------------------------------------
/ssThinning.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vianamp/MitoGraph/70819e5f517e968fd11870b3d99764f827a7a289/ssThinning.h
--------------------------------------------------------------------------------
/tools/seg2para/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | PROJECT(seg2para)
4 |
5 | include_directories('.')
6 |
7 | find_package(VTK REQUIRED)
8 | include(${VTK_USE_FILE})
9 |
10 | add_executable(seg2para MACOSX_BUNDLE seg2para)
11 |
12 | if(VTK_LIBRARIES)
13 | target_link_libraries(seg2para ${VTK_LIBRARIES})
14 | else()
15 | target_link_libraries(seg2para vtkHybrid vtkWidgets)
16 | endif()
17 |
--------------------------------------------------------------------------------
/tools/seg2para/seg2para.cpp:
--------------------------------------------------------------------------------
1 | // ==================================================================
2 | // Liya Ding. 2016.04.
3 | // This code is developed based on the frame work of MitoGraph.
4 | // It reuses a majority part of the code of MitoGraph.
5 | // MitoGraph is written by Matheus P. Viana,
6 | // from Susanne Rafelski Lab, University of California Irvine
7 | // ==================================================================
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 | #include
46 | #include
47 | #include
48 | #include
49 | #include
50 | #include
51 | #include
52 | #include
53 | #include
54 | #include
55 | #include
56 |
57 | bool _DebugFlag = true;
58 | double _rad = 0.150;
59 | double _dxy, _dz = -1.0;
60 | bool _export_graph_files = true;
61 | bool _export_image_resampled = true;
62 | bool _adaptive_threshold = false;
63 | bool _scale_polydata_before_save = true;
64 | bool _improve_skeleton_quality = false;
65 | bool _export_nodes_label = true;
66 | double _div_threshold = 0.1666667;
67 | bool _checkonly = false;
68 | bool _width = false;
69 | bool _resampleonly = false;
70 | bool _image_2_surface_flag = false;
71 | bool _filename_specific = false;
72 |
73 |
74 | // |------06------|
75 | // |------------------------18------------------------|
76 | // |---------------------------------------26----------------------------------|
77 | int ssdx_sort[26] = { 0,-1, 0, 1, 0, 0,-1, 0, 1, 0,-1, 1, 1,-1,-1, 0, 1, 0, -1, 1, 1,-1,-1, 1, 1,-1};
78 | int ssdy_sort[26] = { 0, 0,-1, 0, 1, 0, 0,-1, 0, 1,-1,-1, 1, 1, 0,-1, 0, 1, -1,-1, 1, 1,-1,-1, 1, 1};
79 | int ssdz_sort[26] = {-1, 0, 0, 0, 0, 1,-1,-1,-1,-1, 0, 0, 0, 0, 1, 1, 1, 1, -1,-1,-1,-1, 1, 1, 1, 1};
80 |
81 | // In order to acess the voxel (x,y,z) from ImageJ, I should use
82 | // GetId(x,(Dim[1]-1)-y,z,Dim);
83 | // Or change the volume orientation...
84 |
85 | /**========================================================
86 | Auxiliar functions
87 | =========================================================*/
88 |
89 |
90 | // This routine returns the x of the id-th point of a 3D volume
91 | // of size Dim[0]xDim[1]xDim[2]
92 | int GetX(vtkIdType id, int *Dim);
93 |
94 | // This routine returns the y of the id-th point of a 3D volume
95 | // of size Dim[0]xDim[1]xDim[2]
96 | int GetY(vtkIdType id, int *Dim);
97 |
98 | // This routine returns the z of the id-th point of a 3D volume
99 | // of size Dim[0]xDim[1]xDim[2]
100 | int GetZ(vtkIdType id, int *Dim);
101 |
102 | // This routine returns the id of a point located at coordinate
103 | // (x,y,z) of a 3D volume of size Dim[0]xDim[1]xDim[2]
104 | vtkIdType GetId(int x, int y, int z, int *Dim);
105 |
106 | // Swap values
107 | void Swap(double *x, double *y);
108 |
109 | // Simple sorting algorithm and the output is such that
110 | // l3 >= l2 >= l3
111 | void Sort(double *l1, double *l2, double *l3);
112 |
113 | // Calculate the Frobenius norm of a given 3x3 matrix
114 | // http://mathworld.wolfram.com/FrobeniusNorm.html
115 | double FrobeniusNorm(double M[3][3]);
116 |
117 | // This routine scales the polydata points to the correct dimension
118 | // given by parameters _dxy and _dz.
119 | void ScalePolyData(vtkSmartPointer PolyData);
120 | void PolyData2XYPixelScale(vtkSmartPointer PolyData);
121 |
122 | /* ================================================================
123 | IMAGE TRANSFORM
124 | =================================================================*/
125 |
126 | // This routine converts 16-bit volumes into 8-bit volumes by
127 | // linearly scaling the original range of intensities [min,max]
128 | // in [0,255] (http://rsbweb.nih.gov/ij/docs/guide/146-28.html)
129 | vtkSmartPointer Convert16To8bit(vtkSmartPointer Image);
130 |
131 | // Apply a threshold to a ImageData and converts the result in
132 | // a 8-bit ImageData.
133 | vtkSmartPointer BinarizeAndConvertToDouble(vtkSmartPointer Image, double threshold);
134 |
135 | // Fill holes in the 3D image
136 | void FillHoles(vtkSmartPointer ImageData);
137 |
138 | /* ================================================================
139 | I/O ROUTINES
140 | =================================================================*/
141 |
142 | // Different utilities of this tool, major function
143 | int utilities(const char FileName[]);
144 |
145 | void SaveImageData(vtkSmartPointer Image, const char FileName[], bool _resample = false);
146 | void SavePolyData(vtkSmartPointer PolyData, const char FileName[], bool scale = _scale_polydata_before_save);
147 |
148 | /* ================================================================*/
149 |
150 | void SaveImageData(vtkSmartPointer Image, const char FileName[], bool _resample) {
151 |
152 | if(_DebugFlag){
153 | printf("Saving ImageData File...\n");
154 | }
155 |
156 | vtkSmartPointer